diff --git a/.gitignore b/.gitignore index 4817f935a680..f3036e090577 100644 --- a/.gitignore +++ b/.gitignore @@ -86,11 +86,11 @@ src/leveldb/build_config.mk Makefile phore-qt phore-Qt.app +background.tiff* # Unit-tests Makefile.test phore-qt_test -src/test/buildenv.py # Resources cpp qrc_*.cpp @@ -113,6 +113,8 @@ coverage_percent.txt linux-coverage-build linux-build win32-build +test/config.ini +test/cache/* qa/pull-tester/run-bitcoind-for-test.sh qa/pull-tester/tests-config.sh qa/pull-tester/cache/* @@ -128,7 +130,7 @@ background.tiff@2x.png /doc/doxygen/ doc/Doxyfile /nbproject/ - +libbitcoinconsensus.pc .idea cmake-build-debug diff --git a/.python-version b/.python-version new file mode 100644 index 000000000000..c49282585a03 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.5.6 diff --git a/.travis.yml b/.travis.yml index a07edaf4abbc..f997848bbe48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,73 +1,209 @@ -sudo: required -dist: trusty +# The test build matrix (stage: test) is constructed to test a wide range of +# configurations, rather than a single pass/fail. This helps to catch build +# failures and logic errors that present on platforms other than the ones the +# author has tested. +# +# Some builders use the dependency-generator in `./depends`, rather than using +# apt-get to install build dependencies. This guarantees that the tester is +# using the same versions as Gitian, so the build results are nearly identical +# to what would be found in a final release. +# +# In order to avoid rebuilding all dependencies for each build, the binaries +# are cached and re-used when possible. Changes in the dependency-generator +# will trigger cache-invalidation and rebuilds as necessary. +# +# These caches can be manually removed if necessary. This is one of the very +# few manual operations that is possible with Travis, and it can be done by a +# PIVX GitHub member via the Travis web interface [0]. +# +# Travis CI uploads the cache after the script phase of the build [1]. +# However, the build is terminated without saving the chache if it takes over +# 50 minutes [2]. Thus, if we spent too much time in early build stages, fail +# with an error and save the cache. +# +# [0] https://travis-ci.org/pivx-project/pivx/caches +# [1] https://docs.travis-ci.com/user/caching/#build-phases +# [2] https://docs.travis-ci.com/user/customizing-the-build#build-timeouts + +dist: xenial os: linux language: minimal cache: + ccache: true directories: - - depends/built - - depends/sdk-sources - - $HOME/.ccache + - $TRAVIS_BUILD_DIR/depends/built + - $TRAVIS_BUILD_DIR/depends/sdk-sources + - $HOME/.ccache +stages: + - lint + - test env: global: - MAKEJOBS=-j3 - - RUN_TESTS=true - - CHECK_DOC=1 - - CHECK_LOGPRINT=1 + - RUN_UNIT_TESTS=true + - RUN_FUNCTIONAL_TESTS=false # Not Yet Implemented + - RUN_BENCH=false # Set to true for any one job that has debug enabled, to quickly check bench is not crashing or hitting assertions + - DOCKER_NAME_TAG=ubuntu:18.04 - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - CCACHE_SIZE=100M - CCACHE_TEMPDIR=/tmp/.ccache-temp - CCACHE_COMPRESS=1 + - CCACHE_DIR=$HOME/.ccache - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out - SDK_URL=https://bitcoincore.org/depends-sources/sdks - WINEDEBUG=fixme-all - matrix: -# ARM - - HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" CHECK_DOC=1 CHECK_LOGPRINT=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" -# Win32 - - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" -# 32-bit + dash - - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" PYZMQ=true -# Win64 - - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" -# phored - - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" PYZMQ=true -# No wallet -# - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" -# Cross-Mac - - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" - + - DOCKER_PACKAGES="build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache" + - CACHE_ERR_MSG="Error! Initial build successful, but not enough time remains to run later build stages and tests. Please manually re-run this job by using the travis restart button or asking a bitcoin maintainer to restart. The next run should not time out because the build cache has been saved." before_install: - - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") + - set -o errexit; source .travis/test_03_before_install.sh install: - - if [ "$PYZMQ" = "true" ]; then pip install pyzmq --user ; fi - - if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi - - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi - - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi + - set -o errexit; source .travis/test_04_install.sh before_script: - - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi - - if [ "$CHECK_LOGPRINT" = 1 ]; then contrib/devtools/logprint-scanner.py; fi - - unset CC; unset CXX - - mkdir -p depends/SDKs depends/sdk-sources - - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS + - set -o errexit; source .travis/test_05_before_script.sh script: - - export TRAVIS_COMMIT_LOG=`git log --format=fuller -1` - - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi - - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST - - BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" - - depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE - - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh - - ./configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - - make distdir PACKAGE=phore VERSION=$HOST - - cd phore-$HOST - - ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) - - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - - if [ "$RUN_TESTS" = "true" ]; then travis_wait 30 make $MAKEJOBS check VERBOSE=1; fi + - export CONTINUE=1 + - if [ $SECONDS -gt 1200 ]; then export CONTINUE=0; fi # Likely the depends build took very long + - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_a.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi + - if [ $SECONDS -gt 1500 ]; then export CONTINUE=0; fi # Likely the build took very long; The tests take about 1000s, so we should abort if we have less than 50*60-1000=2000s left + - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_b.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi after_script: - - echo $TRAVIS_COMMIT_RANGE - - echo $TRAVIS_COMMIT_LOG -notifications: - slack: - secure: w22XjHoG/3xplxWzddS9Ma7i99Q/hq4FA3Q56xS+RtO2vlFgDT+eDzCppstdx96mn2/4e+/V1aiQ4E6GVEvJMeldqSUhPv9OBnKR0KJVAOwu4haNXt+0ZeQFt8lIndKB5cMVyOJkoq6peGoHNXslClM0lGuBn7g7VC2QPQYNWrJNrrGL7IiVb6fNOIKHWcC4URkzSvXAhO/WIqSSlmKxAAx0B2oEsM8LhdAbcjbp7Sm7zH87TIVGBZ7iTVuMc6B9+SfClbE8bBuRtvjTX57Q4UUZzn0zDtKdPdCte0oXdaQF4RdVim9mDodBGIpDo+avW4WL7EE+AK33fs94pwH5bu0LEandR/aeEvVpbSpQ2XsEKSe+6woizgl5i4GXFVZduJF62y/o1f+S/zC3qW9lIEEpiZc4PpX7pDy30X3p6S5nMrW7T/zNh+SjLhS1VP6XKdQtpD3WRCY4GKZYammZhk5RbOy3jTXAahIXuttWdhl/Q3Rb5VqfFJWlrG/qQXt73qOk2/DgJnABxXE6gnWO4MpHAq+kdomNR+nod4HeXI3DOk1wRuQRVoW1rSjiqQd6Db+TP56RKYgt4M4csOD0DG9G+W0AOtZkuKHTeoEtmQfkKFPZLYAQumv41cDN2UE9gKIECmvJSevj4sMCDTWtozKWqay/W4n2+cmhbzmGflY= + - echo $TRAVIS_COMMIT_RANGE + - echo $TRAVIS_COMMIT_LOG +jobs: + include: + + - stage: lint + name: 'lint' + env: + cache: false + language: python + python: '3.5' # Oldest supported version according to doc/dependencies.md + install: + - set -o errexit; source .travis/lint_04_install.sh + before_script: + - set -o errexit; source .travis/lint_05_before_script.sh + script: + - set -o errexit; source .travis/lint_06_script.sh + + - stage: test + name: 'ARM 32-bit [GOAL: install] [no unit or functional tests]' + env: >- + HOST=arm-linux-gnueabihf + PACKAGES="python3 g++-arm-linux-gnueabihf" + RUN_UNIT_TESTS=false + RUN_FUNCTIONAL_TESTS=false + GOAL="install" + # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" + # This could be removed once the ABI change warning does not show up by default + BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" + + - stage: test + name: 'ARM 64-bit [GOAL:install] [no unit or functional tests]' + env: >- + HOST=aarch64-linux-gnu + PACKAGES="python3 g++-aarch64-linux-gnu" + RUN_UNIT_TESTS=false + RUN_FUNCTIONAL_TESTS=false + GOAL="install" + BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + + - stage: test + name: 'Win32 [GOAL: deploy] [no functional tests]' + env: >- + HOST=i686-w64-mingw32 + DPKG_ADD_ARCH="i386" + PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32" + RUN_FUNCTIONAL_TESTS=false + GOAL="deploy" + BITCOIN_CONFIG="--enable-reduce-exports" + + - stage: test + name: 'Win64 [GOAL: deploy] [no functional tests]' + env: >- + HOST=x86_64-w64-mingw32 + PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" + RUN_FUNCTIONAL_TESTS=false + GOAL="deploy" + BITCOIN_CONFIG="--enable-reduce-exports" + + - stage: test + name: '32-bit + dash [GOAL: install] [no gui]' + env: >- + HOST=i686-pc-linux-gnu + PACKAGES="g++-multilib python3-zmq" + GOAL="install" + BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" + CONFIG_SHELL="/bin/dash" + +# - stage: test +# name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package instead of depends Qt to speed up build and avoid timeout]' +# env: >- +# HOST=x86_64-unknown-linux-gnu +# PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" +# DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" +# RUN_FUNCTIONAL_TESTS=true +# #TEST_RUNNER_EXTRA="--coverage --extended" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash +# GOAL="install" +# BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports" + +# - stage: test +# name: 'x86_64 Linux [GOAL: install] [trusty] [no functional tests, no depends, only system libs]' +# env: >- +# HOST=x86_64-unknown-linux-gnu +# DOCKER_NAME_TAG=ubuntu:14.04 +# PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" +# NO_DEPENDS=1 +# RUN_FUNCTIONAL_TESTS=false +# GOAL="install" +# BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no" + + - stage: test + name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs]' + env: >- + HOST=x86_64-unknown-linux-gnu + DOCKER_NAME_TAG=ubuntu:16.04 + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + NO_DEPENDS=1 + GOAL="install" + BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --disable-hardening --disable-asm" + + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs]' + env: >- + HOST=x86_64-unknown-linux-gnu + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + NO_DEPENDS=1 + GOAL="install" + BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER" + +# - stage: test +# name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: fuzzer,address]' +# env: >- +# HOST=x86_64-unknown-linux-gnu +# PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" +# NO_DEPENDS=1 +# RUN_UNIT_TESTS=false +# RUN_FUNCTIONAL_TESTS=false +# RUN_BENCH=true +# GOAL="install" +# BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=undefined CC=clang CXX=clang++" + +# - stage: test +# name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]' +# env: >- +# HOST=x86_64-unknown-linux-gnu +# PACKAGES="python3-zmq" +# DEP_OPTS="NO_WALLET=1" +# GOAL="install" +# BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + + - stage: test + name: 'macOS 10.10 [GOAL: deploy] [no functional tests]' + env: >- + HOST=x86_64-apple-darwin14 + PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools" + OSX_SDK=10.11 + RUN_UNIT_TESTS=false + RUN_FUNCTIONAL_TESTS=false + GOAL="deploy" + BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" diff --git a/.travis/README.md b/.travis/README.md new file mode 100644 index 000000000000..21d1b9cc03ae --- /dev/null +++ b/.travis/README.md @@ -0,0 +1,8 @@ +## travis build scripts + +The `.travis` directory contains scripts for each build step in each build stage. +Currently the travis build defines two stages `lint` and `test`. Each stage has +it's own [lifecycle](https://docs.travis-ci.com/user/customizing-the-build/#the-build-lifecycle). +Every script in here is named and numbered according to which stage and lifecycle +step it belongs to. + diff --git a/.travis/lint_04_install.sh b/.travis/lint_04_install.sh new file mode 100755 index 000000000000..9a22773e5765 --- /dev/null +++ b/.travis/lint_04_install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C + +travis_retry pip install codespell==1.13.0 +travis_retry pip install flake8==3.5.0 +travis_retry pip install vulture==0.29 + +SHELLCHECK_VERSION=v0.6.0 +curl -s "https://storage.googleapis.com/shellcheck/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/ +export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}" diff --git a/.travis/lint_05_before_script.sh b/.travis/lint_05_before_script.sh new file mode 100755 index 000000000000..28bcbb47f748 --- /dev/null +++ b/.travis/lint_05_before_script.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C + +git fetch --unshallow diff --git a/.travis/lint_06_script.sh b/.travis/lint_06_script.sh new file mode 100755 index 000000000000..a4c3a82401a7 --- /dev/null +++ b/.travis/lint_06_script.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C + +#Till we properly set it as a sub tree +#contrib/devtools/git-subtree-check.sh src/secp256k1 +#contrib/devtools/git-subtree-check.sh src/univalue +#contrib/devtools/git-subtree-check.sh src/leveldb +contrib/devtools/check-doc.py +contrib/devtools/logprint-scanner.py + +if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then + contrib/devtools/lint-whitespace.sh +fi diff --git a/.travis/test_03_before_install.sh b/.travis/test_03_before_install.sh new file mode 100755 index 000000000000..3c9fcf3f983a --- /dev/null +++ b/.travis/test_03_before_install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") +# Add llvm-symbolizer directory to PATH. Needed to get symbolized stack traces from the sanitizers. +PATH=$PATH:/usr/lib/llvm-6.0/bin/ +export PATH + +BEGIN_FOLD () { + echo "" + CURRENT_FOLD_NAME=$1 + echo "travis_fold:start:${CURRENT_FOLD_NAME}" +} + +END_FOLD () { + RET=$? + echo "travis_fold:end:${CURRENT_FOLD_NAME}" + if [ $RET != 0 ]; then + echo "${CURRENT_FOLD_NAME} failed with status code ${RET}" + fi +} + diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh new file mode 100755 index 000000000000..ce6248a4f4d4 --- /dev/null +++ b/.travis/test_04_install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +travis_retry docker pull "$DOCKER_NAME_TAG" +env | grep -E '^(BITCOIN_CONFIG|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL)' | tee /tmp/env +if [[ $HOST = *-mingw32 ]]; then + DOCKER_ADMIN="--cap-add SYS_ADMIN" +elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764) + DOCKER_ADMIN="--cap-add SYS_PTRACE" +fi +DOCKER_ID=$(docker run $DOCKER_ADMIN -idt --mount type=bind,src=$TRAVIS_BUILD_DIR,dst=$TRAVIS_BUILD_DIR --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR -w $TRAVIS_BUILD_DIR --env-file /tmp/env $DOCKER_NAME_TAG) + +DOCKER_EXEC () { + docker exec $DOCKER_ID bash -c "cd $PWD && $*" +} + +if [ -n "$DPKG_ADD_ARCH" ]; then + DOCKER_EXEC dpkg --add-architecture "$DPKG_ADD_ARCH" +fi + +travis_retry DOCKER_EXEC apt-get update +travis_retry DOCKER_EXEC apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES $DOCKER_PACKAGES + diff --git a/.travis/test_05_before_script.sh b/.travis/test_05_before_script.sh new file mode 100755 index 000000000000..24d718a260b5 --- /dev/null +++ b/.travis/test_05_before_script.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +#DOCKER_EXEC echo \> \$HOME/.phore # Make sure default datadir does not exist and is never read by creating a dummy file + +mkdir -p depends/SDKs depends/sdk-sources + +if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then + curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz +fi +if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then + tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz +fi +if [[ $HOST = *-mingw32 ]]; then + DOCKER_EXEC update-alternatives --set $HOST-g++ \$\(which $HOST-g++-posix\) +fi +if [ -z "$NO_DEPENDS" ]; then + DOCKER_EXEC CONFIG_SHELL= make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS +fi + diff --git a/.travis/test_06_script_a.sh b/.travis/test_06_script_a.sh new file mode 100755 index 000000000000..df89fbe19c68 --- /dev/null +++ b/.travis/test_06_script_a.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +TRAVIS_COMMIT_LOG=$(git log --format=fuller -1) +export TRAVIS_COMMIT_LOG + +OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST +BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" +if [ -z "$NO_DEPENDS" ]; then + DOCKER_EXEC ccache --max-size=$CCACHE_SIZE +fi + +BEGIN_FOLD autogen +if [ -n "$CONFIG_SHELL" ]; then + DOCKER_EXEC "$CONFIG_SHELL" -c "./autogen.sh" +else + DOCKER_EXEC ./autogen.sh +fi +END_FOLD + +mkdir build +cd build || (echo "could not enter build directory"; exit 1) + +BEGIN_FOLD configure +DOCKER_EXEC ../configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) +END_FOLD + +BEGIN_FOLD distdir +DOCKER_EXEC make distdir VERSION=$HOST +END_FOLD + +cd "phore-$HOST" || (echo "could not enter distdir phore-$HOST"; exit 1) + +BEGIN_FOLD configure +DOCKER_EXEC ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) +END_FOLD + +set -o errtrace +trap 'DOCKER_EXEC "cat ${TRAVIS_BUILD_DIR}/sanitizer-output/* 2> /dev/null"' ERR + +BEGIN_FOLD build +DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false ) +END_FOLD + +cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1) \ No newline at end of file diff --git a/.travis/test_06_script_b.sh b/.travis/test_06_script_b.sh new file mode 100755 index 000000000000..11b8051488d5 --- /dev/null +++ b/.travis/test_06_script_b.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +cd "build/phore-$HOST" || (echo "could not enter distdir build/phore-$HOST"; exit 1) + +if [ "$RUN_UNIT_TESTS" = "true" ]; then + BEGIN_FOLD unit-tests + DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1 + END_FOLD +fi + +if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then + BEGIN_FOLD functional-tests + DOCKER_EXEC test/functional/test_runner.py --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} + END_FOLD +fi + +cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000000..43797e3b5c72 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,544 @@ +cmake_minimum_required(VERSION 3.10) +project(PIVX) + +set(BDB_VER "4.8.30") +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/contrib/cmake") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ") +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + message(STATUS "Compiling on macOS") + list(APPEND CMAKE_PREFIX_PATH /usr/local/opt/qt5) + list(APPEND CMAKE_PREFIX_PATH /usr/local/opt/openssl) + list(APPEND CMAKE_PREFIX_PATH /usr/local/Cellar/berkeley-db@4) + set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl/") + set(ENV{CPPFLAGS} "-I${OPENSSL_ROOT_DIR}/include") + set(ENV{LDFLAGS} "-L${OPENSSL_ROOT_DIR}/lib") + set(BerkeleyDB_ROOT_DIR "/usr/local/Cellar/berkeley-db@4/${BDB_VER}/") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + file(READ "/proc/version" _SYS_VERSION) + std::string(REGEX MATCH "Microsoft" _SYSTEM_VERSION_PARSED "${_SYS_VERSION}") + if(${_SYSTEM_VERSION_PARSED} MATCHES "Microsoft") + message(STATUS "Compiling on WSL") + set(ENV{triple} x86_64-w64-mingw32) + set(ENV{target} Windows) + execute_process( + COMMAND make HOST=x86_64-w64-mingw32 -j16 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/depends + ) + file(REMOVE ${CMAKE_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CMakeCXXCompiler.cmake) + file(REMOVE ${CMAKE_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CMakeCCompiler.cmake) + set(CMAKE_C_COMPILER /usr/bin/$ENV{triple}-gcc) + set(CMAKE_CXX_COMPILER /usr/bin/$ENV{triple}-g++) + set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}) + set(BOOST_INCLUDEDIR ${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/include/) + set(BOOST_LIBRARYDIR ${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib) + set(Boost_USE_STATIC_RUNTIME ON) + set(Boost_THREADAPI "win32") + else() + message(STATUS "Compiling on Linux") + list(APPEND CMAKE_PREFIX_PATH /usr/lib/x86_64-linux-gnu/cmake/Qt5) + set(Qt5core_DIR "/usr/lib/x86_64-linux-gnu/cmake/Qt5/QtCore") + include_directories("/usr/include") + include_directories("/usr/include/x86_64-linux-gnu") + add_definitions("-D__BYTE_ORDER -D__LITTLE_ENDIAN") + endif() +endif() + +# Find Dependencies +find_package(BerkeleyDB ${BDB_VER} REQUIRED) +if (BerkeleyDB_FOUND) + if(NOT ${BerkeleyDB_VERSION} MATCHES "${BDB_VER}") + message(WARNING "BerkeleyDB version other than ${BDB_VER} found!") + set(BDB_CONFIGURE_FLAGS "--with-incompatible-bdb") + endif() + include_directories( ${BerkeleyDB_INCLUDE_DIRS} ) + link_directories( ${BerkeleyDB_ROOT_DIR}/lib ) +endif () + +find_package(OpenSSL REQUIRED) +if (OPENSSL_FOUND) + message(STATUS "Found OpenSSL (${OPENSSL_VERSION}): ${OPENSSL_LIBRARIES}") + include_directories( ${OPENSSL_INCLUDE_DIR} ) +endif() + +find_package(LibEvent REQUIRED) +if (LibEvent_FOUND) + include_directories ( ${LibEvent_INCLUDE_DIR} ) + link_directories ( ${LibEvent_LIBRARY_DIRS} ) +endif() + +find_package(GMP) +if (GMP_FOUND) + include_directories ( ${GMP_INCLUDE_DIR} ) + link_directories ( ${GMP_LIBRARY_DIRS} ) +else() + message(WARNING "GMP not found, falling back to OpenSSL for bignum!") + set(BIGNUM_CONFIGURE_FLAGS "--with-zerocoin-bignum=openssl") +endif() + +find_package(ZMQ) +if (ZMQ_Found) + include_directories ( ${ZMQ_INCLUDE_DIR} ) + link_directories ( ${ZMQ_LIB_DIRS} ) +endif() + +find_package(Boost COMPONENTS system filesystem thread program_options REQUIRED) +include_directories( ${Boost_INCLUDE_DIRS} ) +link_directories ( ${Boost_LIBRARY_DIRS} ) + +# run autogen.sh if missing header files from configure on Linux/Mac +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/configure") +else() + execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/autogen.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() + +# run configure if pivx_config.h doesn't exist +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/config/pivx-config.h") +else() + execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure ${BDB_CONFIGURE_FLAGS} ${BIGNUM_CONFIGURE_FLAGS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() +add_definitions(-DHAVE_CONFIG_H) + +ExternalProject_Add ( + libunivalue + SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/univalue + CONFIGURE_COMMAND "" + BUILD_COMMAND make + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "" + ) + +ExternalProject_Add ( + libsecp256k1 + SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/secp256k1 + CONFIGURE_COMMAND "" + BUILD_COMMAND make + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "" +) + +link_directories( + ${CMAKE_SOURCE_DIR}/src/univalue/.libs + ${CMAKE_SOURCE_DIR}/src/secp256k1/.libs +) + +include_directories( + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/src/compat + ${CMAKE_SOURCE_DIR}/src/config + ${CMAKE_SOURCE_DIR}/src/obj + ${CMAKE_SOURCE_DIR}/src/leveldb + ${CMAKE_SOURCE_DIR}/src/leveldb/include + ${CMAKE_SOURCE_DIR}/src/leveldb/helpers/memenv + ${CMAKE_SOURCE_DIR}/src/secp256k1 + ${CMAKE_SOURCE_DIR}/src/secp256k1/include + ${CMAKE_SOURCE_DIR}/src/univalue/include +) + +set(libleveldb_a_headers + ${CMAKE_CURRENT_SOURCE_DIR}/src/config/pivx-config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/atomic_pointer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_example.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_posix.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/win/stdint.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_win.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/thread_annotations.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/db.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/options.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/comparator.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/filter_policy.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/slice.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/table_builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/env.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/c.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/iterator.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/dumpfile.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/table.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/write_batch.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/status.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_format.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/memtable.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_set.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/write_batch_internal.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/filename.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_edit.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/dbformat.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_writer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_iter.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/skiplist.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_impl.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/table_cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/snapshot.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_reader.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/filter_block.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block_builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/two_level_iterator.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/merger.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/format.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/iterator_wrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/crc32c.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env_posix_test_helper.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/arena.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/random.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/posix_logger.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/histogram.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/coding.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/testutil.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/mutexlock.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/logging.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/testharness.h + ) + +set(libleveldb_a_sources + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/builder.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/c.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/dbformat.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_impl.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_iter.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/dumpfile.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/filename.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_reader.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_writer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/memtable.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/repair.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/table_cache.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_edit.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_set.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/write_batch.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block_builder.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/filter_block.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/format.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/iterator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/merger.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/table_builder.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/table.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/two_level_iterator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/arena.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/bloom.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/cache.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/coding.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/comparator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/crc32c.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env_posix.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/filter_policy.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/hash.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/histogram.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/logging.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/options.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/status.cc + ) + +set(libleveldb_cpp_flags) +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(libleveldb_cpp_flags -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1) + list(APPEND libleveldb_a_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env_win.cc) + list(APPEND libleveldb_a_srouces ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_win.cc) +else() + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(libleveldb_cpp_flags -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX) + else() + set(libleveldb_cpp_flags -DOS_LINUX -DLEVELDB_PLATFORM_POSIX) + endif() + list(APPEND libleveldb_a_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_posix.cc) +endif() + +add_library(leveldb STATIC ${libleveldb_a_headers} ${libleveldb_a_sources}) +target_compile_definitions(leveldb PUBLIC ${libleveldb_cpp_flags} -DLEVELDB_ATOMIC_PRESENT -D__STDC_LIMIT_MACROS) +target_compile_options(leveldb PUBLIC -I${CMAKE_CURRENT_SOURCE_DIR}/src/compat) + +set(libmemenv_a_sources + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/helpers/memenv/memenv.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/helpers/memenv/memenv.h + ) +add_library(memenv STATIC ${libmemenv_a_sources}) +target_compile_definitions(memenv PUBLIC ${libleveldb_cpp_flags}) + +set(libleveldb_sse42_a_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_posix_sse.cc) +add_library(leveldb_sse42 ${libleveldb_sse42_a_sources}) + +link_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb ) + +file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h) +file(GLOB CRYPTO_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/*.h) +file(GLOB PRIMITIVE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/primitives/*.h) +file(GLOB ZMQ_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/zmq/*.h) +file(GLOB SCRIPT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/script/*.h) +file(GLOB RPC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/rpc/*.h) +file(GLOB COMPAT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/compat/*.h) + +source_group("BitcoinHeaders" FILES + ${HEADERS} + ${CRYPTO_HEADERS} + ${PRIMITIVE_HEADERS} + ${ZMQ_HEADERS} + ${SCRIPT_HEADERS} + ${RPC_HEADERS} + ${COMPAT_HEADERS} + ./src/support/cleanse.h + ) + +set(SERVER_SOURCES + ./src/addrman.cpp + ./src/alert.cpp + ./src/bloom.cpp + ./src/blocksignature.cpp + ./src/chain.cpp + ./src/checkpoints.cpp + ./src/httprpc.cpp + ./src/httpserver.cpp + ./src/init.cpp + ./src/leveldbwrapper.cpp + ./src/main.cpp + ./src/merkleblock.cpp + ./src/miner.cpp + ./src/net.cpp + ./src/noui.cpp + ./src/pow.cpp + ./src/rest.cpp + ./src/rpc/blockchain.cpp + ./src/rpc/masternode.cpp + ./src/rpc/budget.cpp + ./src/rpc/mining.cpp + ./src/rpc/misc.cpp + ./src/rpc/net.cpp + ./src/rpc/rawtransaction.cpp + ./src/rpc/server.cpp + ./src/script/sigcache.cpp + ./src/sporkdb.cpp + ./src/timedata.cpp + ./src/torcontrol.cpp + ./src/txdb.cpp + ./src/txmempool.cpp + ./src/validationinterface.cpp + ./src/zpivchain.cpp + ) +add_library(SERVER_A STATIC ${BitcoinHeaders} ${SERVER_SOURCES}) + +if (ZMQ_FOUND) + set(ZMQ_SOURCES + ./src/zmq/zmqabstractnotifier.cpp + ./src/zmq/zmqnotificationinterface.cpp + ./src/zmq/zmqpublishnotifier.cpp + ) + add_library(ZMQ_A STATIC ${BitcoinHeaders} ${ZMQ_SOURCES}) +endif() + +set(WALLET_SOURCES + ./src/activemasternode.cpp + ./src/bip38.cpp + ./src/denomination_functions.cpp + ./src/obfuscation.cpp + ./src/obfuscation-relay.cpp + ./src/wallet/db.cpp + ./src/crypter.cpp + ./src/swifttx.cpp + ./src/masternode.cpp + ./src/masternode-budget.cpp + ./src/masternode-payments.cpp + ./src/masternode-sync.cpp + ./src/masternodeconfig.cpp + ./src/masternodeman.cpp + ./src/zpiv/mintpool.cpp + ./src/wallet/rpcdump.cpp + ./src/zpiv/deterministicmint.cpp + ./src/zpiv/zerocoin.cpp + ./src/wallet/rpcwallet.cpp + ./src/kernel.cpp + ./src/wallet/wallet.cpp + ./src/wallet/wallet_ismine.cpp + ./src/wallet/walletdb.cpp + ./src/zpiv/zpivwallet.cpp + ./src/zpiv/zpivtracker.cpp + ./src/zpiv/zpivmodule.cpp + ./src/stakeinput.cpp + ./src/genwit.cpp + ./src/lightzpivthread.cpp + ) +add_library(WALLET_A STATIC ${BitcoinHeaders} ${WALLET_SOURCES}) + +set(BITCOIN_CRYPTO_SOURCES + ./src/crypto/sha1.cpp + ./src/crypto/sha256.cpp + ./src/crypto/sha512.cpp + ./src/crypto/hmac_sha256.cpp + ./src/crypto/rfc6979_hmac_sha256.cpp + ./src/crypto/hmac_sha512.cpp + ./src/crypto/scrypt.cpp + ./src/crypto/ripemd160.cpp + ./src/crypto/aes_helper.c + ./src/crypto/blake.c + ./src/crypto/bmw.c + ./src/crypto/groestl.c + ./src/crypto/jh.c + ./src/crypto/keccak.c + ./src/crypto/skein.c + ./src/crypto/common.h + ./src/crypto/sha256.h + ./src/crypto/sha512.h + ./src/crypto/hmac_sha256.h + ./src/crypto/rfc6979_hmac_sha256.h + ./src/crypto/hmac_sha512.h + ./src/crypto/scrypt.h + ./src/crypto/sha1.h + ./src/crypto/ripemd160.h + ./src/crypto/sph_blake.h + ./src/crypto/sph_bmw.h + ./src/crypto/sph_groestl.h + ./src/crypto/sph_jh.h + ./src/crypto/sph_keccak.h + ./src/crypto/sph_skein.h + ./src/crypto/sph_types.h + ) +add_library(BITCOIN_CRYPTO_A STATIC ${BITCOIN_CRYPTO_SOURCES}) + +set(ZEROCOIN_SOURCES + ./src/libzerocoin/Accumulator.h + ./src/libzerocoin/AccumulatorProofOfKnowledge.h + ./src/libzerocoin/bignum.h + ./src/libzerocoin/bignum.cpp + ./src/libzerocoin/Coin.h + ./src/libzerocoin/CoinSpend.h + ./src/libzerocoin/Commitment.h + ./src/libzerocoin/Denominations.h + ./src/libzerocoin/ParamGeneration.h + ./src/libzerocoin/Params.h + ./src/libzerocoin/SerialNumberSignatureOfKnowledge.h + ./src/libzerocoin/SpendType.h + ./src/libzerocoin/ZerocoinDefines.h + ./src/libzerocoin/Accumulator.cpp + ./src/libzerocoin/AccumulatorProofOfKnowledge.cpp + ./src/libzerocoin/Coin.cpp + ./src/libzerocoin/Denominations.cpp + ./src/libzerocoin/CoinSpend.cpp + ./src/libzerocoin/Commitment.cpp + ./src/libzerocoin/ParamGeneration.cpp + ./src/libzerocoin/Params.cpp + ./src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp + ) +if(GMP_FOUND) + list(APPEND ZEROCOIN_SOURCES ./src/libzerocoin/bignum_gmp.cpp) +else() + list(APPEND ZEROCOIN_SOURCES ./src/libzerocoin/bignum_openssl.cpp) +endif() +add_library(ZEROCOIN_A STATIC ${ZEROCOIN_SOURCES}) + +set(COMMON_SOURCES + ./src/zpiv/accumulators.cpp + ./src/zpiv/accumulatorcheckpoints.cpp + ./src/zpiv/accumulatormap.cpp + ./src/zpiv/witness.cpp + ./src/allocators.cpp + ./src/amount.cpp + ./src/base58.cpp + ./src/bip38.cpp + ./src/chainparams.cpp + ./src/coins.cpp + ./src/compressor.cpp + ./src/primitives/block.cpp + ./src/zpiv/deterministicmint.cpp + ./src/primitives/transaction.cpp + ./src/zpiv/zerocoin.cpp + ./src/core_read.cpp + ./src/core_write.cpp + ./src/hash.cpp + ./src/invalid.cpp + ./src/key.cpp + ./src/keystore.cpp + ./src/netbase.cpp + ./src/protocol.cpp + ./src/pubkey.cpp + ./src/scheduler.cpp + ./src/script/interpreter.cpp + ./src/script/script.cpp + ./src/script/sign.cpp + ./src/script/standard.cpp + ./src/script/script_error.cpp + ./src/spork.cpp + ./src/sporkdb.cpp + ) +add_library(COMMON_A STATIC ${BitcoinHeaders} ${COMMON_SOURCES}) + +set(UTIL_SOURCES + ./src/allocators.cpp + ./src/compat/strnlen.cpp + ./src/compat/glibc_sanity.cpp + ./src/compat/glibcxx_sanity.cpp + ./src/chainparamsbase.cpp + ./src/clientversion.cpp + ./src/random.cpp + ./src/rpc/protocol.cpp + ./src/sync.cpp + ./src/uint256.cpp + ./src/util.cpp + ./src/utilstrencodings.cpp + ./src/utilmoneystr.cpp + ./src/utiltime.cpp + ./src/support/cleanse.cpp + ) +add_library(UTIL_A STATIC ${BitcoinHeaders} ${UTIL_SOURCES}) + +set(CLI_SOURCES ./src/rpc/client.cpp) +add_library(CLI_A STATIC ${BitcoinHeaders} ${CLI_SOURCES}) + +add_executable(pivx-cli ${CMAKE_CURRENT_SOURCE_DIR}/src/pivx-cli.cpp) +add_dependencies(pivx-cli libunivalue) +target_link_libraries(pivx-cli + CLI_A + univalue + UTIL_A + BITCOIN_CRYPTO_A + ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBEVENT_LIB} + ) + +add_executable(pivx-tx ${CMAKE_CURRENT_SOURCE_DIR}/src/pivx-tx.cpp) +add_dependencies(pivx-tx libunivalue libsecp256k1) +target_link_libraries(pivx-tx + univalue + COMMON_A + ZEROCOIN_A + UTIL_A + BITCOIN_CRYPTO_A + secp256k1 + ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBEVENT_LIB} + ) +if(GMP_FOUND) + target_link_libraries(pivx-tx ${GMP_LIBRARY}) +endif() + +add_executable(pivxd ${CMAKE_CURRENT_SOURCE_DIR}/src/pivxd.cpp) +add_dependencies(pivxd libunivalue libsecp256k1 leveldb leveldb_sse42 memenv) +target_link_libraries(pivxd + SERVER_A + COMMON_A + univalue + ZEROCOIN_A + UTIL_A + WALLET_A + BITCOIN_CRYPTO_A + leveldb leveldb_sse42 memenv secp256k1 + ${BerkeleyDB_LIBRARIES} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${LIBEVENT_LIB} miniupnpc pthread + ) +if(GMP_FOUND) + target_link_libraries(pivxd ${GMP_LIBRARY}) +endif() +if(ZMQ_FOUND) + target_link_libraries(pivxd ZMQ_A ${ZMQ_LIB}) +endif () + + +add_subdirectory(src/qt) diff --git a/Makefile.am b/Makefile.am index d21ca92f0dc1..c726bb7516ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,9 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 SUBDIRS = src +if ENABLE_MAN +SUBDIRS += doc/man +endif .PHONY: deploy FORCE export PYTHONPATH @@ -35,6 +38,18 @@ OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) +DIST_CONTRIB = $(top_srcdir)/contrib/phore-cli.bash-completion \ + $(top_srcdir)/contrib/phore-tx.bash-completion \ + $(top_srcdir)/contrib/phored.bash-completion \ + $(top_srcdir)/contrib/init \ + $(top_srcdir)/contrib/install_db4.sh + +DIST_SHARE = \ + $(top_srcdir)/share/genbuild.sh \ + $(top_srcdir)/share/rpcauth + +BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ + $(top_srcdir)/contrib/devtools/security-check.py WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ $(top_srcdir)/share/pixmaps/nsis-header.bmp \ @@ -47,24 +62,14 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh -COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ - leveldb_baseline.info test_phore_filtered.info total_coverage.info \ - baseline_filtered.info block_test_filtered.info \ - leveldb_baseline_filtered.info test_phore_coverage.info test_phore.info +COVERAGE_INFO = baseline.info \ + test_phore_filtered.info total_coverage.info \ + baseline_filtered.info functional_test.info functional_test_filtered.info \ + test_phore_coverage.info test_phore.info dist-hook: - -$(MAKE) -C $(top_distdir)/src/leveldb clean - -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - -distcheck-hook: - $(MKDIR_P) $(top_distdir)/_build/src/leveldb - cp -rf $(top_srcdir)/src/leveldb/* $(top_distdir)/_build/src/leveldb/ - -$(MAKE) -C $(top_distdir)/_build/src/leveldb clean - -distcleancheck: - @: - $(BITCOIN_WIN_INSTALLER): all-recursive $(MKDIR_P) $(top_builddir)/release STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release @@ -90,9 +95,9 @@ $(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) $(MKDIR_P) $(@D) $(INSTALL_DATA) $< $@ -$(OSX_APP)/Contents/MacOS/Phore-Qt: $(BITCOIN_QT_BIN) +$(OSX_APP)/Contents/MacOS/Phore-Qt: all-recursive $(MKDIR_P) $(@D) - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ + STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $@ $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(MKDIR_P) $(@D) @@ -164,53 +169,45 @@ $(BITCOIN_CLI_BIN): FORCE $(MAKE) -C src $(@F) if USE_LCOV +LCOV_FILTER_PATTERN=-p "/usr/include/" -p "src/leveldb/" -p "src/univalue" -p "src/secp256k1" baseline.info: $(LCOV) -c -i -d $(abs_builddir)/src -o $@ baseline_filtered.info: baseline.info - $(LCOV) -r $< "/usr/include/*" -o $@ - -leveldb_baseline.info: baseline_filtered.info - $(LCOV) -c -i -d $(abs_builddir)/src/leveldb -b $(abs_builddir)/src/leveldb -o $@ - -leveldb_baseline_filtered.info: leveldb_baseline.info - $(LCOV) -r $< "/usr/include/*" -o $@ - -baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info - $(LCOV) -a leveldb_baseline_filtered.info -a baseline_filtered.info -o $@ + $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ + $(LCOV) -a $@ $(LCOV_OPTS) -o $@ -test_phore.info: baseline_filtered_combined.info +test_phore.info: baseline_filtered.info $(MAKE) -C src/ check - $(LCOV) -c -d $(abs_builddir)/src -t test_phore -o $@ - $(LCOV) -z -d $(abs_builddir)/src - $(LCOV) -z -d $(abs_builddir)/src/leveldb + $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src -t test_phore -o $@ + $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src test_phore_filtered.info: test_phore.info - $(LCOV) -r $< "/usr/include/*" -o $@ + $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ + $(LCOV) -a $@ $(LCOV_OPTS) -o $@ -block_test.info: test_phore_filtered.info - $(MKDIR_P) qa/tmp - -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool 0 - $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ - $(LCOV) -z -d $(abs_builddir)/src - $(LCOV) -z -d $(abs_builddir)/src/leveldb +functional_test.info: test_phore_filtered.info + -@TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS) + $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t functional-tests -o $@ + $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src -block_test_filtered.info: block_test.info - $(LCOV) -r $< "/usr/include/*" -o $@ +functional_test_filtered.info: functional_test.info + $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@ + $(LCOV) -a $@ $(LCOV_OPTS) -o $@ -test_phore_coverage.info: baseline_filtered_combined.info test_phore_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_phore_filtered.info -o $@ +test_phore_coverage.info: baseline_filtered.info test_phore_filtered.info + $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_phore_filtered.info -o $@ -total_coverage.info: baseline_filtered_combined.info test_phore_filtered.info block_test_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_phore_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt +total_coverage.info: test_phore_filtered.info functional_test_filtered.info + $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_phore_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt test_phore.coverage/.dirstamp: test_phore_coverage.info - $(GENHTML) -s $< -o $(@D) + $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) @touch $@ total.coverage/.dirstamp: total_coverage.info - $(GENHTML) -s $< -o $(@D) + $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D) @touch $@ cov: test_phore.coverage/.dirstamp total.coverage/.dirstamp @@ -219,11 +216,51 @@ endif dist_noinst_SCRIPTS = autogen.sh -EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.sh qa/pull-tester/run-bitcoin-cli test $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) +EXTRA_DIST = $(DIST_SHARE) qa/pull-tester/rpc-tests.sh qa/pull-tester/run-bitcoin-cli test $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) + +EXTRA_DIST += \ + test/util/bitcoin-util-test.py \ + test/util/data/bitcoin-util-test.json \ + test/util/data/blanktxv1.hex \ + test/util/data/blanktxv1.json \ + test/util/data/tt-delin1-out.hex \ + test/util/data/tt-delin1-out.json \ + test/util/data/tt-delout1-out.hex \ + test/util/data/tt-delout1-out.json \ + test/util/data/tt-locktime317000-out.hex \ + test/util/data/tt-locktime317000-out.json \ + test/util/data/tx394b54bb.hex \ + test/util/data/txcreate1.hex \ + test/util/data/txcreate1.json \ + test/util/data/txcreate2.hex \ + test/util/data/txcreate2.json \ + test/util/data/txcreatescript1.hex \ + test/util/data/txcreatescript1.json \ + test/util/data/txcreatesign.hex \ + test/util/data/txcreatesign.json \ + test/util/rpcauth-test.py CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) .INTERMEDIATE: $(COVERAGE_INFO) -clean-local: - rm -rf test_phore.coverage/ total.coverage/ $(OSX_APP) +DISTCHECK_CONFIGURE_FLAGS = --enable-man + +doc/doxygen/.stamp: doc/Doxyfile FORCE + $(MKDIR_P) $(@D) + $(DOXYGEN) $^ + $(AM_V_at) touch $@ + +if HAVE_DOXYGEN +docs: doc/doxygen/.stamp +else +docs: + @echo "error: doxygen not found" +endif + +clean-docs: + rm -rf doc/doxygen + +clean-local: clean-docs + rm -rf coverage_percent.txt test_phore.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP) + diff --git a/autogen.sh b/autogen.sh index 27417daf7691..0c05626ccce5 100755 --- a/autogen.sh +++ b/autogen.sh @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +export LC_ALL=C set -e srcdir="$(dirname $0)" cd "$srcdir" diff --git a/build-aux/m4/ax_boost_chrono.m4 b/build-aux/m4/ax_boost_chrono.m4 index 318ecea17fab..6ea77b9b3eff 100644 --- a/build-aux/m4/ax_boost_chrono.m4 +++ b/build-aux/m4/ax_boost_chrono.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html +# https://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html # =========================================================================== # # SYNOPSIS @@ -8,7 +8,7 @@ # # DESCRIPTION # -# Test for System library from the Boost C++ libraries. The macro requires +# Test for Chrono library from the Boost C++ libraries. The macro requires # a preceding call to AX_BOOST_BASE. Further documentation is available at # . # @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 1 +#serial 4 AC_DEFUN([AX_BOOST_CHRONO], [ @@ -68,7 +68,7 @@ AC_DEFUN([AX_BOOST_CHRONO], CXXFLAGS_SAVE=$CXXFLAGS AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::chrono::system_clock::time_point time;]])], + [[boost::chrono::system_clock::time_point* time = new boost::chrono::system_clock::time_point; delete time;]])], ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) @@ -81,7 +81,6 @@ AC_DEFUN([AX_BOOST_CHRONO], LDFLAGS_SAVE=$LDFLAGS if test "x$ax_boost_user_chrono_lib" = "x"; then - ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, @@ -106,7 +105,7 @@ AC_DEFUN([AX_BOOST_CHRONO], fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the boost_chrono library!) + AC_MSG_ERROR(Could not find a version of the library!) fi if test "x$link_chrono" = "xno"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/build-aux/m4/ax_boost_unit_test_framework.m4 b/build-aux/m4/ax_boost_unit_test_framework.m4 index 4efd1e2f18be..3d8e93e964bd 100644 --- a/build-aux/m4/ax_boost_unit_test_framework.m4 +++ b/build-aux/m4/ax_boost_unit_test_framework.m4 @@ -1,6 +1,6 @@ -# ================================================================================ -# http://www.gnu.org/software/autoconf-archive/ax_boost_unit_test_framework.html -# ================================================================================ +# ================================================================================= +# https://www.gnu.org/software/autoconf-archive/ax_boost_unit_test_framework.html +# ================================================================================= # # SYNOPSIS # @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 19 +#serial 21 AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], [ @@ -66,7 +66,7 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], [AC_LANG_PUSH([C++]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[using boost::unit_test::test_suite; - test_suite* test= BOOST_TEST_SUITE( "Unit test example 1" ); return 0;]])], + test_suite* test= BOOST_TEST_SUITE( "Unit test example 1" ); if (test == NULL) { return 1; } else { return 0; }]])], ax_cv_boost_unit_test_framework=yes, ax_cv_boost_unit_test_framework=no) AC_LANG_POP([C++]) ]) @@ -76,7 +76,6 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], if test "x$ax_boost_user_unit_test_framework_lib" = "x"; then saved_ldflags="${LDFLAGS}" - ax_lib= for monitor_library in `ls $BOOSTLIBDIR/libboost_unit_test_framework*.so* $BOOSTLIBDIR/libboost_unit_test_framework*.dylib* $BOOSTLIBDIR/libboost_unit_test_framework*.a* 2>/dev/null` ; do if test -r $monitor_library ; then libextension=`echo $monitor_library | sed 's,.*/,,' | sed -e 's;^lib\(boost_unit_test_framework.*\)\.so.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.a.*$;\1;'` @@ -125,7 +124,7 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], done fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the boost_unit_test_framework library!) + AC_MSG_ERROR(Could not find a version of the library!) fi if test "x$link_unit_test_framework" != "xyes"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 index 3d45bae9d718..f147cee3b117 100644 --- a/build-aux/m4/ax_cxx_compile_stdcxx.m4 +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -63,6 +63,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [m4_fatal([invalid fourth argument `$4' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no + m4_if([$4], [nodefault], [], [dnl AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, ax_cv_cxx_compile_cxx$1, diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index a7cb0ac59c74..624953481098 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -53,8 +53,8 @@ dnl CAUTION: Do not use this inside of a conditional. AC_DEFUN([BITCOIN_QT_INIT],[ dnl enable qt support AC_ARG_WITH([gui], - [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@], - [build phore-qt GUI (default=auto, qt5 tried first)])], + [AS_HELP_STRING([--with-gui@<:@=no|qt5|auto@:>@], + [build phore-qt GUI (default=auto)])], [ bitcoin_qt_want_version=$withval if test "x$bitcoin_qt_want_version" = xyes; then @@ -94,18 +94,17 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi if test "x$use_pkgconfig" = xyes; then - BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG([$2])]) + BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG]) else BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG]) fi dnl This is ugly and complicated. Yuck. Works as follows: - dnl We can't discern whether Qt4 builds are static or not. For Qt5, we can - dnl check a header to find out. When Qt is built statically, some plugins must - dnl be linked into the final binary as well. These plugins have changed between - dnl Qt4 and Qt5. With Qt5, languages moved into core and the WindowsIntegration - dnl plugin was added. Since we can't tell if Qt4 is static or not, it is - dnl assumed for windows builds. + dnl For Qt5, we can check a header to find out whether Qt is build + dnl statically. When Qt is built statically, some plugins must be linked into + dnl the final binary as well. + dnl With Qt5, languages moved into core and the WindowsIntegration plugin was + dnl added. dnl _BITCOIN_QT_CHECK_STATIC_PLUGINS does a quick link-check and appends the dnl results to QT_LIBS. BITCOIN_QT_CHECK([ @@ -113,54 +112,40 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" CXXFLAGS="$PIC_FLAGS $CXXFLAGS" - if test "x$bitcoin_qt_got_major_vers" = x5; then - TEMP_CPPFLAGS="$TEMP_CPPFLAGS -DHAVE_QT5" - _BITCOIN_QT_IS_STATIC - if test "x$bitcoin_cv_static_qt" = xyes; then - _BITCOIN_QT_FIND_STATIC_PLUGINS - AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - AC_CACHE_CHECK(for Qt < 5.4, bitcoin_cv_need_acc_widget,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include - #ifndef QT_VERSION - # include - #endif - ]], - [[ - #if QT_VERSION >= 0x050400 - choke - #endif - ]])], - [bitcoin_cv_need_acc_widget=yes], - [bitcoin_cv_need_acc_widget=no]) - ]) - if test "x$bitcoin_cv_need_acc_widget" = xyes; then - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) - fi - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) - AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) - if test "x$TARGET_OS" = xwindows; then - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) - AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) - elif test "x$TARGET_OS" = xlinux; then - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) - AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) - elif test "x$TARGET_OS" = xdarwin; then - AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) - AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) - fi + _BITCOIN_QT_IS_STATIC + if test "x$bitcoin_cv_static_qt" = xyes; then + _BITCOIN_QT_FIND_STATIC_PLUGINS + AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) + AC_CACHE_CHECK(for Qt < 5.4, bitcoin_cv_need_acc_widget,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ + #if QT_VERSION >= 0x050400 + choke + #endif + ]])], + [bitcoin_cv_need_acc_widget=yes], + [bitcoin_cv_need_acc_widget=no]) + ]) + if test "x$bitcoin_cv_need_acc_widget" = xyes; then + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) fi - else + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) + AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) if test "x$TARGET_OS" = xwindows; then - AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - _BITCOIN_QT_CHECK_STATIC_PLUGINS([ - Q_IMPORT_PLUGIN(qcncodecs) - Q_IMPORT_PLUGIN(qjpcodecs) - Q_IMPORT_PLUGIN(qtwcodecs) - Q_IMPORT_PLUGIN(qkrcodecs) - Q_IMPORT_PLUGIN(AccessibleFactory)], - [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) + AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) + elif test "x$TARGET_OS" = xlinux; then + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) + AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) + elif test "x$TARGET_OS" = xdarwin; then + AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) + AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) fi fi CPPFLAGS=$TEMP_CPPFLAGS @@ -168,9 +153,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ ]) if test "x$use_pkgconfig$qt_bin_path" = xyes; then - if test "x$bitcoin_qt_got_major_vers" = x5; then - qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" - fi + qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" fi if test "x$use_hardening" != xno; then @@ -220,11 +203,11 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ ]) fi - BITCOIN_QT_PATH_PROGS([MOC], [moc-qt${bitcoin_qt_got_major_vers} moc${bitcoin_qt_got_major_vers} moc], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([UIC], [uic-qt${bitcoin_qt_got_major_vers} uic${bitcoin_qt_got_major_vers} uic], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt${bitcoin_qt_got_major_vers} rcc${bitcoin_qt_got_major_vers} rcc], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt${bitcoin_qt_got_major_vers} lrelease${bitcoin_qt_got_major_vers} lrelease], $qt_bin_path) - BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt${bitcoin_qt_got_major_vers} lupdate${bitcoin_qt_got_major_vers} lupdate],$qt_bin_path, yes) + BITCOIN_QT_PATH_PROGS([MOC], [moc-qt5 moc5 moc], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([UIC], [uic-qt5 uic5 uic], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt5 rcc5 rcc], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt5 lrelease5 lrelease], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt5 lupdate5 lupdate],$qt_bin_path, yes) MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)' case $host in @@ -263,7 +246,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ ],[ bitcoin_enable_qt=no ]) - AC_MSG_RESULT([$bitcoin_enable_qt (Qt${bitcoin_qt_got_major_vers})]) + AC_MSG_RESULT([$bitcoin_enable_qt (Qt5)]) AC_SUBST(QT_PIE_FLAGS) AC_SUBST(QT_INCLUDES) @@ -273,7 +256,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ AC_SUBST(QT_DBUS_LIBS) AC_SUBST(QT_TEST_INCLUDES) AC_SUBST(QT_TEST_LIBS) - AC_SUBST(QT_SELECT, qt${bitcoin_qt_got_major_vers}) + AC_SUBST(QT_SELECT, qt5) AC_SUBST(MOC_DEFS) ]) @@ -293,7 +276,7 @@ AC_DEFUN([_BITCOIN_QT_CHECK_QT5],[ #endif ]], [[ - #if QT_VERSION < 0x050000 + #if QT_VERSION < 0x050000 || QT_VERSION_MAJOR < 5 choke #endif ]])], @@ -301,13 +284,11 @@ AC_DEFUN([_BITCOIN_QT_CHECK_QT5],[ [bitcoin_cv_qt5=no]) ])]) -dnl Internal. Check if the linked version of Qt was built as static libs. -dnl Requires: Qt5. This check cannot determine if Qt4 is static. -dnl Requires: INCLUDES and LIBS must be populated as necessary. -dnl Output: bitcoin_cv_static_qt=yes|no -dnl Output: Defines QT_STATICPLUGIN if plugins are static. -AC_DEFUN([_BITCOIN_QT_IS_STATIC],[ - AC_CACHE_CHECK(for static Qt, bitcoin_cv_static_qt,[ +dnl Internal. Check if the included version of Qt is greater than Qt58. +dnl Requires: INCLUDES must be populated as necessary. +dnl Output: bitcoin_cv_qt5=yes|no +AC_DEFUN([_BITCOIN_QT_CHECK_QT58],[ + AC_CACHE_CHECK(for > Qt 5.7, bitcoin_cv_qt58,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #ifndef QT_VERSION @@ -315,13 +296,36 @@ AC_DEFUN([_BITCOIN_QT_IS_STATIC],[ #endif ]], [[ - #if !defined(QT_STATIC) + #if QT_VERSION_MINOR < 8 choke #endif ]])], - [bitcoin_cv_static_qt=yes], - [bitcoin_cv_static_qt=no]) - ]) + [bitcoin_cv_qt58=yes], + [bitcoin_cv_qt58=no]) +])]) + + +dnl Internal. Check if the linked version of Qt was built as static libs. +dnl Requires: Qt5. +dnl Requires: INCLUDES and LIBS must be populated as necessary. +dnl Output: bitcoin_cv_static_qt=yes|no +dnl Output: Defines QT_STATICPLUGIN if plugins are static. +AC_DEFUN([_BITCOIN_QT_IS_STATIC],[ + AC_CACHE_CHECK(for static Qt, bitcoin_cv_static_qt,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION OR QT_VERSION_STR + # include + #endif + ]], + [[ + #if !defined(QT_STATIC) + choke + #endif + ]])], + [bitcoin_cv_static_qt=yes], + [bitcoin_cv_static_qt=no]) + ]) if test "x$bitcoin_cv_static_qt" = xyes; then AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol for static Qt plugins]) fi @@ -347,28 +351,36 @@ AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_PLUGINS],[ ]) dnl Internal. Find paths necessary for linking qt static plugins -dnl Inputs: bitcoin_qt_got_major_vers. 4 or 5. dnl Inputs: qt_plugin_path. optional. dnl Outputs: QT_LIBS is appended AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ - if test "x$bitcoin_qt_got_major_vers" = x5; then - if test "x$qt_plugin_path" != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" - if test -d "$qt_plugin_path/accessible"; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - fi + if test "x$qt_plugin_path" != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + if test -d "$qt_plugin_path/accessible"; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" fi if test "x$use_pkgconfig" = xyes; then : dnl m4_ifdef([PKG_CHECK_MODULES],[ - PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) + if test x$bitcoin_cv_qt58 = xno; then + PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) + else + PKG_CHECK_MODULES([QTFONTDATABASE], [Qt5FontDatabaseSupport], [QT_LIBS="-lQt5FontDatabaseSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTEVENTDISPATCHER], [Qt5EventDispatcherSupport], [QT_LIBS="-lQt5EventDispatcherSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTTHEME], [Qt5ThemeSupport], [QT_LIBS="-lQt5ThemeSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTDEVICEDISCOVERY], [Qt5DeviceDiscoverySupport], [QT_LIBS="-lQt5DeviceDiscoverySupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTACCESSIBILITY], [Qt5AccessibilitySupport], [QT_LIBS="-lQt5AccessibilitySupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTFB], [Qt5FbSupport], [QT_LIBS="-lQt5FbSupport $QT_LIBS"]) + fi if test "x$TARGET_OS" = xlinux; then PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) fi elif test "x$TARGET_OS" = xdarwin; then - PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"]) + PKG_CHECK_MODULES([QTCLIPBOARD], [Qt5ClipboardSupport], [QT_LIBS="-lQt5ClipboardSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport], [QT_LIBS="-lQt5GraphicsSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTCGL], [Qt5CglSupport], [QT_LIBS="-lQt5CglSupport $QT_LIBS"]) fi ]) else @@ -381,7 +393,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ #endif ]], [[ - #if QT_VERSION < 0x050600 + #if QT_VERSION < 0x050600 || QT_VERSION_MINOR < 6 choke #endif ]])], @@ -389,16 +401,21 @@ AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ [bitcoin_cv_need_platformsupport=no]) ]) if test "x$bitcoin_cv_need_platformsupport" = xyes; then - BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}PlatformSupport not found))) + if test x$bitcoin_cv_qt58 = xno; then + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXPlatformSupport not found))) + else + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}FontDatabaseSupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXFontDatabaseSupport not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}EventDispatcherSupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXEventDispatcherSupport not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}ThemeSupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXThemeSupport not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}FbSupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXFbSupport not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}DeviceDiscoverySupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXDeviceDiscoverySupport not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}AccessibilitySupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXAccessibilitySupport not found))) + QT_LIBS="$QT_LIBS -lversion -ldwmapi -luxtheme" + fi fi fi fi - else - if test "x$qt_plugin_path" != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs" - fi - fi + fi ]) dnl Internal. Find Qt libraries using pkg-config. @@ -407,38 +424,14 @@ dnl first. dnl Inputs: $1: If bitcoin_qt_want_version is "auto", check for this version dnl first. dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ m4_ifdef([PKG_CHECK_MODULES],[ - auto_priority_version=$1 - if test "x$auto_priority_version" = x; then - auto_priority_version=qt5 - fi - if test "x$bitcoin_qt_want_version" = xqt5 || ( test "x$bitcoin_qt_want_version" = xauto && test "x$auto_priority_version" = xqt5 ); then - QT_LIB_PREFIX=Qt5 - bitcoin_qt_got_major_vers=5 - else - QT_LIB_PREFIX=Qt - bitcoin_qt_got_major_vers=4 - fi + QT_LIB_PREFIX=Qt5 qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" - qt4_modules="QtCore QtGui QtNetwork" BITCOIN_QT_CHECK([ - if test "x$bitcoin_qt_want_version" = xqt5 || ( test "x$bitcoin_qt_want_version" = xauto && test "x$auto_priority_version" = xqt5 ); then - PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no]) - elif test "x$bitcoin_qt_want_version" = xqt4 || ( test "x$bitcoin_qt_want_version" = xauto && test "x$auto_priority_version" = xqt4 ); then - PKG_CHECK_MODULES([QT4], [$qt4_modules], [QT_INCLUDES="$QT4_CFLAGS"; QT_LIBS="$QT4_LIBS" ; have_qt=yes], [have_qt=no]) - fi + PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no]) - dnl qt version is set to 'auto' and the preferred version wasn't found. Now try the other. - if test "x$have_qt" = xno && test "x$bitcoin_qt_want_version" = xauto; then - if test "x$auto_priority_version" = xqt5; then - PKG_CHECK_MODULES([QT4], [$qt4_modules], [QT_INCLUDES="$QT4_CFLAGS"; QT_LIBS="$QT4_LIBS" ; have_qt=yes; QT_LIB_PREFIX=Qt; bitcoin_qt_got_major_vers=4], [have_qt=no]) - else - PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" ; have_qt=yes; QT_LIB_PREFIX=Qt5; bitcoin_qt_got_major_vers=5], [have_qt=no]) - fi - fi if test "x$have_qt" != xyes; then have_qt=no BITCOIN_QT_FAIL([Qt dependencies not found]) @@ -459,7 +452,6 @@ dnl from the discovered headers. dnl Inputs: bitcoin_qt_want_version (from --with-gui=). The version to use. dnl If "auto", the version will be discovered by _BITCOIN_QT_CHECK_QT5. dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_CPPFLAGS="$CPPFLAGS" @@ -480,14 +472,9 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ BITCOIN_QT_CHECK([ if test "x$bitcoin_qt_want_version" = xauto; then _BITCOIN_QT_CHECK_QT5 + _BITCOIN_QT_CHECK_QT58 fi - if test "x$bitcoin_cv_qt5" = xyes || test "x$bitcoin_qt_want_version" = xqt5; then - QT_LIB_PREFIX=Qt5 - bitcoin_qt_got_major_vers=5 - else - QT_LIB_PREFIX=Qt - bitcoin_qt_got_major_vers=4 - fi + QT_LIB_PREFIX=Qt5 ]) BITCOIN_QT_CHECK([ @@ -502,16 +489,19 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ ]) BITCOIN_QT_CHECK(AC_CHECK_LIB([z] ,[main],,AC_MSG_WARN([zlib not found. Assuming qt has it built-in]))) - BITCOIN_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) BITCOIN_QT_CHECK(AC_SEARCH_LIBS([jpeg_create_decompress] ,[qtjpeg jpeg],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in]))) - BITCOIN_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) - BITCOIN_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) + if test x$bitcoin_cv_qt58 = xno; then + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) + else + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtlibpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([pcre2_match_16], [qtpcre2 libqtpcre2],,AC_MSG_WARN([libqtpcre2 not found. Assuming qt has it built-in]))) + fi + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng qtharfbuzz harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Core not found))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Gui not found))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Network not found))) - if test "x$bitcoin_qt_got_major_vers" = x5; then - BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found))) - fi + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found))) QT_LIBS="$LIBS" LIBS="$TEMP_LIBS" diff --git a/configure.ac b/configure.ac index 2a9cf5c6697b..d239eae3b61c 100644 --- a/configure.ac +++ b/configure.ac @@ -81,8 +81,8 @@ AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) -dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893) -AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python]) +dnl Python 3.5 is specified in .python-version and should be used if available, see doc/dependencies.md +AC_PATH_PROGS([PYTHON], [python3.5 python3.6 python3.7 python3.8 python3 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) @@ -91,6 +91,11 @@ AC_PATH_PROG(HEXDUMP,hexdump) AC_PATH_TOOL(READELF, readelf) AC_PATH_TOOL(CPPFILT, c++filt) AC_PATH_TOOL(OBJCOPY, objcopy) +AC_PATH_PROG(DOXYGEN, doxygen) +if test -z "$DOXYGEN"; then + AC_MSG_WARN([Doxygen not found]) +fi +AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files) @@ -118,15 +123,20 @@ AC_ARG_ENABLE(tests, [use_tests=$enableval], [use_tests=no]) -AC_ARG_WITH([comparison-tool], - AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]), - [use_comparison_tool=$withval], - [use_comparison_tool=no]) +AC_ARG_ENABLE(gui-tests, + AS_HELP_STRING([--disable-gui-tests],[do not compile GUI tests (default is to compile if GUI and tests enabled)]), + [use_gui_tests=$enableval], + [use_gui_tests=$use_tests]) + +AC_ARG_ENABLE(bench, + AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]), + [use_bench=$enableval], + [use_bench=no]) -AC_ARG_ENABLE([comparison-tool-reorg-tests], - AS_HELP_STRING([--enable-comparison-tool-reorg-tests],[enable expensive reorg tests in the comparison tool (default no)]), - [use_comparison_tool_reorg_tests=$enableval], - [use_comparison_tool_reorg_tests=no]) +AC_ARG_ENABLE([extended-functional-tests], + AS_HELP_STRING([--enable-extended-functional-tests],[enable expensive functional tests when using lcov (default no)]), + [use_extended_functional_tests=$enableval], + [use_extended_functional_tests=no]) AC_ARG_WITH([qrencode], [AS_HELP_STRING([--with-qrencode], @@ -136,9 +146,9 @@ AC_ARG_WITH([qrencode], AC_ARG_ENABLE([hardening], [AS_HELP_STRING([--disable-hardening], - [do not attempt to harden the resulting executables (default is to harden)])], + [do not attempt to harden the resulting executables (default is to harden when possible)])], [use_hardening=$enableval], - [use_hardening=yes]) + [use_hardening=auto]) AC_ARG_ENABLE([reduce-exports], [AS_HELP_STRING([--enable-reduce-exports], @@ -158,17 +168,27 @@ AC_ARG_ENABLE([lcov], [use_lcov=$enableval], [use_lcov=no]) +AC_ARG_ENABLE([lcov-branch-coverage], + [AS_HELP_STRING([--enable-lcov-branch-coverage], + [enable lcov testing branch coverage (default is no)])], + [use_lcov_branch=yes], + [use_lcov_branch=no]) + AC_ARG_ENABLE([glibc-back-compat], [AS_HELP_STRING([--enable-glibc-back-compat], [enable backwards compatibility with glibc])], [use_glibc_compat=$enableval], [use_glibc_compat=no]) -AC_ARG_ENABLE([zmq], - [AS_HELP_STRING([--disable-zmq], - [disable ZMQ notifications])], - [use_zmq=$enableval], - [use_zmq=yes]) +AC_ARG_ENABLE([asm], + [AS_HELP_STRING([--enable-asm], + [Enable assembly routines (default is yes)])], + [use_asm=$enableval], + [use_asm=yes]) + +if test "x$use_asm" = xyes; then + AC_DEFINE(USE_ASM, 1, [Define this symbol to build in assembly routines]) +fi AC_ARG_WITH([system-univalue], [AS_HELP_STRING([--with-system-univalue], @@ -176,9 +196,20 @@ AC_ARG_WITH([system-univalue], [system_univalue=$withval], [system_univalue=no] ) +AC_ARG_ENABLE([zmq], + [AS_HELP_STRING([--disable-zmq], + [disable ZMQ notifications])], + [use_zmq=$enableval], + [use_zmq=yes]) AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) +AC_ARG_ENABLE(man, + [AS_HELP_STRING([--disable-man], + [do not install man pages (default is to install)])],, + enable_man=yes) +AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no) + # Enable debug AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], @@ -186,6 +217,19 @@ AC_ARG_ENABLE([debug], [enable_debug=$enableval], [enable_debug=no]) +# Enable different -fsanitize options +AC_ARG_WITH([sanitizers], + [AS_HELP_STRING([--with-sanitizers], + [comma separated list of extra sanitizers to build with (default is none enabled)])], + [use_sanitizers=$withval]) + +# Enable gprof profiling +AC_ARG_ENABLE([gprof], + [AS_HELP_STRING([--enable-gprof], + [use gprof profiling compiler flags (default is no)])], + [enable_gprof=$enableval], + [enable_gprof=no]) + # Turn warnings into errors AC_ARG_ENABLE([werror], [AS_HELP_STRING([--enable-werror], @@ -197,14 +241,47 @@ AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) if test "x$enable_debug" = xyes; then - CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER" - if test "x$GCC" = xyes; then - CFLAGS="$CFLAGS -g3 -O0" - fi + # Clear default -g -O2 flags + if test "x$CXXFLAGS_overridden" = xno; then + CXXFLAGS="" + fi + # Prefer -Og, fall back to -O0 if that is unavailable. + AX_CHECK_COMPILE_FLAG( + [-Og], + [[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -Og"]], + [AX_CHECK_COMPILE_FLAG([-O0],[[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -O0"]],,[[$CXXFLAG_WERROR]])], + [[$CXXFLAG_WERROR]]) + + # Prefer -g3, fall back to -g if that is unavailable. + AX_CHECK_COMPILE_FLAG( + [-g3], + [[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -g3"]], + [AX_CHECK_COMPILE_FLAG([-g],[[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -g"]],,[[$CXXFLAG_WERROR]])], + [[$CXXFLAG_WERROR]]) + + AX_CHECK_PREPROC_FLAG([-DDEBUG],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG"]],,[[$CXXFLAG_WERROR]]) + AX_CHECK_PREPROC_FLAG([-DDEBUG_LOCKORDER],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG_LOCKORDER"]],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-ftrapv],[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -ftrapv"],,[[$CXXFLAG_WERROR]]) +fi - if test "x$GXX" = xyes; then - CXXFLAGS="$CXXFLAGS -g3 -O0" - fi +if test x$use_sanitizers != x; then + # First check if the compiler accepts flags. If an incompatible pair like + # -fsanitize=address,thread is used here, this check will fail. This will also + # fail if a bad argument is passed, e.g. -fsanitize=undfeined + AX_CHECK_COMPILE_FLAG( + [[-fsanitize=$use_sanitizers]], + [[SANITIZER_CXXFLAGS=-fsanitize=$use_sanitizers]], + [AC_MSG_ERROR([compiler did not accept requested flags])]) + + # Some compilers (e.g. GCC) require additional libraries like libasan, + # libtsan, libubsan, etc. Make sure linking still works with the sanitize + # flag. This is a separate check so we can give a better error message when + # the sanitize flags are supported by the compiler but the actual sanitizer + # libs are missing. + AX_CHECK_LINK_FLAG( + [[-fsanitize=$use_sanitizers]], + [[SANITIZER_LDFLAGS=-fsanitize=$use_sanitizers]], + [AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])]) fi ERROR_CXXFLAGS= @@ -217,22 +294,102 @@ if test "x$enable_werror" = "xyes"; then fi if test "x$CXXFLAGS_overridden" = "xno"; then - AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS="$CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[CXXFLAGS="$CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wall],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wextra],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wvla],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat-security],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wrange-loop-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wredundant-decls],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"],,[[$CXXFLAG_WERROR]]) ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all ## unknown options if any other warning is produced. Test the -Wfoo case, and ## set the -Wno-foo case if it works. - AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[CXXFLAGS="$CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wself-assign],[CXXFLAGS="$CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[CXXFLAGS="$CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wself-assign],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) fi + +# Check for optional instruction set support. Enabling these does _not_ imply that all code will +# be compiled with them, rather that specific objects/libs may use them after checking for runtime +# compatibility. +AX_CHECK_COMPILE_FLAG([-msse4.2],[[SSE42_CXXFLAGS="-msse4.2"]],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-msse4.1],[[SSE41_CXXFLAGS="-msse4.1"]],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-mavx -mavx2],[[AVX2_CXXFLAGS="-mavx -mavx2"]],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-msse4 -msha],[[SHANI_CXXFLAGS="-msse4 -msha"]],,[[$CXXFLAG_WERROR]]) + +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $SSE42_CXXFLAGS" +AC_MSG_CHECKING(for assembler crc32 support) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #if defined(_MSC_VER) + #include + #elif defined(__GNUC__) && defined(__SSE4_2__) + #include + #endif + ]],[[ + uint64_t l = 0; + l = _mm_crc32_u8(l, 0); + l = _mm_crc32_u32(l, 0); + l = _mm_crc32_u64(l, 0); + return l; + ]])], + [ AC_MSG_RESULT(yes); enable_hwcrc32=yes], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $SSE41_CXXFLAGS" +AC_MSG_CHECKING(for SSE4.1 intrinsics) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + ]],[[ + __m128i l = _mm_set1_epi32(0); + return _mm_extract_epi32(l, 3); + ]])], + [ AC_MSG_RESULT(yes); enable_sse41=yes; AC_DEFINE(ENABLE_SSE41, 1, [Define this symbol to build code that uses SSE4.1 intrinsics]) ], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $AVX2_CXXFLAGS" +AC_MSG_CHECKING(for AVX2 intrinsics) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + ]],[[ + __m256i l = _mm256_set1_epi32(0); + return _mm256_extract_epi32(l, 7); + ]])], + [ AC_MSG_RESULT(yes); enable_avx2=yes; AC_DEFINE(ENABLE_AVX2, 1, [Define this symbol to build code that uses AVX2 intrinsics]) ], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $SHANI_CXXFLAGS" +AC_MSG_CHECKING(for SHA-NI intrinsics) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + ]],[[ + __m128i i = _mm_set1_epi32(0); + __m128i j = _mm_set1_epi32(1); + __m128i k = _mm_set1_epi32(2); + return _mm_extract_epi32(_mm_sha256rnds2_epu32(i, i, k), 0); + ]])], + [ AC_MSG_RESULT(yes); enable_shani=yes; AC_DEFINE(ENABLE_SHANI, 1, [Define this symbol to build code that uses SHA-NI intrinsics]) ], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], @@ -243,7 +400,7 @@ AC_ARG_WITH([utils], AC_ARG_WITH([libs], [AS_HELP_STRING([--with-libs], - [build libraries (default=yes)])], + [build libraries (default=no)])], [build_bitcoin_libs=$withval], [build_bitcoin_libs=no]) @@ -261,25 +418,25 @@ case $host in use_pkgconfig=no TARGET_OS=windows - AC_CHECK_LIB([mingwthrd], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([kernel32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([user32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([gdi32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([comdlg32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([winspool], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([winmm], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([shell32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([comctl32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([ole32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([oleaut32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([uuid], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([rpcrt4], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([advapi32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([ws2_32], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([mswsock], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([shlwapi], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(lib missing)) - AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([mingwthrd], [main],, AC_MSG_ERROR(libmingwthrd missing)) + AC_CHECK_LIB([kernel32], [main],, AC_MSG_ERROR(libkernel32 missing)) + AC_CHECK_LIB([user32], [main],, AC_MSG_ERROR(libuser32 missing)) + AC_CHECK_LIB([gdi32], [main],, AC_MSG_ERROR(libgdi32 missing)) + AC_CHECK_LIB([comdlg32], [main],, AC_MSG_ERROR(libcomdlg32 missing)) + AC_CHECK_LIB([winspool], [main],, AC_MSG_ERROR(libwinspool missing)) + AC_CHECK_LIB([winmm], [main],, AC_MSG_ERROR(libwinmm missing)) + AC_CHECK_LIB([shell32], [main],, AC_MSG_ERROR(libshell32 missing)) + AC_CHECK_LIB([comctl32], [main],, AC_MSG_ERROR(libcomctl32 missing)) + AC_CHECK_LIB([ole32], [main],, AC_MSG_ERROR(libole32 missing)) + AC_CHECK_LIB([oleaut32], [main],, AC_MSG_ERROR(liboleaut32 missing)) + AC_CHECK_LIB([uuid], [main],, AC_MSG_ERROR(libuuid missing)) + AC_CHECK_LIB([rpcrt4], [main],, AC_MSG_ERROR(librpcrt4 missing)) + AC_CHECK_LIB([advapi32], [main],, AC_MSG_ERROR(libadvapi32 missing)) + AC_CHECK_LIB([ws2_32], [main],, AC_MSG_ERROR(libws2_32 missing)) + AC_CHECK_LIB([mswsock], [main],, AC_MSG_ERROR(libmswsock missing)) + AC_CHECK_LIB([shlwapi], [main],, AC_MSG_ERROR(libshlwapi missing)) + AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(libiphlpapi missing)) + AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(libcrypt32 missing)) # -static is interpreted by libtool, where it has a different meaning. # In libtool-speak, it's -all-static. @@ -296,7 +453,7 @@ case $host in fi CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB" - LEVELDB_TARGET_FLAGS="TARGET_OS=OS_WINDOWS_CROSSCOMPILE" + LEVELDB_TARGET_FLAGS="-DOS_WINDOWS" if test "x$CXXFLAGS_overridden" = "xno"; then CXXFLAGS="$CXXFLAGS -w" fi @@ -318,7 +475,7 @@ case $host in ;; *darwin*) TARGET_OS=darwin - LEVELDB_TARGET_FLAGS="TARGET_OS=Darwin" + LEVELDB_TARGET_FLAGS="-DOS_MACOSX" if test x$cross_compiling != xyes; then BUILD_OS=darwin AC_CHECK_PROG([PORT],port, port) @@ -383,10 +540,39 @@ case $host in CPPFLAGS="$CPPFLAGS -DMAC_OSX" OBJCXXFLAGS="$CXXFLAGS" ;; + *android*) + dnl make sure android stays above linux for hosts like *linux-android* + LEVELDB_TARGET_FLAGS="-DOS_ANDROID" + ;; *linux*) TARGET_OS=linux + LEVELDB_TARGET_FLAGS="-DOS_LINUX" + ;; + *kfreebsd*) + LEVELDB_TARGET_FLAGS="-DOS_KFREEBSD" + ;; + *freebsd*) + LEVELDB_TARGET_FLAGS="-DOS_FREEBSD" + ;; + *openbsd*) + LEVELDB_TARGET_FLAGS="-DOS_OPENBSD" + ;; + *netbsd*) + LEVELDB_TARGET_FLAGS="-DOS_NETBSD" + ;; + *dragonfly*) + LEVELDB_TARGET_FLAGS="-DOS_DRAGONFLYBSD" + ;; + *solaris*) + LEVELDB_TARGET_FLAGS="-DOS_SOLARIS" + ;; + *hpux*) + LEVELDB_TARGET_FLAGS="-DOS_HPUX" ;; *) + OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'` + AC_MSG_WARN([Guessing LevelDB OS as OS_${OTHER_OS}, please check whether this is correct, if not add an entry to configure.ac.]) + LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}" ;; esac @@ -400,17 +586,8 @@ if test x$use_pkgconfig = xyes; then ]) fi -if test x$use_comparison_tool != xno; then - AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool) -fi - -if test x$use_comparison_tool_reorg_tests != xno; then - if test x$use_comparison_tool = x; then - AC_MSG_ERROR("comparison tool reorg tests but comparison tool was not specified") - fi - AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 1) -else - AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0) +if test x$use_extended_functional_tests != xno; then + AC_SUBST(EXTENDED_FUNCTIONAL_TESTS, --extended) fi if test x$use_lcov = xyes; then @@ -435,8 +612,12 @@ if test x$use_lcov = xyes; then CXXFLAGS="$CXXFLAGS -Og" fi -dnl Require little endian -AC_C_BIGENDIAN([AC_MSG_ERROR("Big Endian not supported")]) +if test x$use_lcov_branch != xno; then + AC_SUBST(LCOV_OPTS, "$LCOV_OPTS --rc lcov_branch_coverage=1") +fi + +dnl Check for endianness +AC_C_BIGENDIAN dnl Check for pthread compile/link requirements AX_PTHREAD @@ -470,7 +651,7 @@ if test x$use_glibc_compat != xno; then #glibc absorbed clock_gettime in 2.17. librt (its previous location) is safe to link #in anyway for back-compat. - AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(librt missing)) #__fdelt_chk's params and return type have changed from long unsigned int to long int. # See which one is present here. @@ -485,16 +666,36 @@ if test x$use_glibc_compat != xno; then [ fdelt_type="long int"]) AC_MSG_RESULT($fdelt_type) AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) + AX_CHECK_LINK_FLAG([[-Wl,--wrap=__divmoddi4]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=__divmoddi4"]) + AX_CHECK_LINK_FLAG([[-Wl,--wrap=log2f]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=log2f"]) else AC_SEARCH_LIBS([clock_gettime],[rt]) fi +if test "x$enable_gprof" = xyes; then + dnl -pg is incompatible with -pie. Since hardening and profiling together doesn't make sense, + dnl we simply make them mutually exclusive here. Additionally, hardened toolchains may force + dnl -pie by default, in which case it needs to be turned off with -no-pie. + + if test x$use_hardening = xyes; then + AC_MSG_ERROR(gprof profiling is not compatible with hardening. Reconfigure with --disable-hardening or --disable-gprof) + fi + use_hardening=no + AX_CHECK_COMPILE_FLAG([-pg],[GPROF_CXXFLAGS="-pg"], + [AC_MSG_ERROR(gprof profiling requested but not available)], [[$CXXFLAG_WERROR]]) + + AX_CHECK_LINK_FLAG([[-no-pie]], [GPROF_LDFLAGS="-no-pie"]) + AX_CHECK_LINK_FLAG([[-pg]],[GPROF_LDFLAGS="$GPROF_LDFLAGS -pg"], + [AC_MSG_ERROR(gprof profiling requested but not available)], [[$GPROF_LDFLAGS]]) +fi + if test x$TARGET_OS != xwindows; then # All windows code is PIC, forcing it on just adds useless compile warnings AX_CHECK_COMPILE_FLAG([-fPIC],[PIC_FLAGS="-fPIC"]) fi if test x$use_hardening != xno; then + use_hardening=yes AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) AX_CHECK_COMPILE_FLAG([-fstack-protector-all],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"]) @@ -510,15 +711,11 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"]) AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"]) AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) - - if test x$TARGET_OS != xwindows; then - AX_CHECK_COMPILE_FLAG([-fPIC],[PIE_FLAGS="-fPIC"]) - AX_CHECK_LINK_FLAG([[-pic]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pic"]) - fi + AX_CHECK_LINK_FLAG([[-fPIE -pie]], [PIE_FLAGS="-fPIE"; HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"],, [[$CXXFLAG_WERROR]]) case $host in *mingw*) - AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(libssp missing)) ;; esac fi @@ -528,35 +725,26 @@ if test x$TARGET_OS = xdarwin; then AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"]) fi -AC_CHECK_HEADERS([endian.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) -AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])]) -AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])]) +AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) AC_CHECK_DECLS([strnlen]) # Check for daemon(3), unrelated to --with-daemon (although used by it) AC_CHECK_DECLS([daemon]) -AC_CHECK_DECLS([le32toh, le64toh, htole32, htole64, be32toh, be64toh, htobe32, htobe64],,, +AC_CHECK_DECLS([le16toh, le32toh, le64toh, htole16, htole32, htole64, be16toh, be32toh, be64toh, htobe16, htobe32, htobe64],,, [#if HAVE_ENDIAN_H #include + #elif HAVE_SYS_ENDIAN_H + #include #endif]) -dnl Check for MSG_NOSIGNAL -AC_MSG_CHECKING(for MSG_NOSIGNAL) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[ int f = MSG_NOSIGNAL; ]])], - [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_NOSIGNAL, 1,[Define this symbol if you have MSG_NOSIGNAL]) ], - [ AC_MSG_RESULT(no)] -) +AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,, + [#if HAVE_BYTESWAP_H + #include + #endif]) -dnl Check for MSG_DONTWAIT -AC_MSG_CHECKING(for MSG_DONTWAIT) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[ int f = MSG_DONTWAIT; ]])], - [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ], - [ AC_MSG_RESULT(no)] -) +AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll]) dnl Check for malloc_info (for memory statistics information in getmemoryinfo) AC_MSG_CHECKING(for getmemoryinfo) @@ -636,7 +824,7 @@ dnl Check for libminiupnpc (optional) if test x$use_upnp != xno; then AC_CHECK_HEADERS( [miniupnpc/miniwget.h miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h], - [AC_CHECK_LIB([miniupnpc], [main],[MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])], + [AC_CHECK_LIB([miniupnpc], [upnpDiscover], [MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])], [have_miniupnpc=no] ) fi @@ -644,9 +832,9 @@ fi BITCOIN_QT_INIT dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus -BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt5]) +BITCOIN_QT_CONFIGURE([$use_pkgconfig]) -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then +if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then use_boost=no else use_boost=yes @@ -659,6 +847,9 @@ define(MINIMUM_REQUIRED_BOOST, 1.47.0) dnl Check for boost libs AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST]) +if test x$want_boost = xno; then + AC_MSG_ERROR([[only libbitcoinconsensus can be built without boost]]) +fi AX_BOOST_SYSTEM AX_BOOST_FILESYSTEM AX_BOOST_PROGRAM_OPTIONS @@ -895,6 +1086,21 @@ else fi fi +save_CXXFLAGS="${CXXFLAGS}" +CXXFLAGS="${CXXFLAGS} ${CRYPTO_CFLAGS} ${SSL_CFLAGS}" +AC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT +#include +]) +CXXFLAGS="${save_CXXFLAGS}" + +AC_CHECK_LIB([crypto],[RAND_egd],[],[ + AC_ARG_WITH([unsupported-ssl], + [AS_HELP_STRING([--with-unsupported-ssl],[Build with system SSL (default is no; DANGEROUS; NOT SUPPORTED; You should use OpenSSL 1.0)])], + [AC_MSG_WARN([Detected unsupported SSL version: This is NOT supported, and may break consensus compatibility!])], + [AC_MSG_ERROR([Detected unsupported SSL version: This is NOT supported, and may break consensus compatibility!])] + ) +]) + AC_CHECK_LIB([crypto],[RAND_egd],[],[ AC_ARG_WITH([unsupported-ssl], [AS_HELP_STRING([--with-unsupported-ssl],[Build with system SSL (default is no; DANGEROUS; NOT SUPPORTED; You should use OpenSSL 1.0)])], @@ -905,6 +1111,12 @@ AC_CHECK_LIB([crypto],[RAND_egd],[],[ dnl univalue check +need_bundled_univalue=yes + +if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then + need_bundled_univalue=no +else + if test x$system_univalue != xno ; then found_univalue=no if test x$use_pkgconfig = xyes; then @@ -912,7 +1124,7 @@ if test x$system_univalue != xno ; then m4_ifdef( [PKG_CHECK_MODULES], [ - PKG_CHECK_MODULES([UNIVALUE],[libunivalue],[found_univalue=yes],[true]) + PKG_CHECK_MODULES([UNIVALUE],[libunivalue >= 1.0.4],[found_univalue=yes],[true]) ] ) else @@ -926,6 +1138,7 @@ if test x$system_univalue != xno ; then if test x$found_univalue = xyes ; then system_univalue=yes + need_bundled_univalue=no elif test x$system_univalue = xyes ; then AC_MSG_ERROR([univalue not found]) else @@ -933,22 +1146,17 @@ if test x$system_univalue != xno ; then fi fi -if test x$system_univalue = xno ; then +if test x$need_bundled_univalue = xyes ; then UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include' UNIVALUE_LIBS='univalue/libunivalue.la' fi -AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$system_univalue = xno]) + +fi + +AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes]) AC_SUBST(UNIVALUE_CFLAGS) AC_SUBST(UNIVALUE_LIBS) -CFLAGS_TEMP="$CFLAGS" -LIBS_TEMP="$LIBS" -CFLAGS="$CFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" -LIBS="$LIBS $SSL_LIBS $CRYPTO_LIBS" -AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),) -CFLAGS="$CFLAGS_TEMP" -LIBS="$LIBS_TEMP" - BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path) AC_MSG_CHECKING([whether to build phored]) @@ -963,6 +1171,7 @@ AC_MSG_CHECKING([whether to build libraries]) AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes]) if test x$build_bitcoin_libs = xyes; then AC_DEFINE(HAVE_CONSENSUS_LIB, 1, [Define this symbol if the consensus lib has been built]) + AC_CONFIG_FILES([libbitcoinconsensus.pc:libbitcoinconsensus.pc.in]) fi AC_MSG_RESULT($build_bitcoin_libs) @@ -1025,8 +1234,8 @@ else fi dnl these are only used when qt is enabled +BUILD_TEST_QT="" if test x$bitcoin_enable_qt != xno; then - BUILD_QT=qt dnl enable dbus support AC_MSG_CHECKING([whether to build GUI with support for D-Bus]) if test x$bitcoin_enable_qt_dbus != xno; then @@ -1056,9 +1265,9 @@ if test x$bitcoin_enable_qt != xno; then fi AC_MSG_CHECKING([whether to build test_phore-qt]) - if test x$use_tests$bitcoin_enable_qt_test = xyesyes; then + if test x$use_gui_tests$bitcoin_enable_qt_test = xyesyes; then AC_MSG_RESULT([yes]) - BUILD_TEST_QT="test" + BUILD_TEST_QT="yes" else AC_MSG_RESULT([no]) fi @@ -1069,9 +1278,10 @@ AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) AC_MSG_CHECKING([whether to build test_phore]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) - BUILD_TEST="test" + BUILD_TEST="yes" else AC_MSG_RESULT([no]) + BUILD_TEST="" fi AC_MSG_CHECKING([whether to reduce exports]) @@ -1081,23 +1291,27 @@ else AC_MSG_RESULT([no]) fi -if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_tests = xnonononono; then - AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui or --enable-tests]) +if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononono; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests]) fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) -AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests = xyes]) +AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) -AM_CONDITIONAL([HAVE_QT5], [test x$bitcoin_qt_got_major_vers = x5]) -AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes]) +AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) +AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) -AM_CONDITIONAL([USE_LIBSECP256K1],[test x$use_libsecp256k1 = xyes]) +AM_CONDITIONAL([ENABLE_HWCRC32],[test x$enable_hwcrc32 = xyes]) +AM_CONDITIONAL([ENABLE_SSE41],[test x$enable_sse41 = xyes]) +AM_CONDITIONAL([ENABLE_AVX2],[test x$enable_avx2 = xyes]) +AM_CONDITIONAL([ENABLE_SHANI],[test x$enable_shani = xyes]) +AM_CONDITIONAL([USE_ASM],[test x$use_asm = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) @@ -1117,21 +1331,31 @@ AC_SUBST(BITCOIN_CLI_NAME) AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) +AC_SUBST(DEBUG_CPPFLAGS) +AC_SUBST(WARN_CXXFLAGS) +AC_SUBST(NOWARN_CXXFLAGS) +AC_SUBST(DEBUG_CXXFLAGS) +AC_SUBST(COMPAT_LDFLAGS) AC_SUBST(ERROR_CXXFLAGS) +AC_SUBST(GPROF_CXXFLAGS) +AC_SUBST(GPROF_LDFLAGS) AC_SUBST(HARDENED_CXXFLAGS) AC_SUBST(HARDENED_CPPFLAGS) AC_SUBST(HARDENED_LDFLAGS) AC_SUBST(PIC_FLAGS) AC_SUBST(PIE_FLAGS) +AC_SUBST(SANITIZER_CXXFLAGS) +AC_SUBST(SANITIZER_LDFLAGS) +AC_SUBST(SSE42_CXXFLAGS) +AC_SUBST(SSE41_CXXFLAGS) +AC_SUBST(AVX2_CXXFLAGS) +AC_SUBST(SHANI_CXXFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) -AC_SUBST(BUILD_TEST) -AC_SUBST(BUILD_QT) -AC_SUBST(BUILD_TEST_QT) AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) AC_SUBST(CRYPTO_LIBS) @@ -1141,11 +1365,12 @@ AC_SUBST(EVENT_PTHREADS_LIBS) AC_SUBST(ZMQ_LIBS) AC_SUBST(PROTOBUF_LIBS) AC_SUBST(QR_LIBS) -AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) +AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) -AC_CONFIG_FILES([doc/Doxyfile]) +AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])]) +AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) dnl boost's m4 checks do something really nasty: they export these vars. As a dnl result, they leak into secp256k1's configure and crazy things happen. @@ -1170,11 +1395,11 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" -if test x$system_univalue = xno; then +if test x$need_bundled_univalue = xyes; then AC_CONFIG_SUBDIRS([src/univalue]) fi -ac_configure_args="${ac_configure_args} --disable-shared --with-pic" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery --disable-jni" AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT @@ -1203,14 +1428,16 @@ echo "Options used to compile and link:" echo " with wallet = $enable_wallet" echo " with gui / qt = $bitcoin_enable_qt" if test x$bitcoin_enable_qt != xno; then - echo " qt version = $bitcoin_qt_got_major_vers" echo " with qr = $use_qr" fi echo " with zmq = $use_zmq" echo " with test = $use_tests" -dnl echo " with bench = $use_bench" +echo " with bench = $use_bench" echo " with upnp = $use_upnp" +echo " use asm = $use_asm" +echo " sanitizers = $use_sanitizers" echo " debug enabled = $enable_debug" +echo " gprof enabled = $enable_gprof" echo " werror = $enable_werror" echo echo " target os = $TARGET_OS" @@ -1218,9 +1445,11 @@ echo " build os = $BUILD_OS" echo echo " CC = $CC" echo " CFLAGS = $CFLAGS" -echo " CPPFLAGS = $CPPFLAGS" +echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CPPFLAGS" echo " CXX = $CXX" -echo " CXXFLAGS = $CXXFLAGS" -echo " LDFLAGS = $LDFLAGS" +echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CXXFLAGS" +echo " LDFLAGS = $PTHREAD_CFLAGS $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAGS" echo " ARFLAGS = $ARFLAGS" +echo " PIC_FLAGS = $PIC_FLAGS" +echo " QT_PIE_FLAGS = $QT_PIE_FLAGS" echo diff --git a/contrib/cmake/FindBerkeleyDB.cmake b/contrib/cmake/FindBerkeleyDB.cmake new file mode 100644 index 000000000000..bf29fbd62fca --- /dev/null +++ b/contrib/cmake/FindBerkeleyDB.cmake @@ -0,0 +1,146 @@ +# Author: sum01 +# Git: https://github.com/sum01/FindBerkeleyDB +# Read the README.md for the full info. + +# Allow user to pass a path instead of guessing +if(BerkeleyDB_ROOT_DIR) + set(_BERKELEYDB_PATHS "${BerkeleyDB_ROOT_DIR}") +elseif(CMAKE_SYSTEM_NAME MATCHES ".*[wW]indows.*") + # MATCHES is used to work on any devies with windows in the name + # Shameless copy-paste from FindOpenSSL.cmake v3.8 + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + list(APPEND _BERKELEYDB_HINTS "${_programfiles}") + + # There's actually production release and version numbers in the file path. + # For example, if they're on v6.2.32: C:/Program Files/Oracle/Berkeley DB 12cR1 6.2.32/ + # But this still works to find it, so I'm guessing it can accept partial path matches. + + foreach(_TARGET_BERKELEYDB_PATH "Oracle/Berkeley DB" "Berkeley DB") + list(APPEND _BERKELEYDB_PATHS + "${_programfiles}/${_TARGET_BERKELEYDB_PATH}" + "C:/Program Files (x86)/${_TARGET_BERKELEYDB_PATH}" + "C:/Program Files/${_TARGET_BERKELEYDB_PATH}" + "C:/${_TARGET_BERKELEYDB_PATH}" + ) + endforeach() +else() + # Paths for anything other than Windows + # Cellar/berkeley-db is for macOS from homebrew installation + list(APPEND _BERKELEYDB_PATHS + "/usr/local/Cellar/berkeley-db@4" + "/usr/local/Cellar/berkeley-db" + "/opt" + "/opt/local" + "/usr/local" + ) +endif() + +# Find includes path +find_path(BerkeleyDB_INCLUDE_DIRS + db_cxx.h + PATHS "${_BERKELEYDB_PATHS}" + PATH_SUFFIXES "include" "includes" + ) + +# Checks if the version file exists, save the version file to a var, and fail if there's no version file +if(BerkeleyDB_INCLUDE_DIRS) + # Read the version file db.h into a variable + file(READ "${BerkeleyDB_INCLUDE_DIRS}/db.h" _BERKELEYDB_DB_HEADER) + # Parse the DB version into variables to be used in the lib names + std::string(REGEX REPLACE ".*DB_VERSION_MAJOR ([0-9]+).*" "\\1" BerkeleyDB_VERSION_MAJOR "${_BERKELEYDB_DB_HEADER}") + std::string(REGEX REPLACE ".*DB_VERSION_MINOR ([0-9]+).*" "\\1" BerkeleyDB_VERSION_MINOR "${_BERKELEYDB_DB_HEADER}") + # Patch version example on non-crypto installs: x.x.xNC + std::string(REGEX REPLACE ".*DB_VERSION_PATCH ([0-9]+(NC)?).*" "\\1" BerkeleyDB_VERSION_PATCH "${_BERKELEYDB_DB_HEADER}") +else() + if(BerkeleyDB_FIND_REQUIRED) + # If the find_package(BerkeleyDB REQUIRED) was used, fail since we couldn't find the header + message(FATAL_ERROR "Failed to find Berkeley DB's header file \"db.h\"! Try setting \"BerkeleyDB_ROOT_DIR\" when initiating Cmake.") + elseif(NOT BerkeleyDB_FIND_QUIETLY) + message(WARNING "Failed to find Berkeley DB's header file \"db.h\"! Try setting \"BerkeleyDB_ROOT_DIR\" when initiating Cmake.") + endif() + # Set some garbage values to the versions since we didn't find a file to read + set(BerkeleyDB_VERSION_MAJOR "0") + set(BerkeleyDB_VERSION_MINOR "0") + set(BerkeleyDB_VERSION_PATCH "0") +endif() + +# The actual returned/output version variable (the others can be used if needed) +set(BerkeleyDB_VERSION "${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}.${BerkeleyDB_VERSION_PATCH}") + +# Finds the target library for berkeley db, since they all follow the same naming conventions +macro(findpackage_berkeleydb_get_lib _BERKELEYDB_OUTPUT_VARNAME _TARGET_BERKELEYDB_LIB) + # Different systems sometimes have a version in the lib name... + # and some have a dash or underscore before the versions. + # CMake recommends to put unversioned names before versioned names + find_library(${_BERKELEYDB_OUTPUT_VARNAME} + NAMES + "${_TARGET_BERKELEYDB_LIB}" + "lib${_TARGET_BERKELEYDB_LIB}" + "lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}" + "lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}" + "lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}" + HINTS ${_BERKELEYDB_HINTS} + PATH_SUFFIXES "lib" "lib64" "libs" "libs64" + PATHS ${_BERKELEYDB_PATHS} + ) + # If the library was found, add it to our list of libraries + if(${_BERKELEYDB_OUTPUT_VARNAME}) + # If found, append to our libraries variable + # The ${{}} is because the first expands to target the real variable, the second expands the variable's contents... + # and the real variable's contents is the path to the lib. Thus, it appends the path of the lib to BerkeleyDB_LIBRARIES. + list(APPEND BerkeleyDB_LIBRARIES "${${_BERKELEYDB_OUTPUT_VARNAME}}") + endif() +endmacro() + +# Find and set the paths of the specific library to the variable +findpackage_berkeleydb_get_lib(BerkeleyDB_LIBRARY "db") +# NOTE: Windows doesn't have a db_cxx lib, but instead compiles the cxx code into the "db" lib +findpackage_berkeleydb_get_lib(BerkeleyDB_Cxx_LIBRARY "db_cxx") +# NOTE: I don't think Linux/Unix gets an SQL lib +findpackage_berkeleydb_get_lib(BerkeleyDB_Sql_LIBRARY "db_sql") +findpackage_berkeleydb_get_lib(BerkeleyDB_Stl_LIBRARY "db_stl") + +# Needed for find_package_handle_standard_args() +include(FindPackageHandleStandardArgs) +# Fails if required vars aren't found, or if the version doesn't meet specifications. +find_package_handle_standard_args(BerkeleyDB + FOUND_VAR BerkeleyDB_FOUND + REQUIRED_VARS + BerkeleyDB_INCLUDE_DIRS + BerkeleyDB_LIBRARY + VERSION_VAR BerkeleyDB_VERSION + ) + +# Create an imported lib for easy linking by external projects +if(BerkeleyDB_FOUND AND BerkeleyDB_LIBRARIES AND NOT TARGET Oracle::BerkeleyDB) + add_library(Oracle::BerkeleyDB UNKNOWN IMPORTED) + set_target_properties(Oracle::BerkeleyDB PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${BerkeleyDB_INCLUDE_DIRS}" + IMPORTED_LOCATION "${BerkeleyDB_LIBRARY}" + INTERFACE_LINK_LIBRARIES "${BerkeleyDB_LIBRARIES}" + ) +endif() + +# Only show the includes path and libraries in the GUI if they click "advanced". +# Does nothing when using the CLI +mark_as_advanced(FORCE + BerkeleyDB_INCLUDE_DIRS + BerkeleyDB_LIBRARIES + BerkeleyDB_LIBRARY + BerkeleyDB_Cxx_LIBRARY + BerkeleyDB_Sql_LIBRARY + BerkeleyDB_Stl_LIBRARY + ) + +include(FindPackageMessage) +# A message that tells the user what includes/libs were found, and obeys the QUIET command. +find_package_message(BerkeleyDB + "Found BerkeleyDB libraries: ${BerkeleyDB_LIBRARIES}" + "[${BerkeleyDB_LIBRARIES}[${BerkeleyDB_INCLUDE_DIRS}]]" + ) diff --git a/contrib/cmake/FindGMP.cmake b/contrib/cmake/FindGMP.cmake new file mode 100644 index 000000000000..ee39ba114385 --- /dev/null +++ b/contrib/cmake/FindGMP.cmake @@ -0,0 +1,33 @@ +# - Find GMP +# This module defines +# GMP_INCLUDE_DIR, where to find GMP headers +# GMP_LIBRARY, LibEvent libraries +# GMP_FOUND, If false, do not try to use GMP + +set(GMP_PREFIX "" CACHE PATH "path ") + +find_path(GMP_INCLUDE_DIR gmp.h gmpxx.h + PATHS ${GMP_PREFIX}/include /usr/include /usr/local/include ) + +find_library(GMP_LIBRARY NAMES gmp libgmp + PATHS ${GMP_PREFIX}/lib /usr/lib /usr/local/lib) + +if(GMP_INCLUDE_DIR AND GMP_LIBRARY) + get_filename_component(GMP_LIBRARY_DIR ${GMP_LIBRARY} PATH) + set(GMP_FOUND TRUE) +endif() + +if(GMP_FOUND) + if(NOT GMP_FIND_QUIETLY) + MESSAGE(STATUS "Found GMP: ${GMP_LIBRARY}") + endif() +elseif(GMP_FOUND) + if(GMP_FIND_REQUIRED) + message(FATAL_ERROR "Could not find GMP") + endif() +endif() + +mark_as_advanced( + GMP_LIB + GMP_INCLUDE_DIR +) diff --git a/contrib/cmake/FindLibEvent.cmake b/contrib/cmake/FindLibEvent.cmake new file mode 100644 index 000000000000..d0ffdf0ad472 --- /dev/null +++ b/contrib/cmake/FindLibEvent.cmake @@ -0,0 +1,44 @@ +# - Find LibEvent (a cross event library) +# This module defines +# LIBEVENT_INCLUDE_DIR, where to find LibEvent headers +# LIBEVENT_LIB, LibEvent libraries +# LibEvent_FOUND, If false, do not try to use libevent + +if(($ENV{triple}) AND (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}")) + set(LIBEVENT_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/include") + set(LIBEVENT_LIB "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib/libevent.a") + set(LIBEVENT_PTHREAD_LIB "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib/libevent.a") +else() + set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") + foreach(prefix ${LibEvent_EXTRA_PREFIXES}) + list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include") + list(APPEND LibEvent_LIB_PATHS "${prefix}/lib") + endforeach() + + find_path(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS}) + find_library(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS}) + find_library(LIBEVENT_PTHREAD_LIB NAMES event_pthreads PATHS ${LibEvent_LIB_PATHS}) +endif() + +if (LIBEVENT_LIB AND LIBEVENT_INCLUDE_DIR AND LIBEVENT_PTHREAD_LIB) + set(LibEvent_FOUND TRUE) + set(LIBEVENT_LIB ${LIBEVENT_LIB} ${LIBEVENT_PTHREAD_LIB}) +else () + set(LibEvent_FOUND FALSE) +endif () + +if (LibEvent_FOUND) + if (NOT LibEvent_FIND_QUIETLY) + message(STATUS "Found libevent: ${LIBEVENT_LIB}") + endif () +else () + if (LibEvent_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find libevent and libevent_pthread.") + endif () + message(STATUS "libevent and libevent_pthread NOT found.") +endif () + +mark_as_advanced( + LIBEVENT_LIB + LIBEVENT_INCLUDE_DIR +) diff --git a/contrib/cmake/FindQrcode.cmake b/contrib/cmake/FindQrcode.cmake new file mode 100644 index 000000000000..702d0d10f7d1 --- /dev/null +++ b/contrib/cmake/FindQrcode.cmake @@ -0,0 +1,37 @@ +# - Find Qrcode +# This module defines +# QRCODE_INCLUDE_DIR, where to find libqrencode headers +# QRCODE_LIB, libqrencode libraries +# QRCODE_FOUND, If false, do not try to use libqrencode + +set(QRCODE_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") +foreach(prefix ${ZMQ_EXTRA_PREFIXES}) + list(APPEND QRCODE_INCLUDE_PATHS "${prefix}/include") + list(APPEND QRCODE_LIB_PATHS "${prefix}/lib") +endforeach() + +find_path(QRCODE_INCLUDE_DIR qrencode.h PATHS ${QRCODE_INCLUDE_PATHS}) +find_library(QRCODE_LIB NAMES qrencode PATHS ${QRCODE_LIB_PATHS}) + +if (QRCODE_LIB AND QRCODE_INCLUDE_DIR) + set(QRCODE_FOUND TRUE) +else () + set(QRCODE_FOUND FALSE) +endif () + +if (QRCODE_FOUND) + if (NOT QRCODE_FIND_QUIETLY) + message(STATUS "Found libqrencode: ${QRCODE_LIB}") + include_directories(${QRCODE_INCLUDE_DIR}) + endif () +else () + if (QRCODE_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find libqrencode.") + endif () + message(STATUS "libqrencode NOT found.") +endif () + +mark_as_advanced( + QRCODE_LIB + QRCODE_INCLUDE_DIR +) diff --git a/contrib/cmake/FindZMQ.cmake b/contrib/cmake/FindZMQ.cmake new file mode 100644 index 000000000000..84b02736da29 --- /dev/null +++ b/contrib/cmake/FindZMQ.cmake @@ -0,0 +1,37 @@ +# - Find ZeroMQ +# This module defines +# ZMQ_INCLUDE_DIR, where to find ZMQ headers +# ZMQ_LIB, ZMQ libraries +# ZMQ_FOUND, If false, do not try to use ZeroMQ + +set(ZMQ_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") +foreach(prefix ${ZMQ_EXTRA_PREFIXES}) + list(APPEND ZMQ_INCLUDE_PATHS "${prefix}/include") + list(APPEND ZMQ_LIB_PATHS "${prefix}/lib") +endforeach() + +find_path(ZMQ_INCLUDE_DIR zmq.h PATHS ${ZMQ_INCLUDE_PATHS}) +find_library(ZMQ_LIB NAMES zmq PATHS ${ZMQ_LIB_PATHS}) + +if (ZMQ_LIB AND ZMQ_INCLUDE_DIR) + set(ZMQ_FOUND TRUE) +else () + set(ZMQ_FOUND FALSE) +endif () + +if (ZMQ_FOUND) + if (NOT ZMQ_FIND_QUIETLY) + message(STATUS "Found ZeroMQ: ${ZMQ_LIB}") + include_directories(${ZMQ_INCLUDE_DIR}) + endif () +else () + if (ZMQ_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find ZeroMQ.") + endif () + message(STATUS "ZeroMQ NOT found.") +endif () + +mark_as_advanced( + ZMQ_LIB + ZMQ_INCLUDE_DIR +) diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py index 15b49bc2079a..149be2af7172 100755 --- a/contrib/devtools/check-doc.py +++ b/contrib/devtools/check-doc.py @@ -1,44 +1,47 @@ -#!/usr/bin/env python2 -# Copyright (c) 2015-2016 The Bitcoin Core developers +#!/usr/bin/env python3 +# Copyright (c) 2015-2018 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' This checks if all command line args are documented. Return value is 0 to indicate no error. + Author: @MarcoFalke ''' from subprocess import check_output import re +import sys FOLDER_GREP = 'src' FOLDER_TEST = 'src/test/' -CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/%s' % FOLDER_GREP -CMD_GREP_ARGS = r"egrep -r -I '(map(Multi)?Args(\.count\(|\[)|Get(Bool)?Arg\()\"\-[^\"]+?\"' %s | grep -v '%s'" % (CMD_ROOT_DIR, FOLDER_TEST) -CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_ROOT_DIR) +CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_GREP) +CMD_GREP_ARGS = r"egrep -r -I '(map(Multi)?Args(\.count\(|\[)|Get(Bool)?Arg\()\"\-[^\"]+?\"' {} | grep -v '{}'".format(CMD_ROOT_DIR, FOLDER_TEST) +CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' {}".format(CMD_ROOT_DIR) REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"') REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")') # list unsupported, deprecated and duplicate args as they need no documentation SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions', '-checklevel', '-liquidityprovider', '-anonymizephoreamount']) def main(): - used = check_output(CMD_GREP_ARGS, shell=True) - docd = check_output(CMD_GREP_DOCS, shell=True) - - args_used = set(re.findall(REGEX_ARG,used)) - args_docd = set(re.findall(REGEX_DOC,docd)).union(SET_DOC_OPTIONAL) - args_need_doc = args_used.difference(args_docd) - args_unknown = args_docd.difference(args_used) - - print "Args used : %s" % len(args_used) - print "Args documented : %s" % len(args_docd) - print "Args undocumented: %s" % len(args_need_doc) - print args_need_doc - print "Args unknown : %s" % len(args_unknown) - print args_unknown - - exit(len(args_need_doc)) + used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True) + docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True) + + args_used = set(re.findall(re.compile(REGEX_ARG), used)) + args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL) + args_need_doc = args_used.difference(args_docd) + args_unknown = args_docd.difference(args_used) + + print("Args used : {}".format(len(args_used))) + print("Args documented : {}".format(len(args_docd))) + print("Args undocumented: {}".format(len(args_need_doc))) + print(args_need_doc) + print("Args unknown : {}".format(len(args_unknown))) + print(args_unknown) + + sys.exit(len(args_need_doc)) + if __name__ == "__main__": main() diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh new file mode 100755 index 000000000000..85e8b841b6b5 --- /dev/null +++ b/contrib/devtools/git-subtree-check.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C +DIR="$1" +COMMIT="$2" +if [ -z "$COMMIT" ]; then + COMMIT=HEAD +fi + +# Taken from git-subtree (Copyright (C) 2009 Avery Pennarun ) +find_latest_squash() +{ + dir="$1" + sq= + main= + sub= + git log --grep="^git-subtree-dir: $dir/*\$" \ + --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$COMMIT" | + while read a b _; do + case "$a" in + START) sq="$b" ;; + git-subtree-mainline:) main="$b" ;; + git-subtree-split:) sub="$b" ;; + END) + if [ -n "$sub" ]; then + if [ -n "$main" ]; then + # a rejoin commit? + # Pretend its sub was a squash. + sq="$sub" + fi + echo "$sq" "$sub" + break + fi + sq= + main= + sub= + ;; + esac + done +} + +# find latest subtree update +latest_squash="$(find_latest_squash "$DIR")" +if [ -z "$latest_squash" ]; then + echo "ERROR: $DIR is not a subtree" >&2 + exit 2 +fi +set $latest_squash +old=$1 +rev=$2 + +# get the tree in the current commit +tree_actual=$(git ls-tree -d "$COMMIT" "$DIR" | head -n 1) +if [ -z "$tree_actual" ]; then + echo "FAIL: subtree directory $DIR not found in $COMMIT" >&2 + exit 1 +fi +set $tree_actual +tree_actual_type=$2 +tree_actual_tree=$3 +echo "$DIR in $COMMIT currently refers to $tree_actual_type $tree_actual_tree" +if [ "d$tree_actual_type" != "dtree" ]; then + echo "FAIL: subtree directory $DIR is not a tree in $COMMIT" >&2 + exit 1 +fi + +# get the tree at the time of the last subtree update +tree_commit=$(git show -s --format="%T" $old) +echo "$DIR in $COMMIT was last updated in commit $old (tree $tree_commit)" + +# ... and compare the actual tree with it +if [ "$tree_actual_tree" != "$tree_commit" ]; then + git diff $tree_commit $tree_actual_tree >&2 + echo "FAIL: subtree directory was touched without subtree merge" >&2 + exit 1 +fi + +# get the tree in the subtree commit referred to +if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then + echo "subtree commit $rev unavailable: cannot compare" >&2 + exit +fi +tree_subtree=$(git show -s --format="%T" $rev) +echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)" + +# ... and compare the actual tree with it +if [ "$tree_actual_tree" != "$tree_subtree" ]; then + echo "FAIL: subtree update commit differs from upstream tree!" >&2 + exit 1 +fi + +echo "GOOD" diff --git a/contrib/devtools/lint-whitespace.sh b/contrib/devtools/lint-whitespace.sh new file mode 100755 index 000000000000..128aa10da5ef --- /dev/null +++ b/contrib/devtools/lint-whitespace.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Check for new lines in diff that introduce trailing whitespace. + +# We can't run this check unless we know the commit range for the PR. + +export LC_ALL=C +while getopts "?" opt; do + case $opt in + ?) + echo "Usage: .lint-whitespace.sh [N]" + echo " TRAVIS_COMMIT_RANGE='' .lint-whitespace.sh" + echo " .lint-whitespace.sh -?" + echo "Checks unstaged changes, the previous N commits, or a commit range." + echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' .lint-whitespace.sh" + exit 0 + ;; + esac +done + +if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then + if [ "$1" ]; then + TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD" + else + TRAVIS_COMMIT_RANGE="HEAD" + fi +fi + +showdiff() { + if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then + echo "Failed to get a diff" + exit 1 + fi +} + +showcodediff() { + if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then + echo "Failed to get a diff" + exit 1 + fi +} + +RET=0 + +# Check if trailing whitespace was found in the diff. +if showdiff | grep -E -q '^\+.*\s+$'; then + echo "This diff appears to have added new lines with trailing whitespace." + echo "The following changes were suspected:" + FILENAME="" + SEEN=0 + SEENLN=0 + while read -r line; do + if [[ "$line" =~ ^diff ]]; then + FILENAME="$line" + SEEN=0 + elif [[ "$line" =~ ^@@ ]]; then + LINENUMBER="$line" + SEENLN=0 + else + if [ "$SEEN" -eq 0 ]; then + # The first time a file is seen with trailing whitespace, we print the + # filename (preceded by a newline). + echo + echo "$FILENAME" + SEEN=1 + fi + if [ "$SEENLN" -eq 0 ]; then + echo "$LINENUMBER" + SEENLN=1 + fi + echo "$line" + fi + done < <(showdiff | grep -E '^(diff --git |@@|\+.*\s+$)') + RET=1 +fi + +# Check if tab characters were found in the diff. +if showcodediff | perl -nle '$MATCH++ if m{^\+.*\t}; END{exit 1 unless $MATCH>0}' > /dev/null; then + echo "This diff appears to have added new lines with tab characters instead of spaces." + echo "The following changes were suspected:" + FILENAME="" + SEEN=0 + SEENLN=0 + while read -r line; do + if [[ "$line" =~ ^diff ]]; then + FILENAME="$line" + SEEN=0 + elif [[ "$line" =~ ^@@ ]]; then + LINENUMBER="$line" + SEENLN=0 + else + if [ "$SEEN" -eq 0 ]; then + # The first time a file is seen with a tab character, we print the + # filename (preceded by a newline). + echo + echo "$FILENAME" + SEEN=1 + fi + if [ "$SEENLN" -eq 0 ]; then + echo "$LINENUMBER" + SEENLN=1 + fi + echo "$line" + fi + done < <(showcodediff | perl -nle 'print if m{^(diff --git |@@|\+.*\t)}') + RET=1 +fi + +exit $RET diff --git a/contrib/devtools/logprint-scanner.py b/contrib/devtools/logprint-scanner.py index 74c36e758ed1..2fd654b63bda 100755 --- a/contrib/devtools/logprint-scanner.py +++ b/contrib/devtools/logprint-scanner.py @@ -1,4 +1,7 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + import os, sys from subprocess import check_output @@ -23,14 +26,14 @@ def countRelevantCommas(line): return numRelevantCommas if __name__ == "__main__": - out = check_output(["git", "rev-parse", "--show-toplevel"]) + out = check_output("git rev-parse --show-toplevel", shell=True, universal_newlines=True) srcDir = out.rstrip() + "/src/" filelist = [os.path.join(dp, f) for dp, dn, filenames in os.walk(srcDir) for f in filenames if os.path.splitext(f)[1] == '.cpp' or os.path.splitext(f)[1] == '.h' ] incorrectInstanceCounter = 0 for file in filelist: - f = open(file,"r") + f = open(file,"r", encoding="utf-8") data = f.read() rows = data.split("\n") count = 0 @@ -73,11 +76,11 @@ def countRelevantCommas(line): numPercents = tempLine.count('%') - numExtraPercents - 2*tempLine.count('%%') if numPercents != numCommas: - print "Incorrect number of arguments for LogPrint(f) statement found." + print("Incorrect number of arguments for LogPrint(f) statement found.") print(str(file) + ":" + str(lineCounter - tempCount)) - print "Line = " + tempLine + print("Line = " + tempLine) print("numRelevantCommas = " + str(numCommas) + ", numRelevantPercents = " + str(numPercents)) - print "" + print("") incorrectInstanceCounter += 1 diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py new file mode 100755 index 000000000000..391984a8f275 --- /dev/null +++ b/contrib/devtools/security-check.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' +Perform basic ELF security checks on a series of executables. +Exit status will be 0 if successful, and the program will be silent. +Otherwise the exit status will be 1 and it will log which executables failed which checks. +Needs `readelf` (for ELF) and `objdump` (for PE). +''' +import subprocess +import sys +import os + +READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') +OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') +NONFATAL = {} # checks which are non-fatal for now but only generate a warning + +def check_ELF_PIE(executable): + ''' + Check for position independent executable (PIE), allowing for address space randomization. + ''' + p = subprocess.Popen([READELF_CMD, '-h', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + + ok = False + for line in stdout.splitlines(): + line = line.split() + if len(line)>=2 and line[0] == 'Type:' and line[1] == 'DYN': + ok = True + return ok + +def get_ELF_program_headers(executable): + '''Return type and flags for ELF program headers''' + p = subprocess.Popen([READELF_CMD, '-l', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + in_headers = False + count = 0 + headers = [] + for line in stdout.splitlines(): + if line.startswith('Program Headers:'): + in_headers = True + if line == '': + in_headers = False + if in_headers: + if count == 1: # header line + ofs_typ = line.find('Type') + ofs_offset = line.find('Offset') + ofs_flags = line.find('Flg') + ofs_align = line.find('Align') + if ofs_typ == -1 or ofs_offset == -1 or ofs_flags == -1 or ofs_align == -1: + raise ValueError('Cannot parse elfread -lW output') + elif count > 1: + typ = line[ofs_typ:ofs_offset].rstrip() + flags = line[ofs_flags:ofs_align].rstrip() + headers.append((typ, flags)) + count += 1 + return headers + +def check_ELF_NX(executable): + ''' + Check that no sections are writable and executable (including the stack) + ''' + have_wx = False + have_gnu_stack = False + for (typ, flags) in get_ELF_program_headers(executable): + if typ == 'GNU_STACK': + have_gnu_stack = True + if 'W' in flags and 'E' in flags: # section is both writable and executable + have_wx = True + return have_gnu_stack and not have_wx + +def check_ELF_RELRO(executable): + ''' + Check for read-only relocations. + GNU_RELRO program header must exist + Dynamic section must have BIND_NOW flag + ''' + have_gnu_relro = False + for (typ, flags) in get_ELF_program_headers(executable): + # Note: not checking flags == 'R': here as linkers set the permission differently + # This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions. + # However, the dynamic linker need to write to this area so these are RW. + # Glibc itself takes care of mprotecting this area R after relocations are finished. + # See also http://permalink.gmane.org/gmane.comp.gnu.binutils/71347 + if typ == 'GNU_RELRO': + have_gnu_relro = True + + have_bindnow = False + p = subprocess.Popen([READELF_CMD, '-d', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + for line in stdout.splitlines(): + tokens = line.split() + if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2:]): + have_bindnow = True + return have_gnu_relro and have_bindnow + +def check_ELF_Canary(executable): + ''' + Check for use of stack canary + ''' + p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + ok = False + for line in stdout.splitlines(): + if '__stack_chk_fail' in line: + ok = True + return ok + +def get_PE_dll_characteristics(executable): + ''' + Get PE DllCharacteristics bits. + Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386' + and bits is the DllCharacteristics value. + ''' + p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + arch = '' + bits = 0 + for line in stdout.splitlines(): + tokens = line.split() + if len(tokens)>=2 and tokens[0] == 'architecture:': + arch = tokens[1].rstrip(',') + if len(tokens)>=2 and tokens[0] == 'DllCharacteristics': + bits = int(tokens[1],16) + return (arch,bits) + +IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 +IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040 +IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100 + +def check_PE_DYNAMIC_BASE(executable): + '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)''' + (arch,bits) = get_PE_dll_characteristics(executable) + reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE + return (bits & reqbits) == reqbits + +# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE +# to have secure ASLR. +def check_PE_HIGH_ENTROPY_VA(executable): + '''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR''' + (arch,bits) = get_PE_dll_characteristics(executable) + if arch == 'i386:x86-64': + reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA + else: # Unnecessary on 32-bit + assert(arch == 'i386') + reqbits = 0 + return (bits & reqbits) == reqbits + +def check_PE_NX(executable): + '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)''' + (arch,bits) = get_PE_dll_characteristics(executable) + return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT + +CHECKS = { +'ELF': [ + ('PIE', check_ELF_PIE), + ('NX', check_ELF_NX), + ('RELRO', check_ELF_RELRO), + ('Canary', check_ELF_Canary) +], +'PE': [ + ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE), + ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), + ('NX', check_PE_NX) +] +} + +def identify_executable(executable): + with open(filename, 'rb') as f: + magic = f.read(4) + if magic.startswith(b'MZ'): + return 'PE' + elif magic.startswith(b'\x7fELF'): + return 'ELF' + return None + +if __name__ == '__main__': + retval = 0 + for filename in sys.argv[1:]: + try: + etype = identify_executable(filename) + if etype is None: + print('%s: unknown format' % filename) + retval = 1 + continue + + failed = [] + warning = [] + for (name, func) in CHECKS[etype]: + if not func(filename): + if name in NONFATAL: + warning.append(name) + else: + failed.append(name) + if failed: + print('%s: failed %s' % (filename, ' '.join(failed))) + retval = 1 + if warning: + print('%s: warning %s' % (filename, ' '.join(warning))) + except IOError: + print('%s: cannot open' % filename) + retval = 1 + sys.exit(retval) + diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index ea8bcb560891..c6158c94225a 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,7 +11,6 @@ find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py ''' -from __future__ import division, print_function, unicode_literals import subprocess import re import sys @@ -37,40 +36,51 @@ # (glibc) GLIBC_2_11 # MAX_VERSIONS = { -'GCC': (4,4,0), -'CXXABI': (1,3,3), -'GLIBCXX': (3,4,13), -'GLIBC': (2,11) +'GCC': (4,4,0), +'CXXABI': (1,3,3), +'GLIBCXX': (3,4,13), +'GLIBC': (2,11), +'LIBATOMIC': (1,0) } # See here for a description of _IO_stdin_used: # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109 # Ignore symbols that are exported as part of every executable IGNORE_EXPORTS = { -b'_edata', b'_end', b'_init', b'__bss_start', b'_fini', b'_IO_stdin_used' +'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr' } READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') # Allowed NEEDED libraries ALLOWED_LIBRARIES = { # bitcoind and bitcoin-qt -b'libgcc_s.so.1', # GCC base support -b'libc.so.6', # C library -b'libpthread.so.0', # threading -b'libanl.so.1', # DNS resolve -b'libm.so.6', # math library -b'librt.so.1', # real-time (clock) -b'ld-linux-x86-64.so.2', # 64-bit dynamic linker -b'ld-linux.so.2', # 32-bit dynamic linker +'libgcc_s.so.1', # GCC base support +'libc.so.6', # C library +'libpthread.so.0', # threading +'libanl.so.1', # DNS resolve +'libm.so.6', # math library +'librt.so.1', # real-time (clock) +'libatomic.so.1', +'ld-linux-x86-64.so.2', # 64-bit dynamic linker +'ld-linux.so.2', # 32-bit dynamic linker +'ld-linux-aarch64.so.1', # 64-bit ARM dynamic linker +'ld-linux-armhf.so.3', # 32-bit ARM dynamic linker +'ld-linux-riscv64-lp64d.so.1', # 64-bit RISC-V dynamic linker # bitcoin-qt only -b'libX11-xcb.so.1', # part of X11 -b'libX11.so.6', # part of X11 -b'libxcb.so.1', # part of X11 -b'libfontconfig.so.1', # font support -b'libfreetype.so.6', # font parsing -b'libdl.so.2' # programming interface to dynamic linker +'libX11-xcb.so.1', # part of X11 +'libX11.so.6', # part of X11 +'libxcb.so.1', # part of X11 +'libfontconfig.so.1', # font support +'libfreetype.so.6', # font parsing +'libdl.so.2' # programming interface to dynamic linker +} +ARCH_MIN_GLIBC_VER = { +'80386': (2,1), +'X86-64': (2,2,5), +'ARM': (2,4), +'AArch64':(2,17), +'RISC-V': (2,27) } - class CPPFilt(object): ''' Demangle C++ symbol names. @@ -78,10 +88,10 @@ class CPPFilt(object): Use a pipe to the 'c++filt' command. ''' def __init__(self): - self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) def __call__(self, mangled): - self.proc.stdin.write(mangled + b'\n') + self.proc.stdin.write(mangled + '\n') self.proc.stdin.flush() return self.proc.stdout.readline().rstrip() @@ -95,43 +105,45 @@ def read_symbols(executable, imports=True): Parse an ELF executable and return a list of (symbol,version) tuples for dynamic, imported symbols. ''' - p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', '-h', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) (stdout, stderr) = p.communicate() if p.returncode: raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip())) syms = [] - for line in stdout.split(b'\n'): + for line in stdout.splitlines(): line = line.split() - if len(line)>7 and re.match(b'[0-9]+:$', line[0]): - (sym, _, version) = line[7].partition(b'@') - is_import = line[6] == b'UND' - if version.startswith(b'@'): + if 'Machine:' in line: + arch = line[-1] + if len(line)>7 and re.match('[0-9]+:$', line[0]): + (sym, _, version) = line[7].partition('@') + is_import = line[6] == 'UND' + if version.startswith('@'): version = version[1:] if is_import == imports: - syms.append((sym, version)) + syms.append((sym, version, arch)) return syms -def check_version(max_versions, version): - if b'_' in version: - (lib, _, ver) = version.rpartition(b'_') +def check_version(max_versions, version, arch): + if '_' in version: + (lib, _, ver) = version.rpartition('_') else: lib = version ver = '0' - ver = tuple([int(x) for x in ver.split(b'.')]) + ver = tuple([int(x) for x in ver.split('.')]) if not lib in max_versions: return False - return ver <= max_versions[lib] + return ver <= max_versions[lib] or lib == 'GLIBC' and ver <= ARCH_MIN_GLIBC_VER[arch] def read_libraries(filename): - p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) (stdout, stderr) = p.communicate() if p.returncode: raise IOError('Error opening file') libraries = [] - for line in stdout.split(b'\n'): + for line in stdout.splitlines(): tokens = line.split() - if len(tokens)>2 and tokens[1] == b'(NEEDED)': - match = re.match(b'^Shared library: \[(.*)\]$', b' '.join(tokens[2:])) + if len(tokens)>2 and tokens[1] == '(NEEDED)': + match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:])) if match: libraries.append(match.group(1)) else: @@ -143,20 +155,23 @@ def read_libraries(filename): retval = 0 for filename in sys.argv[1:]: # Check imported symbols - for sym,version in read_symbols(filename, True): - if version and not check_version(MAX_VERSIONS, version): - print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym).decode('utf-8'), version.decode('utf-8'))) + for sym,version,arch in read_symbols(filename, True): + if version and not check_version(MAX_VERSIONS, version, arch): + print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version)) retval = 1 # Check exported symbols - for sym,version in read_symbols(filename, False): - if sym in IGNORE_EXPORTS: - continue - print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym).decode('utf-8'))) - retval = 1 + if arch != 'RISC-V': + for sym,version,arch in read_symbols(filename, False): + if sym in IGNORE_EXPORTS: + continue + print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym))) + retval = 1 # Check dependency libraries for library_name in read_libraries(filename): if library_name not in ALLOWED_LIBRARIES: - print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8'))) + print('%s: NEEDED library %s is not allowed' % (filename, library_name)) retval = 1 - exit(retval) + sys.exit(retval) + + diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py new file mode 100755 index 000000000000..9b6d6bf6658b --- /dev/null +++ b/contrib/devtools/test-security-check.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' +Test script for security-check.py +''' +import subprocess +import unittest + +def write_testcode(filename): + with open(filename, 'w', encoding="utf8") as f: + f.write(''' + #include + int main() + { + printf("the quick brown fox jumps over the lazy god\\n"); + return 0; + } + ''') + +def call_security_check(cc, source, executable, options): + subprocess.check_call([cc,source,'-o',executable] + options) + p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + return (p.returncode, stdout.rstrip()) + +class TestSecurityChecks(unittest.TestCase): + def test_ELF(self): + source = 'test1.c' + executable = 'test1' + cc = 'gcc' + write_testcode(source) + + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']), + (1, executable+': failed PIE NX RELRO Canary')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']), + (1, executable+': failed PIE RELRO Canary')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']), + (1, executable+': failed PIE RELRO')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']), + (1, executable+': failed RELRO')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']), + (0, '')) + + def test_32bit_PE(self): + source = 'test1.c' + executable = 'test1.exe' + cc = 'i686-w64-mingw32-gcc' + write_testcode(source) + + self.assertEqual(call_security_check(cc, source, executable, []), + (1, executable+': failed DYNAMIC_BASE NX')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']), + (1, executable+': failed DYNAMIC_BASE')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), + (0, '')) + def test_64bit_PE(self): + source = 'test1.c' + executable = 'test1.exe' + cc = 'x86_64-w64-mingw32-gcc' + write_testcode(source) + + self.assertEqual(call_security_check(cc, source, executable, []), (1, executable+': failed DYNAMIC_BASE NX\n'+executable+': warning HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']), (1, executable+': failed DYNAMIC_BASE\n'+executable+': warning HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), (0, executable+': warning HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va']), (0, '')) + +if __name__ == '__main__': + unittest.main() + diff --git a/contrib/filter-lcov.py b/contrib/filter-lcov.py new file mode 100755 index 000000000000..df1db76e924e --- /dev/null +++ b/contrib/filter-lcov.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import argparse + +parser = argparse.ArgumentParser(description='Remove the coverage data from a tracefile for all files matching the pattern.') +parser.add_argument('--pattern', '-p', action='append', help='the pattern of files to remove', required=True) +parser.add_argument('tracefile', help='the tracefile to remove the coverage data from') +parser.add_argument('outfile', help='filename for the output to be written to') + +args = parser.parse_args() +tracefile = args.tracefile +pattern = args.pattern +outfile = args.outfile + +in_remove = False +with open(tracefile, 'r', encoding="utf8") as f: + with open(outfile, 'w', encoding="utf8") as wf: + for line in f: + for p in pattern: + if line.startswith("SF:") and p in line: + in_remove = True + if not in_remove: + wf.write(line) + if line == 'end_of_record\n': + in_remove = False diff --git a/contrib/gitian-descriptors/gitian-aarch64.yml b/contrib/gitian-descriptors/gitian-aarch64.yml index 23f3b43fc02a..b52991fb8f1a 100644 --- a/contrib/gitian-descriptors/gitian-aarch64.yml +++ b/contrib/gitian-descriptors/gitian-aarch64.yml @@ -23,7 +23,6 @@ packages: - "bsdmainutils" - "ca-certificates" - "python" -reference_datetime: "2015-06-01 00:00:00" remotes: - "url": "https://github.com/phoreproject/phore.git" "dir": "phore" @@ -40,6 +39,7 @@ script: | HOST_LDFLAGS=-static-libstdc++ export QT_RCC_TEST=1 + export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" @@ -53,7 +53,7 @@ script: | function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} @@ -65,7 +65,7 @@ script: | function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} @@ -95,7 +95,7 @@ script: | for prog in gcc g++; do rm -f ${WRAP_DIR}/${prog} cat << EOF > ${WRAP_DIR}/${prog} - #!/bin/bash + #!/usr/bin/env bash REAL="`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1`" for var in "\$@" do @@ -167,5 +167,4 @@ script: | rm -rf distsrc-${i} done mkdir -p $OUTDIR/src - mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 7bda15a6a975..79246db46f50 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,24 +1,29 @@ --- name: "phore-linux-1.6" enable_cache: true +distro: "ubuntu" suites: -- "trusty" +- "bionic" architectures: - "amd64" packages: - "curl" - "g++-aarch64-linux-gnu" -- "g++-4.8-aarch64-linux-gnu" -- "gcc-4.8-aarch64-linux-gnu" +- "g++-8-aarch64-linux-gnu" +- "gcc-8-aarch64-linux-gnu" - "binutils-aarch64-linux-gnu" - "g++-arm-linux-gnueabihf" -- "g++-4.8-arm-linux-gnueabihf" -- "gcc-4.8-arm-linux-gnueabihf" +- "g++-8-arm-linux-gnueabihf" +- "gcc-8-arm-linux-gnueabihf" - "binutils-arm-linux-gnueabihf" -- "g++-4.8-multilib" -- "gcc-4.8-multilib" +- "g++-riscv64-linux-gnu" +- "g++-8-riscv64-linux-gnu" +- "gcc-8-riscv64-linux-gnu" +- "binutils-riscv64-linux-gnu" +- "g++-8-multilib" +- "gcc-8-multilib" - "binutils-gold" -- "git-core" +- "git" - "pkg-config" - "autoconf" - "libtool" @@ -26,24 +31,25 @@ packages: - "faketime" - "bsdmainutils" - "ca-certificates" -- "python" -reference_datetime: "2015-06-01 00:00:00" +- "python3" remotes: - "url": "https://github.com/phoreproject/phore.git" "dir": "phore" files: [] script: | + set -e -o pipefail WRAP_DIR=$HOME/wrapped - HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf" + HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu" CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests" - FAKETIME_HOST_PROGS="" + FAKETIME_HOST_PROGS="gcc g++" FAKETIME_PROGS="date ar ranlib nm" HOST_CFLAGS="-O2 -g" HOST_CXXFLAGS="-O2 -g" HOST_LDFLAGS=-static-libstdc++ export QT_RCC_TEST=1 + export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" @@ -57,7 +63,7 @@ script: | function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} @@ -69,12 +75,15 @@ script: | function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} - echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} - echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} - echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} - chmod +x ${WRAP_DIR}/${i}-${prog} + if which ${i}-${prog}-8 + then + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} + echo "REAL=\`which -a ${i}-${prog}-8 | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} + chmod +x ${WRAP_DIR}/${i}-${prog} + fi done done } @@ -99,8 +108,8 @@ script: | for prog in gcc g++; do rm -f ${WRAP_DIR}/${prog} cat << EOF > ${WRAP_DIR}/${prog} - #!/bin/bash - REAL="`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1`" + #!/usr/bin/env bash + REAL="`which -a ${prog}-8 | grep -v ${WRAP_DIR}/${prog} | head -1`" for var in "\$@" do if [ "\$var" = "-m32" ]; then @@ -145,6 +154,9 @@ script: | find phore-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do @@ -155,21 +167,27 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" make ${MAKEOPTS} - + make ${MAKEOPTS} -C src check-security + make ${MAKEOPTS} -C src check-symbols make install DESTDIR=${INSTALLPATH} cd installed find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig - find ${DISTNAME}/bin -type f -executable -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; - # find ${DISTNAME}/lib -type f -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; + find ${DISTNAME}/bin -type f -executable -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg + #find ${DISTNAME}/lib -type f -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg + cp ../doc/README.md ${DISTNAME}/ find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz cd ../../ rm -rf distsrc-${i} done mkdir -p $OUTDIR/src - mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index a886bca27af3..53654648b92a 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -1,7 +1,8 @@ --- name: "phore-dmg-signer" +distro: "ubuntu" suites: -- "trusty" +- "bionic" architectures: - "amd64" packages: @@ -12,6 +13,8 @@ remotes: files: - "phore-osx-unsigned.tar.gz" script: | + set -e -o pipefail + WRAP_DIR=$HOME/wrapped mkdir -p ${WRAP_DIR} export PATH=`pwd`:$PATH @@ -19,7 +22,7 @@ script: | # Create global faketime wrappers for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} @@ -33,5 +36,7 @@ script: | tar -xf ${UNSIGNED} OSX_VOLNAME="$(cat osx_volname)" ./detached-sig-apply.sh ${UNSIGNED} signature/osx - ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "Phore-Qt" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app + + ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "${OSX_VOLNAME}" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app + ${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 0a6b71c4cf5b..212cfcbe90f1 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,15 +1,16 @@ --- name: "phore-osx-1.6" enable_cache: true +distro: "ubuntu" suites: -- "trusty" +- "bionic" architectures: - "amd64" packages: - "ca-certificates" - "curl" - "g++" -- "git-core" +- "git" - "pkg-config" - "autoconf" - "librsvg2-bin" @@ -23,9 +24,9 @@ packages: - "libcap-dev" - "libz-dev" - "libbz2-dev" -- "python" -- "python-dev" -- "python-setuptools" +- "python3" +- "python3-dev" +- "python3-setuptools" - "fonts-tuffy" remotes: - "url": "https://github.com/phoreproject/phore.git" @@ -33,13 +34,16 @@ remotes: files: - "MacOSX10.11.sdk.tar.gz" script: | + set -e -o pipefail + WRAP_DIR=$HOME/wrapped - HOSTS="x86_64-apple-darwin11" + HOSTS="x86_64-apple-darwin14" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date dmg genisoimage" export QT_RCC_TEST=1 + export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" @@ -55,7 +59,7 @@ script: | function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} @@ -67,7 +71,7 @@ script: | function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} @@ -114,6 +118,9 @@ script: | find phore-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do @@ -124,6 +131,11 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} make install-strip DESTDIR=${INSTALLPATH} diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 28d4c026c8d2..14783fb064c8 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -1,11 +1,13 @@ --- name: "phore-win-signer" +distro: "ubuntu" suites: -- "trusty" +- "bionic" architectures: - "amd64" packages: -- "libssl-dev" +# Once osslsigncode supports openssl 1.1, we can change this back to libssl-dev +- "libssl1.0-dev" - "autoconf" remotes: - "url": "https://github.com/phoreproject/phore-detached-sigs.git" @@ -15,6 +17,8 @@ files: - "osslsigncode-Backports-to-1.7.1.patch" - "phore-win-unsigned.tar.gz" script: | + set -e -o pipefail + BUILD_DIR=`pwd` SIGDIR=${BUILD_DIR}/signature/win UNSIGNED_DIR=${BUILD_DIR}/unsigned diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index f658eebc2875..b05369f66e67 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,14 +1,15 @@ --- name: "phore-win-1.6" enable_cache: true +distro: "ubuntu" suites: -- "trusty" +- "bionic" architectures: - "amd64" packages: - "curl" - "g++" -- "git-core" +- "git" - "pkg-config" - "autoconf" - "libtool" @@ -20,21 +21,25 @@ packages: - "nsis" - "zip" - "ca-certificates" -- "python" +- "python3" +- "rename" remotes: - "url": "https://github.com/phoreproject/phore.git" "dir": "phore" files: [] script: | + set -e -o pipefail + WRAP_DIR=$HOME/wrapped HOSTS="i686-w64-mingw32 x86_64-w64-mingw32" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests" - FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip objcopy" + FAKETIME_HOST_PROGS="ar ranlib nm windres strip objcopy" FAKETIME_PROGS="date makensis zip" HOST_CFLAGS="-O2 -g" HOST_CXXFLAGS="-O2 -g" export QT_RCC_TEST=1 + export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" @@ -48,7 +53,7 @@ script: | function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} @@ -60,7 +65,7 @@ script: | function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} @@ -76,15 +81,15 @@ script: | for i in $HOSTS; do mkdir -p ${WRAP_DIR}/${i} for prog in collect2; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}/${prog} REAL=$(${i}-gcc -print-prog-name=${prog}) echo "export MALLOC_PERTURB_=255" >> ${WRAP_DIR}/${i}/${prog} echo "${REAL} \$@" >> $WRAP_DIR/${i}/${prog} chmod +x ${WRAP_DIR}/${i}/${prog} done for prog in gcc g++; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} - echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} + echo "REAL=\`which -a ${i}-${prog}-posix | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog} @@ -131,6 +136,9 @@ script: | cp ../$SOURCEDIST $OUTDIR/src popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do @@ -141,10 +149,17 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" make ${MAKEOPTS} + make ${MAKEOPTS} -C src check-security make deploy make install DESTDIR=${INSTALLPATH} + rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe cp -f phore-*setup*.exe $OUTDIR/ cd installed # mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ # temporarily disabled for Zerocoin @@ -158,9 +173,11 @@ script: | cd ../../ rm -rf distsrc-${i} done - cd $OUTDIR - rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe - find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz + cp -rf contrib/windeploy $BUILD_DIR + cd $BUILD_DIR/windeploy + mkdir unsigned + cp $OUTDIR/phore-*setup-unsigned.exe unsigned/ + find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip diff --git a/contrib/init/org.phore.phored.plist b/contrib/init/org.phore.phored.plist new file mode 100644 index 000000000000..781bb71ec9cc --- /dev/null +++ b/contrib/init/org.phore.phored.plist @@ -0,0 +1,14 @@ + + + + + Label + org.phore.phored + ProgramArguments + + /usr/local/bin/phored + + RunAtLoad + + + diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh new file mode 100755 index 000000000000..cb70eec13f31 --- /dev/null +++ b/contrib/install_db4.sh @@ -0,0 +1,87 @@ +#!/bin/sh + +# Install libdb4.8 (Berkeley DB). + +export LC_ALL=C +set -e + +if [ -z "${1}" ]; then + echo "Usage: ./install_db4.sh [ ...]" + echo + echo "Must specify a single argument: the directory in which db4 will be built." + echo "This is probably \`pwd\` if you're at the root of the phore repository." + exit 1 +fi + +expand_path() { + echo "$(cd "${1}" && pwd -P)" +} + +BDB_PREFIX="$(expand_path ${1})/db4"; shift; +BDB_VERSION='db-4.8.30.NC' +BDB_HASH='12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef' +BDB_URL="https://download.oracle.com/berkeley-db/${BDB_VERSION}.tar.gz" + +check_exists() { + which "$1" >/dev/null 2>&1 +} + +sha256_check() { + # Args: + # + if check_exists sha256sum; then + echo "${1} ${2}" | sha256sum -c + elif check_exists sha256; then + if [ "$(uname)" = "FreeBSD" ]; then + sha256 -c "${1}" "${2}" + else + echo "${1} ${2}" | sha256 -c + fi + else + echo "${1} ${2}" | shasum -a 256 -c + fi +} + +http_get() { + # Args: + # + # It's acceptable that we don't require SSL here because we manually verify + # content hashes below. + # + if [ -f "${2}" ]; then + echo "File ${2} already exists; not downloading again" + elif check_exists curl; then + curl --insecure "${1}" -o "${2}" + else + wget --no-check-certificate "${1}" -O "${2}" + fi + + sha256_check "${3}" "${2}" +} + +mkdir -p "${BDB_PREFIX}" +http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}" +tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX" +cd "${BDB_PREFIX}/${BDB_VERSION}/" + +# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592) +CLANG_CXX11_PATCH_URL='https://gist.githubusercontent.com/LnL7/5153b251fd525fe15de69b67e63a6075/raw/7778e9364679093a32dec2908656738e16b6bdcb/clang.patch' +CLANG_CXX11_PATCH_HASH='7a9a47b03fd5fb93a16ef42235fa9512db9b0829cfc3bdf90edd3ec1f44d637c' +http_get "${CLANG_CXX11_PATCH_URL}" clang.patch "${CLANG_CXX11_PATCH_HASH}" +patch -p2 < clang.patch + +cd build_unix/ + +"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \ + --enable-cxx --disable-shared --disable-replication --with-pic --prefix="${BDB_PREFIX}" \ + "${@}" + +make install + +echo +echo "db4 build complete." +echo +echo 'When compiling phored, run `./configure` in the following way:' +echo +echo " export BDB_PREFIX='${BDB_PREFIX}'" +echo ' ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ...' diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py index 8d44fdfff76e..1832a28a0d37 100644 --- a/contrib/macdeploy/custom_dsstore.py +++ b/contrib/macdeploy/custom_dsstore.py @@ -1,8 +1,7 @@ -#!/usr/bin/env python -# Copyright (c) 2013-2016 The Bitcoin Core developers +#!/usr/bin/env python3 +# Copyright (c) 2013-2017 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from __future__ import division,print_function,unicode_literals import biplist from ds_store import DSStore from mac_alias import Alias @@ -14,7 +13,7 @@ ds = DSStore.open(output_file, 'w+') ds['.']['bwsp'] = { 'ShowStatusBar': False, - 'WindowBounds': b'{{300, 280}, {500, 343}}', + 'WindowBounds': '{{300, 280}, {500, 343}}', 'ContainerShowSidebar': False, 'SidebarWidth': 0, 'ShowTabView': False, diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index a3dc38b7fad1..f8503e4de8c5 100644 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -1,11 +1,15 @@ #!/bin/sh +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C set -e -UNSIGNED=$1 -SIGNATURE=$2 +UNSIGNED="$1" +SIGNATURE="$2" ARCH=x86_64 ROOTDIR=dist -BUNDLE=${ROOTDIR}/Phore-Qt.app TEMPDIR=signed.temp OUTDIR=signed-app @@ -21,7 +25,7 @@ fi rm -rf ${TEMPDIR} && mkdir -p ${TEMPDIR} tar -C ${TEMPDIR} -xf ${UNSIGNED} -tar -C ${TEMPDIR} -xf ${SIGNATURE} +cp -rf "${SIGNATURE}"/* ${TEMPDIR} if [ -z "${PAGESTUFF}" ]; then PAGESTUFF=${TEMPDIR}/pagestuff @@ -31,21 +35,21 @@ if [ -z "${CODESIGN_ALLOCATE}" ]; then CODESIGN_ALLOCATE=${TEMPDIR}/codesign_allocate fi -for i in `find ${TEMPDIR} -name "*.sign"`; do - SIZE=`stat -c %s ${i}` - TARGET_FILE=`echo ${i} | sed 's/\.sign$//'` +find ${TEMPDIR} -name "*.sign" | while read i; do + SIZE=`stat -c %s "${i}"` + TARGET_FILE="`echo "${i}" | sed 's/\.sign$//'`" echo "Allocating space for the signature of size ${SIZE} in ${TARGET_FILE}" - ${CODESIGN_ALLOCATE} -i ${TARGET_FILE} -a ${ARCH} ${SIZE} -o ${i}.tmp + ${CODESIGN_ALLOCATE} -i "${TARGET_FILE}" -a ${ARCH} ${SIZE} -o "${i}.tmp" - OFFSET=`${PAGESTUFF} ${i}.tmp -p | tail -2 | grep offset | sed 's/[^0-9]*//g'` + OFFSET=`${PAGESTUFF} "${i}.tmp" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'` if [ -z ${QUIET} ]; then echo "Attaching signature at offset ${OFFSET}" fi - dd if=$i of=${i}.tmp bs=1 seek=${OFFSET} count=${SIZE} 2>/dev/null - mv ${i}.tmp ${TARGET_FILE} - rm ${i} + dd if="$i" of="${i}.tmp" bs=1 seek=${OFFSET} count=${SIZE} 2>/dev/null + mv "${i}.tmp" "${TARGET_FILE}" + rm "${i}" echo "Success." done mv ${TEMPDIR}/${ROOTDIR} ${OUTDIR} diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 46a16568adb1..c32b890a1812 100644 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -1,4 +1,9 @@ #!/bin/sh +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C set -e ROOTDIR=dist @@ -6,7 +11,8 @@ BUNDLE=${ROOTDIR}/Phore-Qt.app CODESIGN=codesign TEMPDIR=sign.temp TEMPLIST=${TEMPDIR}/signatures.txt -OUT=signature.tar.gz +OUT=signature-osx.tar.gz +OUTROOT=osx if [ ! -n "$1" ]; then echo "usage: $0 " @@ -19,28 +25,28 @@ mkdir -p ${TEMPDIR} ${CODESIGN} -f --file-list ${TEMPLIST} "$@" "${BUNDLE}" -for i in `grep -v CodeResources ${TEMPLIST}`; do - TARGETFILE="${BUNDLE}/`echo ${i} | sed "s|.*${BUNDLE}/||"`" - SIZE=`pagestuff $i -p | tail -2 | grep size | sed 's/[^0-9]*//g'` - OFFSET=`pagestuff $i -p | tail -2 | grep offset | sed 's/[^0-9]*//g'` - SIGNFILE="${TEMPDIR}/${TARGETFILE}.sign" - DIRNAME="`dirname ${SIGNFILE}`" +grep -v CodeResources < "${TEMPLIST}" | while read i; do + TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`" + SIZE=`pagestuff "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g'` + OFFSET=`pagestuff "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'` + SIGNFILE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign" + DIRNAME="`dirname "${SIGNFILE}"`" mkdir -p "${DIRNAME}" echo "Adding detached signature for: ${TARGETFILE}. Size: ${SIZE}. Offset: ${OFFSET}" - dd if=$i of=${SIGNFILE} bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null + dd if="$i" of="${SIGNFILE}" bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null done -for i in `grep CodeResources ${TEMPLIST}`; do - TARGETFILE="${BUNDLE}/`echo ${i} | sed "s|.*${BUNDLE}/||"`" - RESOURCE="${TEMPDIR}/${TARGETFILE}" +grep CodeResources < "${TEMPLIST}" | while read i; do + TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`" + RESOURCE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}" DIRNAME="`dirname "${RESOURCE}"`" mkdir -p "${DIRNAME}" - echo "Adding resource for: "${TARGETFILE}"" + echo "Adding resource for: \"${TARGETFILE}\"" cp "${i}" "${RESOURCE}" done rm ${TEMPLIST} -tar -C ${TEMPDIR} -czf ${OUT} . -rm -rf ${TEMPDIR} +tar -C "${TEMPDIR}" -czf "${OUT}" . +rm -rf "${TEMPDIR}" echo "Created ${OUT}" diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh index 1e4d1d413d35..4c175156f4e4 100755 --- a/contrib/macdeploy/extract-osx-sdk.sh +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -1,8 +1,9 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright (c) 2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +export LC_ALL=C set -e INPUTFILE="Xcode_7.3.1.dmg" @@ -31,4 +32,3 @@ echo "Building ${SDKNAME}.tar.gz ..." MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')" find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz" echo 'All done!' - diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 367afaef6b53..8ea7f3f8808d 100644 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -1,5 +1,4 @@ -#!/usr/bin/env python -from __future__ import division, print_function, unicode_literals +#!/usr/bin/env python3 # # Copyright (C) 2011 Patrick "p2k" Schneider # @@ -203,7 +202,7 @@ def getFrameworks(binaryPath, verbose): if verbose >= 3: print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") - otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) o_stdout, o_stderr = otool.communicate() if otool.returncode != 0: if verbose >= 1: @@ -211,7 +210,7 @@ def getFrameworks(binaryPath, verbose): sys.stderr.flush() raise RuntimeError("otool failed with return code %d" % otool.returncode) - otoolLines = o_stdout.decode().split("\n") + otoolLines = o_stdout.split("\n") otoolLines.pop(0) # First line is the inspected binary if ".framework" in binaryPath or binaryPath.endswith(".dylib"): otoolLines.pop(0) # Frameworks and dylibs list themselves as a dependency. @@ -714,22 +713,6 @@ elif config.sign: if config.dmg is not None: - #Patch in check_output for Python 2.6 - if "check_output" not in dir( subprocess ): - def f(*popenargs, **kwargs): - if 'stdout' in kwargs: - raise ValueError('stdout argument not allowed, it will be overridden.') - process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise CalledProcessError(retcode, cmd) - return output - subprocess.check_output = f - def runHDIUtil(verb, image_basename, **kwargs): hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] if "capture_stdout" in kwargs: @@ -747,7 +730,7 @@ if config.dmg is not None: if not value is True: hdiutil_args.append(str(value)) - return run(hdiutil_args) + return run(hdiutil_args, universal_newlines=True) if verbose >= 2: if fancy is None: @@ -789,7 +772,7 @@ if config.dmg is not None: except subprocess.CalledProcessError as e: sys.exit(e.returncode) - m = re.search("/Volumes/(.+$)", output.decode()) + m = re.search("/Volumes/(.+$)", output) disk_root = m.group(0) disk_name = m.group(1) diff --git a/contrib/phore-cli.bash-completion b/contrib/phore-cli.bash-completion new file mode 100644 index 000000000000..31e5ba034aa7 --- /dev/null +++ b/contrib/phore-cli.bash-completion @@ -0,0 +1,154 @@ +# bash programmable completion for phore-cli(1) +# Copyright (c) 2012-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# call $phore-cli for RPC +_phore_rpc() { + # determine already specified args necessary for RPC + local rpcargs=() + for i in ${COMP_LINE}; do + case "$i" in + -conf=*|-datadir=*|-regtest|-rpc*|-testnet) + rpcargs=( "${rpcargs[@]}" "$i" ) + ;; + esac + done + $phore_cli "${rpcargs[@]}" "$@" +} + +# Add wallet accounts to COMPREPLY +_phore_accounts() { + local accounts + accounts=$(_phore_rpc listaccounts | awk -F '"' '{ print $2 }') + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$accounts" -- "$cur" ) ) +} + +_phore_cli() { + local cur prev words=() cword + local phore_cli + + # save and use original argument to invoke phore-cli for -help, help and RPC + # as phore-cli might not be in $PATH + phore_cli="$1" + + COMPREPLY=() + _get_comp_words_by_ref -n = cur prev words cword + + if ((cword > 5)); then + case ${words[cword-5]} in + sendtoaddress) + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + esac + fi + + if ((cword > 4)); then + case ${words[cword-4]} in + importaddress|listtransactions|setban) + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + signrawtransaction) + COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) ) + return 0 + ;; + esac + fi + + if ((cword > 3)); then + case ${words[cword-3]} in + addmultisigaddress) + _phore_accounts + return 0 + ;; + getbalance|gettxout|importaddress|importpubkey|importprivkey|listreceivedbyaccount|listreceivedbyaddress|listsinceblock) + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + esac + fi + + if ((cword > 2)); then + case ${words[cword-2]} in + addnode) + COMPREPLY=( $( compgen -W "add remove onetry" -- "$cur" ) ) + return 0 + ;; + setban) + COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) ) + return 0 + ;; + fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction) + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + move|setaccount) + _phore_accounts + return 0 + ;; + esac + fi + + case "$prev" in + backupwallet|dumpwallet|importwallet) + _filedir + return 0 + ;; + getaddednodeinfo|getrawmempool|lockunspent|setgenerate) + COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) + return 0 + ;; + getaccountaddress|getaddressesbyaccount|getbalance|getnewaddress|getreceivedbyaccount|listtransactions|move|sendfrom|sendmany) + _phore_accounts + return 0 + ;; + esac + + case "$cur" in + -conf=*) + cur="${cur#*=}" + _filedir + return 0 + ;; + -datadir=*) + cur="${cur#*=}" + _filedir -d + return 0 + ;; + -*=*) # prevent nonsense completions + return 0 + ;; + *) + local helpopts commands + + # only parse -help if senseful + if [[ -z "$cur" || "$cur" =~ ^- ]]; then + helpopts=$($phore_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + fi + + # only parse help if senseful + if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then + commands=$(_phore_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }') + fi + + COMPREPLY=( $( compgen -W "$helpopts $commands" -- "$cur" ) ) + + # Prevent space if an argument is desired + if [[ $COMPREPLY == *= ]]; then + compopt -o nospace + fi + return 0 + ;; + esac +} && +complete -F _phore_cli phore-cli + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh diff --git a/contrib/phore-qt.pro b/contrib/phore-qt.pro index 4954e05e46cf..ef503b577e3d 100644 --- a/contrib/phore-qt.pro +++ b/contrib/phore-qt.pro @@ -114,9 +114,9 @@ HEADERS += src/activemasternode.h \ src/protocol.h \ src/pubkey.h \ src/random.h \ - src/rpcclient.h \ - src/rpcprotocol.h \ - src/rpcserver.h \ + src/rpc/client.h \ + src/rpc/protocol.h \ + src/rpc/server.h \ src/serialize.h \ src/spork.h \ src/streams.h \ @@ -418,18 +418,18 @@ SOURCES += src/activemasternode.cpp \ src/pubkey.cpp \ src/random.cpp \ src/rest.cpp \ - src/rpcblockchain.cpp \ - src/rpcclient.cpp \ - src/rpcdump.cpp \ - src/rpcmasternode-budget.cpp \ - src/rpcmasternode.cpp \ - src/rpcmining.cpp \ - src/rpcmisc.cpp \ - src/rpcnet.cpp \ - src/rpcprotocol.cpp \ - src/rpcrawtransaction.cpp \ - src/rpcserver.cpp \ - src/rpcwallet.cpp \ + src/rpc/blockchain.cpp \ + src/rpc/client.cpp \ + src/rpc/dump.cpp \ + src/rpc/masternode-budget.cpp \ + src/rpc/masternode.cpp \ + src/rpc/mining.cpp \ + src/rpc/misc.cpp \ + src/rpc/net.cpp \ + src/rpc/protocol.cpp \ + src/rpc/rawtransaction.cpp \ + src/rpc/server.cpp \ + src/wallet/rpcwallet.cpp \ src/spork.cpp \ src/support/cleanse.cpp \ src/sync.cpp \ diff --git a/contrib/phore-tx.bash-completion b/contrib/phore-tx.bash-completion new file mode 100644 index 000000000000..25a24a925d71 --- /dev/null +++ b/contrib/phore-tx.bash-completion @@ -0,0 +1,57 @@ +# bash programmable completion for phore-tx(1) +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +_phore_tx() { + local cur prev words=() cword + local phore_tx + + # save and use original argument to invoke phore-tx for -help + # it might not be in $PATH + phore_tx="$1" + + COMPREPLY=() + _get_comp_words_by_ref -n =: cur prev words cword + + case "$cur" in + load=*:*) + cur="${cur#load=*:}" + _filedir + return 0 + ;; + *=*) # prevent attempts to complete other arguments + return 0 + ;; + esac + + if [[ "$cword" == 1 || ( "$prev" != "-create" && "$prev" == -* ) ]]; then + # only options (or an uncompletable hex-string) allowed + # parse phore-tx -help for options + local helpopts + helpopts=$($phore_tx -help | sed -e '/^ -/ p' -e d ) + COMPREPLY=( $( compgen -W "$helpopts" -- "$cur" ) ) + else + # only commands are allowed + # parse -help for commands + local helpcmds + helpcmds=$($phore_tx -help | sed -e '1,/Commands:/d' -e 's/=.*/=/' -e '/^ [a-z]/ p' -e d ) + COMPREPLY=( $( compgen -W "$helpcmds" -- "$cur" ) ) + fi + + # Prevent space if an argument is desired + if [[ $COMPREPLY == *= ]]; then + compopt -o nospace + fi + + return 0 +} && +complete -F _phore_tx phore-tx + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh diff --git a/contrib/phored.bash-completion b/contrib/phored.bash-completion index 321eb28c7d03..0aae5102dc9b 100644 --- a/contrib/phored.bash-completion +++ b/contrib/phored.bash-completion @@ -1,102 +1,21 @@ -# bash programmable completion for phored(1) and phore-cli(1) -# Copyright (c) 2012,2014 Christian von Roques -# Distributed under the MIT/X11 software license, see the accompanying +# bash programmable completion for phored(1) and phore-qt(1) +# Copyright (c) 2012-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -have phored && { - -# call $phored for RPC -_phore_rpc() { - # determine already specified args necessary for RPC - local rpcargs=() - for i in ${COMP_LINE}; do - case "$i" in - -conf=*|-proxy*|-rpc*) - rpcargs=( "${rpcargs[@]}" "$i" ) - ;; - esac - done - $phored "${rpcargs[@]}" "$@" -} - -# Add phore accounts to COMPREPLY -_phore_accounts() { - local accounts - accounts=$(_phore_rpc listaccounts | awk '/".*"/ { a=$1; gsub(/"/, "", a); print a}') - COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$accounts" -- "$cur" ) ) -} - _phored() { local cur prev words=() cword local phored - # save and use original argument to invoke phored - # phored might not be in $PATH + # save and use original argument to invoke phored for -help + # it might not be in $PATH phored="$1" COMPREPLY=() _get_comp_words_by_ref -n = cur prev words cword - if ((cword > 4)); then - case ${words[cword-4]} in - listtransactions) - COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) - return 0 - ;; - signrawtransaction) - COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) ) - return 0 - ;; - esac - fi - - if ((cword > 3)); then - case ${words[cword-3]} in - addmultisigaddress) - _phore_accounts - return 0 - ;; - getbalance|gettxout|importaddress|importprivkey|listreceivedbyaccount|listreceivedbyaddress|listsinceblock|importpubkey) - COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) - return 0 - ;; - esac - fi - - if ((cword > 2)); then - case ${words[cword-2]} in - addnode) - COMPREPLY=( $( compgen -W "add remove onetry" -- "$cur" ) ) - return 0 - ;; - getblock|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction) - COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) - return 0 - ;; - move|setaccount) - _phore_accounts - return 0 - ;; - esac - fi - - case "$prev" in - backupwallet|dumpwallet|dumpallprivatekeys|importwallet) - _filedir - return 0 - ;; - getmempool|lockunspent|setgenerate) - COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) - return 0 - ;; - getaccountaddress|getaddressesbyaccount|getbalance|getnewaddress|getreceivedbyaccount|listtransactions|move|sendfrom|sendmany) - _phore_accounts - return 0 - ;; - esac - case "$cur" in - -conf=*|-pid=*|-loadblock=*|-wallet=*) + -conf=*|-pid=*|-loadblock=*|-rootcertificates=*|-rpccookiefile=*|-wallet=*) cur="${cur#*=}" _filedir return 0 @@ -110,20 +29,14 @@ _phored() { return 0 ;; *) - local helpopts commands - # only parse --help if senseful + # only parse -help if sensible if [[ -z "$cur" || "$cur" =~ ^- ]]; then - helpopts=$($phored --help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + local helpopts + helpopts=$($phored -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + COMPREPLY=( $( compgen -W "$helpopts" -- "$cur" ) ) fi - # only parse help if senseful - if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then - commands=$(_phore_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }') - fi - - COMPREPLY=( $( compgen -W "$helpopts $commands" -- "$cur" ) ) - # Prevent space if an argument is desired if [[ $COMPREPLY == *= ]]; then compopt -o nospace @@ -131,10 +44,8 @@ _phored() { return 0 ;; esac -} - -complete -F _phored phored phore-cli -} +} && +complete -F _phored phored phore-qt # Local variables: # mode: shell-script diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp new file mode 100644 index 000000000000..c6bc05891401 --- /dev/null +++ b/contrib/valgrind.supp @@ -0,0 +1,43 @@ +# Valgrind suppressions file for Phore. +# +# Includes known Valgrind warnings in our dependencies that cannot be fixed +# in-tree. +# +# Example use: +# $ valgrind --suppressions=contrib/valgrind.supp src/test/test_phore +# $ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \ +# --show-leak-kinds=all src/test/test_phore --log_level=test_suite +{ + Suppress libstdc++ warning - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65434 + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + obj:*/libstdc++.* + fun:call_init.part.0 + fun:call_init + fun:_dl_init + obj:*/ld-*.so +} +{ + Suppress libdb warning - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=662917 + Memcheck:Cond + obj:*/libdb_cxx-*.so + fun:__log_put + obj:*/libdb_cxx-*.so + fun:__log_put_record +} +{ + Suppress leveldb warning (leveldb::InitModule()) - https://github.com/google/leveldb/issues/113 + Memcheck:Leak + match-leak-kinds: reachable + fun:_Znwm + fun:_ZN7leveldbL10InitModuleEv +} +{ + Suppress leveldb warning (leveldb::Env::Default()) - https://github.com/google/leveldb/issues/113 + Memcheck:Leak + match-leak-kinds: reachable + fun:_Znwm + ... + fun:_ZN7leveldbL14InitDefaultEnvEv +} diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh new file mode 100755 index 000000000000..15f8108cf011 --- /dev/null +++ b/contrib/windeploy/detached-sig-create.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C +if [ -z "$OSSLSIGNCODE" ]; then + OSSLSIGNCODE=osslsigncode +fi + +if [ ! -n "$1" ]; then + echo "usage: $0 " + echo "example: $0 -key codesign.key" + exit 1 +fi + +OUT=signature-win.tar.gz +SRCDIR=unsigned +WORKDIR=./.tmp +OUTDIR="${WORKDIR}/out" +OUTSUBDIR="${OUTDIR}/win" +TIMESERVER=http://timestamp.comodoca.com +CERTFILE="win-codesign.cert" + +mkdir -p "${OUTSUBDIR}" +basename -a `ls -1 "${SRCDIR}"/*-unsigned.exe` | while read UNSIGNED; do + echo Signing "${UNSIGNED}" + "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@" + "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}" +done + +rm -f "${OUT}" +tar -C "${OUTDIR}" -czf "${OUT}" . +rm -rf "${WORKDIR}" +echo "Created ${OUT}" diff --git a/depends/.gitignore b/depends/.gitignore index 6ab1fb2a6749..68424b9ee3d0 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -9,4 +9,6 @@ mips* arm* aarch64* !patches/** -!Makefile \ No newline at end of file +!Makefile +riscv32* +riscv64* diff --git a/depends/Makefile b/depends/Makefile index 0ddd348e53ed..ee046e3e458d 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -1,10 +1,12 @@ .NOTPARALLEL : SOURCES_PATH ?= $(BASEDIR)/sources +WORK_PATH = $(BASEDIR)/work BASE_CACHE ?= $(BASEDIR)/built SDK_PATH ?= $(BASEDIR)/SDKs NO_QT ?= NO_WALLET ?= +NO_ZMQ ?= NO_UPNP ?= FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources @@ -13,7 +15,7 @@ HOST ?= $(BUILD) PATCHES_PATH = $(BASEDIR)/patches BASEDIR = $(CURDIR) HASH_LENGTH:=11 -DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_CONNECT_TIMEOUT:=30 DOWNLOAD_RETRIES:=3 HOST_ID_SALT ?= salt BUILD_ID_SALT ?= salt @@ -21,7 +23,6 @@ BUILD_ID_SALT ?= salt host:=$(BUILD) ifneq ($(HOST),) host:=$(HOST) -host_toolchain:=$(HOST)- endif ifneq ($(DEBUG),) @@ -30,9 +31,9 @@ else release_type=release endif -base_build_dir=$(BASEDIR)/work/build -base_staging_dir=$(BASEDIR)/work/staging -base_download_dir=$(BASEDIR)/work/download +base_build_dir=$(WORK_PATH)/build +base_staging_dir=$(WORK_PATH)/staging +base_download_dir=$(WORK_PATH)/download canonical_host:=$(shell ./config.sub $(HOST)) build:=$(shell ./config.sub $(BUILD)) @@ -92,6 +93,7 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) wallet_packages_$(NO_WALLET) = $(wallet_packages) upnp_packages_$(NO_UPNP) = $(upnp_packages) +zmq_packages_$(NO_ZMQ) = $(zmq_packages) packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) @@ -100,6 +102,10 @@ ifneq ($(qt_packages_),) native_packages += $(qt_native_packages) endif +ifneq ($(zmq_packages_),) +packages += $(zmq_packages) +endif + all_packages = $(packages) $(native_packages) meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk @@ -136,6 +142,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_ -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ -e 's|@no_qt@|$(NO_QT)|' \ + -e 's|@no_zmq@|$(NO_ZMQ)|' \ -e 's|@no_wallet@|$(NO_WALLET)|' \ -e 's|@no_upnp@|$(NO_UPNP)|' \ -e 's|@debug@|$(DEBUG)|' \ @@ -166,17 +173,25 @@ $(host_prefix)/share/config.site: check-packages check-packages: check-sources +clean-all: clean + @rm -rf $(SOURCES_PATH) x86_64* i686* mips* arm* aarch64* riscv32* riscv64* + +clean: + @rm -rf $(WORK_PATH) $(BASE_CACHE) $(BUILD) + install: check-packages $(host_prefix)/share/config.site download-one: check-sources $(all_sources) download-osx: - @$(MAKE) -s HOST=x86_64-apple-darwin11 download-one + @$(MAKE) -s HOST=x86_64-apple-darwin14 download-one download-linux: @$(MAKE) -s HOST=x86_64-unknown-linux-gnu download-one download-win: @$(MAKE) -s HOST=x86_64-w64-mingw32 download-one download: download-osx download-linux download-win -.PHONY: install cached download-one download-osx download-linux download-win download check-packages check-sources +$(foreach package,$(all_packages),$(eval $(call ext_add_stages,$(package)))) + +.PHONY: install cached clean clean-all download-one download-osx download-linux download-win download check-packages check-sources diff --git a/depends/README.md b/depends/README.md index 99eef1952c6d..590acd82698a 100644 --- a/depends/README.md +++ b/depends/README.md @@ -22,36 +22,54 @@ Common `host-platform-triplets` for cross compilation are: - `i686-w64-mingw32` for Win32 - `x86_64-w64-mingw32` for Win64 -- `x86_64-apple-darwin11` for MacOSX +- `x86_64-apple-darwin14` for macOS - `arm-linux-gnueabihf` for Linux ARM 32 bit - `aarch64-linux-gnu` for Linux ARM 64 bit +- `riscv32-linux-gnu` for Linux RISC-V 32 bit +- `riscv64-linux-gnu` for Linux RISC-V 64 bit No other options are needed, the paths are automatically configured. -Install the required dependencies: Ubuntu & Debian --------------------------------------------------- +### Install the required dependencies: Ubuntu & Debian -For macOS cross compilation: +#### For macOS cross compilation - sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python-setuptools + sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools -For Win32/Win64 cross compilation: +#### For Win32/Win64 cross compilation - see [build-windows.md](../doc/build-windows.md#cross-compilation-for-ubuntu-and-windows-subsystem-for-linux) -For linux (including i386, ARM) cross compilation: +#### For linux (including i386, ARM) cross compilation - sudo apt-get install curl g++-aarch64-linux-gnu g++-4.8-aarch64-linux-gnu gcc-4.8-aarch64-linux-gnu binutils-aarch64-linux-gnu g++-arm-linux-gnueabihf g++-4.8-arm-linux-gnueabihf gcc-4.8-arm-linux-gnueabihf binutils-arm-linux-gnueabihf g++-4.8-multilib gcc-4.8-multilib binutils-gold bsdmainutils +Common linux dependencies: + sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch -Dependency Options: +For linux ARM cross compilation: + + sudo apt-get install g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf + +For linux AARCH64 cross compilation: + + sudo apt-get install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + +For linux RISC-V 64-bit cross compilation (there are no packages for 32-bit): + + sudo apt-get install g++-riscv64-linux-gnu binutils-riscv64-linux-gnu + +RISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_phore` executable (see https://github.com/bitcoin/bitcoin/pull/13543), +this is apparently fixed in gcc-8.1.0. + +### Dependency Options The following can be set when running make: make FOO=bar SOURCES_PATH: downloaded sources will be placed here BASE_CACHE: built packages will be placed here - SDK_PATH: Path where sdk's can be found (used by OSX) + SDK_PATH: Path where sdk's can be found (used by macOS) FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up NO_QT: Don't download/build/cache qt and its dependencies + NO_ZMQ: Don't download/build/cache packages needed for enabling zeromq NO_WALLET: Don't download/build/cache libs needed to enable the wallet NO_UPNP: Don't download/build/cache packages needed for enabling upnp DEBUG: disable some optimizations and enable more runtime checking @@ -61,10 +79,10 @@ The following can be set when running make: make FOO=bar If some packages are not built, for example `make NO_WALLET=1`, the appropriate options will be passed to bitcoin's configure. In this case, `--disable-wallet`. -Additional targets: +### Additional targets download: run 'make download' to fetch all sources without building them - download-osx: run 'make download-osx' to fetch all sources needed for osx builds + download-osx: run 'make download-osx' to fetch all sources needed for macOS builds download-win: run 'make download-win' to fetch all sources needed for win builds download-linux: run 'make download-linux' to fetch all sources needed for linux builds diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index 27f550ab036a..c7671c1548b7 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -1,13 +1,13 @@ -build_darwin_CC: = $(shell xcrun -f clang) -build_darwin_CXX: = $(shell xcrun -f clang++) -build_darwin_AR: = $(shell xcrun -f ar) -build_darwin_RANLIB: = $(shell xcrun -f ranlib) -build_darwin_STRIP: = $(shell xcrun -f strip) -build_darwin_OTOOL: = $(shell xcrun -f otool) -build_darwin_NM: = $(shell xcrun -f nm) +build_darwin_CC:=$(shell xcrun -f clang) +build_darwin_CXX:=$(shell xcrun -f clang++) +build_darwin_AR:=$(shell xcrun -f ar) +build_darwin_RANLIB:=$(shell xcrun -f ranlib) +build_darwin_STRIP:=$(shell xcrun -f strip) +build_darwin_OTOOL:=$(shell xcrun -f otool) +build_darwin_NM:=$(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) -build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o +build_darwin_SHA256SUM=shasum -a 256 +build_darwin_DOWNLOAD=curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/config.guess b/depends/config.guess index 69ed3e573bb3..2b79f6d837b9 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2017 Free Software Foundation, Inc. +# Copyright 1992-2018 Free Software Foundation, Inc. -timestamp='2017-03-05' +timestamp='2018-07-06' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2017-03-05' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -27,7 +27,7 @@ timestamp='2017-03-05' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . @@ -39,7 +39,7 @@ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2017 Free Software Foundation, Inc. +Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -101,15 +101,15 @@ trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && e trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; +case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" ; for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; @@ -132,14 +132,14 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in +case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu - eval $set_cc_for_build - cat <<-EOF > $dummy.c + eval "$set_cc_for_build" + cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc @@ -149,13 +149,20 @@ Linux|GNU|GNU/*) LIBC=gnu #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -169,30 +176,30 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build + eval "$set_cc_for_build" if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then @@ -208,10 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Determine ABI tags. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -219,46 +226,55 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in + case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" + echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) - echo ${UNAME_MACHINE}-unknown-sortix + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -310,28 +326,19 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos + echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos + echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition @@ -343,7 +350,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} + echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos @@ -370,19 +377,19 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} + echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build + eval "$set_cc_for_build" SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. @@ -395,13 +402,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in SUN_ARCH=x86_64 fi fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in @@ -410,25 +417,25 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) - echo sparc-sun-sunos${UNAME_RELEASE} + echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} + echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not @@ -439,44 +446,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} + echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} + echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} + echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} + echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} + echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} + echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} + echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} + echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { @@ -485,23 +492,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} + echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax @@ -527,17 +534,17 @@ EOF AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] then - echo m88k-dg-dgux${UNAME_RELEASE} + echo m88k-dg-dgux"$UNAME_RELEASE" else - echo m88k-dg-dguxbcs${UNAME_RELEASE} + echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else - echo i586-dg-dgux${UNAME_RELEASE} + echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) @@ -554,7 +561,7 @@ EOF echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id @@ -566,14 +573,14 @@ EOF if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #include main() @@ -584,7 +591,7 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else @@ -598,7 +605,7 @@ EOF exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc @@ -607,18 +614,18 @@ EOF IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx @@ -633,28 +640,28 @@ EOF echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in + case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in + case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + if [ "$HP_ARCH" = "" ]; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include @@ -687,13 +694,13 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = hppa2.0w ] + if [ "$HP_ARCH" = hppa2.0w ] then - eval $set_cc_for_build + eval "$set_cc_for_build" # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler @@ -712,15 +719,15 @@ EOF HP_ARCH=hppa64 fi fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #include int main () @@ -745,11 +752,11 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) @@ -758,7 +765,7 @@ EOF *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) @@ -766,9 +773,9 @@ EOF exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + echo "$UNAME_MACHINE"-unknown-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) @@ -793,128 +800,109 @@ EOF echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} + echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin + echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 + echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 + echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 + echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case "$UNAME_MACHINE" in x86) - echo i586-pc-interix${UNAME_RELEASE} + echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} + echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} + echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin + echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in @@ -928,63 +916,63 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) - eval $set_cc_for_build + eval "$set_cc_for_build" if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el @@ -998,70 +986,70 @@ EOF #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" + test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } ;; mips64el:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} + echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} + echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} + echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} + echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} + echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -1075,34 +1063,34 @@ EOF # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx + echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop + echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos + echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable + echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} + echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp + echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) @@ -1112,12 +1100,12 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 @@ -1127,9 +1115,9 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv32 + echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) @@ -1149,9 +1137,9 @@ EOF exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) @@ -1171,9 +1159,9 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; @@ -1182,28 +1170,28 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} + echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} + echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} + echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} + echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} + echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 @@ -1214,7 +1202,7 @@ EOF *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 + echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi @@ -1234,23 +1222,23 @@ EOF exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos + echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} + echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv"$UNAME_RELEASE" else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. @@ -1269,49 +1257,56 @@ EOF echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} + echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} + echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} + echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} + echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} + echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} + echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux${UNAME_RELEASE} + echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} + echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build + eval "$set_cc_for_build" if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub @@ -1322,7 +1317,7 @@ EOF # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` @@ -1330,22 +1325,25 @@ EOF UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} + echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; - NSX-?:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk${UNAME_RELEASE} + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux @@ -1354,7 +1352,7 @@ EOF echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 @@ -1365,7 +1363,7 @@ EOF else UNAME_MACHINE="$cputype" fi - echo ${UNAME_MACHINE}-unknown-plan9 + echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 @@ -1386,14 +1384,14 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in + case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; @@ -1402,32 +1400,44 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos + echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros + echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx + echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 </dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/depends/config.site.in b/depends/config.site.in index 0a4a9c327e2e..e63375206653 100755 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -33,6 +33,10 @@ if test -z $with_gui && test -n "@no_qt@"; then with_gui=no fi +if test -z $enable_zmq && test -n "@no_zmq@"; then + enable_zmq=no +fi + if test x@host_os@ = xdarwin; then BREW=no PORT=no @@ -61,11 +65,13 @@ fi CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" LDFLAGS="-L$depends_prefix/lib $LDFLAGS" -CC="@CC@" -CXX="@CXX@" -OBJC="${CC}" -CCACHE=$depends_prefix/native/bin/ccache -PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH +if test -n "@CC@" -a -z "${CC}"; then + CC="@CC@" +fi +if test -n "@CXX@" -a -z "${CXX}"; then + CXX="@CXX@" +fi +PYTHONPATH=$depends_prefix/native/lib/python3/dist-packages:$PYTHONPATH if test -n "@AR@"; then AR=@AR@ diff --git a/depends/config.sub b/depends/config.sub index 40ea5dfe1152..c95acc681d1b 100755 --- a/depends/config.sub +++ b/depends/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2017 Free Software Foundation, Inc. +# Copyright 1992-2018 Free Software Foundation, Inc. -timestamp='2017-04-02' +timestamp='2018-07-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2017-04-02' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -33,7 +33,7 @@ timestamp='2017-04-02' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -57,7 +57,7 @@ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -67,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2017 Free Software Foundation, Inc. +Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -94,7 +94,7 @@ while test $# -gt 0 ; do *local*) # First pass through any local machine types. - echo $1 + echo "$1" exit ;; * ) @@ -110,134 +110,455 @@ case $# in exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac +# Split fields of configuration type +IFS="-" read -r field1 field2 field3 field4 <&2 + exit 1 ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + *-*-*-*) + basic_machine=$field1-$field2 + os=$field3-$field4 ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ + | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + os=linux-android + ;; + *) + basic_machine=$field1-$field2 + os=$field3 + ;; + esac ;; - -psos*) - os=-psos + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc532* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* | hitachi* \ + | c[123]* | convex* | sun | crds | omron* | dg | ultra | tti* \ + | harris | dolphin | highlevel | gould | cbm | ns | masscomp \ + | apple | axis | knuth | cray | microblaze* \ + | sim | cisco | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + os= + ;; + *) + basic_machine=$field1 + os=$field2 + ;; + esac ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + os=bsd + ;; + a29khif) + basic_machine=a29k-amd + os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=scout + ;; + am29k) + basic_machine=a29k-none + os=bsd + ;; + amdahl) + basic_machine=580-amdahl + os=sysv + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=bsd + ;; + aros) + basic_machine=i386-pc + os=aros + ;; + aux) + basic_machine=m68k-apple + os=aux + ;; + balance) + basic_machine=ns32k-sequent + os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=linux + ;; + cegcc) + basic_machine=arm-unknown + os=cegcc + ;; + cray) + basic_machine=j90-cray + os=unicos + ;; + craynv) + basic_machine=craynv-cray + os=unicosmp + ;; + delta88) + basic_machine=m88k-motorola + os=sysv3 + ;; + dicos) + basic_machine=i686-pc + os=dicos + ;; + djgpp) + basic_machine=i586-pc + os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=ose + ;; + gmicro) + basic_machine=tron-gmicro + os=sysv + ;; + go32) + basic_machine=i386-pc + os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=hms + ;; + harris) + basic_machine=m88k-harris + os=sysv3 + ;; + hp300bsd) + basic_machine=m68k-hp + os=bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=hpux + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=proelf + ;; + i386mach) + basic_machine=i386-mach + os=mach + ;; + vsta) + basic_machine=i386-unknown + os=vsta + ;; + isi68 | isi) + basic_machine=m68k-isi + os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=sysv + ;; + merlin) + basic_machine=ns32k-utek + os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + os=coff + ;; + morphos) + basic_machine=powerpc-unknown + os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=moxiebox + ;; + msdos) + basic_machine=i386-pc + os=msdos + ;; + msys) + basic_machine=i686-pc + os=msys + ;; + mvs) + basic_machine=i370-ibm + os=mvs + ;; + nacl) + basic_machine=le32-unknown + os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=newsos + ;; + news1000) + basic_machine=m68030-sony + os=newsos + ;; + necv70) + basic_machine=v70-nec + os=sysv + ;; + nh3000) + basic_machine=m68k-harris + os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=cxux + ;; + nindy960) + basic_machine=i960-intel + os=nindy + ;; + mon960) + basic_machine=i960-intel + os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=ose + ;; + os68k) + basic_machine=m68k-none + os=os68k + ;; + paragon) + basic_machine=i860-intel + os=osf + ;; + parisc) + basic_machine=hppa-unknown + os=linux + ;; + pw32) + basic_machine=i586-unknown + os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=rdos + ;; + rdos32) + basic_machine=i386-pc + os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=coff + ;; + sa29200) + basic_machine=a29k-amd + os=udi + ;; + sei) + basic_machine=mips-sei + os=seiux + ;; + sps7) + basic_machine=m68k-bull + os=sysv2 + ;; + stratus) + basic_machine=i860-stratus + os=sysv4 + ;; + sun2os3) + basic_machine=m68000-sun + os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=solaris2 + ;; + sv1) + basic_machine=sv1-cray + os=unicos + ;; + symmetry) + basic_machine=i386-sequent + os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=unicos + ;; + t90) + basic_machine=t90-cray + os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + os=tpf + ;; + udi29k) + basic_machine=a29k-amd + os=udi + ;; + ultra3) + basic_machine=a29k-nyu + os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=none + ;; + vaxv) + basic_machine=vax-dec + os=sysv + ;; + vms) + basic_machine=vax-dec + os=vms + ;; + vxworks960) + basic_machine=i960-wrs + os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=vxworks + ;; + xbox) + basic_machine=i686-pc + os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + os=unicos + ;; + *) + basic_machine=$1 + os= + ;; + esac ;; esac @@ -252,12 +573,12 @@ case $basic_machine in | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ - | c4x | c8051 | clipper \ + | c4x | c8051 | clipper | csky \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ @@ -296,14 +617,15 @@ case $basic_machine in | mt \ | msp430 \ | nds32 | nds32le | nds32be \ + | nfp \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ + | pdp10 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ - | riscv32 | riscv64 \ + | riscv | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ @@ -316,7 +638,6 @@ case $basic_machine in | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | wasm32 \ - | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown @@ -335,20 +656,23 @@ case $basic_machine in ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown - os=-none + os=${os:-none} ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) + ;; + m9s12z | m68hcs12z | hcs12z | s12z) + basic_machine=s12z-unknown + os=${os:-none} ;; ms1) basic_machine=mt-unknown ;; - strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown - os=-none + os=${os:-none} ;; xscaleeb) basic_machine=armeb-unknown @@ -364,11 +688,6 @@ case $basic_machine in i*86 | x86_64) basic_machine=$basic_machine-pc ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ @@ -382,7 +701,7 @@ case $basic_machine in | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ + | c8051-* | clipper-* | craynv-* | csky-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ @@ -423,6 +742,7 @@ case $basic_machine in | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ + | nfp-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ @@ -432,7 +752,7 @@ case $basic_machine in | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ - | riscv32-* | riscv64-* \ + | riscv-* | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ @@ -460,141 +780,77 @@ case $basic_machine in ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; abacus) basic_machine=abacus-unknown ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; amd64) basic_machine=x86_64-pc ;; amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv + basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; amiga | amiga-*) basic_machine=m68k-unknown ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; asmjs) basic_machine=asmjs-unknown ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; bluegene*) basic_machine=powerpc-ibm - os=-cnk + os=cnk ;; c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc + os=${os:-unicos} ;; convex-c1) basic_machine=c1-convex - os=-bsd + os=bsd ;; convex-c2) basic_machine=c2-convex - os=-bsd + os=bsd ;; convex-c32) basic_machine=c32-convex - os=-bsd + os=bsd ;; convex-c34) basic_machine=c34-convex - os=-bsd + os=bsd ;; convex-c38) basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp + os=bsd ;; cr16 | cr16-*) basic_machine=cr16-unknown - os=-elf + os=${os:-elf} ;; crds | unos) basic_machine=m68k-crds @@ -607,7 +863,7 @@ case $basic_machine in ;; crx) basic_machine=crx-unknown - os=-elf + os=${os:-elf} ;; da30 | da30-*) basic_machine=m68k-da30 @@ -617,58 +873,38 @@ case $basic_machine in ;; decsystem10* | dec10*) basic_machine=pdp10-dec - os=-tops10 + os=tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec - os=-tops20 + os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; dpx20 | dpx20-*) basic_machine=rs6000-bull - os=-bosx + os=${os:-bosx} ;; - dpx2* | dpx2*-bull) + dpx2*) basic_machine=m68k-bull - os=-sysv3 + os=sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=$os"spe" ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; encore | umax | mmax) basic_machine=ns32k-encore ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose + elxsi) + basic_machine=elxsi-elxsi + os=${os:-bsd} ;; fx2800) basic_machine=i860-alliant @@ -676,45 +912,13 @@ case $basic_machine in genix) basic_machine=ns32k-ns ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 + os=hiuxwe2 ;; hp300-*) basic_machine=m68k-hp ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; @@ -744,200 +948,82 @@ case $basic_machine in hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv32 ;; i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv4 ;; i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv ;; i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=solaris2 ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta + j90 | j90-cray) + basic_machine=j90-cray + os=${os:-unicos} ;; iris | iris4d) basic_machine=mips-sgi case $os in - -irix*) + irix*) ;; *) - os=-irix4 + os=irix4 ;; esac ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux + basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` ;; m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv + basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; microblaze*) basic_machine=microblaze-xilinx ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; miniframe) basic_machine=m68000-convergent ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari - os=-mint + os=mint ;; mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` ;; mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown ;; ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos + basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` ;; news-3600 | risc-news) basic_machine=mips-sony - os=-newsos + os=newsos ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) + next | m*-next) basic_machine=m68k-next case $os in - -nextstep* ) + nextstep* ) ;; - -ns2*) - os=-nextstep2 + ns2*) + os=nextstep2 ;; *) - os=-nextstep3 + os=nextstep3 ;; esac ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; np1) basic_machine=np1-gould ;; @@ -950,43 +1036,26 @@ case $basic_machine in nsr-tandem) basic_machine=nsr-tandem ;; + nsv-tandem) + basic_machine=nsv-tandem + ;; nsx-tandem) basic_machine=nsx-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki - os=-proelf + os=proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; pa-hitachi) basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux + os=hiuxwe2 ;; parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; pbd) basic_machine=sparc-tti @@ -1001,7 +1070,7 @@ case $basic_machine in basic_machine=i386-pc ;; pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc @@ -1016,16 +1085,16 @@ case $basic_machine in basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould @@ -1035,43 +1104,27 @@ case $basic_machine in ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; rm[46]00) basic_machine=mips-siemens ;; @@ -1084,10 +1137,6 @@ case $basic_machine in s390x | s390x-*) basic_machine=s390x-ibm ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; sb1) basic_machine=mipsisa64sb1-unknown ;; @@ -1096,32 +1145,17 @@ case $basic_machine in ;; sde) basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux + os=${os:-elf} ;; sequent) basic_machine=i386-sequent ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; sh5el) basic_machine=sh5le-unknown ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) + simso-wrs) basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 + os=vxworks ;; spur) basic_machine=spur-unknown @@ -1129,44 +1163,12 @@ case $basic_machine in st2000) basic_machine=m68k-tandem ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; sun3 | sun3-*) basic_machine=m68k-sun ;; @@ -1176,25 +1178,9 @@ case $basic_machine in sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; tile*) basic_machine=$basic_machine-unknown - os=-linux-gnu + os=linux-gnu ;; tx39) basic_machine=mipstx39-unknown @@ -1202,88 +1188,32 @@ case $basic_machine in tx39el) basic_machine=mipstx39el-unknown ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; tower | tower-32) basic_machine=m68k-ncr ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - wasm32) - basic_machine=wasm32-unknown - ;; w65*) basic_machine=w65-wdc - os=-none + os=none ;; w89k-*) basic_machine=hppa1.1-winbond - os=-proelf + os=proelf ;; - xbox) - basic_machine=i686-pc - os=-mingw32 + x64) + basic_machine=x86_64-pc ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim + basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` ;; none) basic_machine=none-none - os=-none + os=${os:-none} ;; # Here we handle the default manufacturer of certain CPU types. It is in @@ -1309,10 +1239,6 @@ case $basic_machine in vax) basic_machine=vax-dec ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; pdp11) basic_machine=pdp11-dec ;; @@ -1322,9 +1248,6 @@ case $basic_machine in sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; cydra) basic_machine=cydra-cydrome ;; @@ -1344,7 +1267,7 @@ case $basic_machine in # Make sure to match an already-canonicalized machine name. ;; *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; esac @@ -1352,10 +1275,10 @@ esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` ;; *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` ;; *) ;; @@ -1363,200 +1286,246 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if [ x$os != x ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + # First match some system type aliases that might get confused + # with valid system types. + # solaris* is a basic system type, with this one exception. + auroraux) + os=auroraux ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` + bluegene*) + os=cnk ;; - -solaris) - os=-solaris2 + solaris1 | solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; - -svr4*) - os=-sysv4 + solaris) + os=solaris2 ;; - -unixware*) - os=-sysv4.2uw + unixware*) + os=sysv4.2uw ;; - -gnu/linux*) + gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; - # First accept the basic system types. + # es1800 is here to avoid being matched by es* (a different OS) + es1800*) + os=ose + ;; + # Some version numbers need modification + chorusos*) + os=chorusos + ;; + isc) + os=isc2.2 + ;; + sco6) + os=sco5v6 + ;; + sco5) + os=sco3.2v5 + ;; + sco4) + os=sco3.2v4 + ;; + sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + ;; + sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + scout) + # Don't match below + ;; + sco*) + os=sco3.2v2 + ;; + psos*) + os=psos + ;; + # Now accept the basic system types. # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) + # Each alternative MUST end in a * to match a version number. + # sysv* is not here because it comes later, after sysvr4. + gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | kopensolaris* | plan9* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | rtu* | xenix* \ + | knetbsd* | mirbsd* | netbsd* \ + | bitrig* | openbsd* | solidbsd* | libertybsd* \ + | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ + | linux-newlib* | linux-musl* | linux-uclibc* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* \ + | morphos* | superux* | rtmk* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd*) # Remember, each alternative MUST END IN *, to match a version number. ;; - -qnx*) + qnx*) case $basic_machine in x86-* | i*86-*) ;; *) - os=-nto$os + os=nto-$os ;; esac ;; - -nto-qnx*) + hiux*) + os=hiuxwe2 ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` + nto-qnx*) ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` + sim | xray | os68k* | v88r* \ + | windows* | osx | abug | netware* | os9* \ + | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) ;; - -linux-dietlibc) - os=-linux-dietlibc + linux-dietlibc) + os=linux-dietlibc ;; - -linux*) + linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` + lynx*178) + os=lynxos178 + ;; + lynx*5) + os=lynxos5 + ;; + lynx*) + os=lynxos ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` + mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` ;; - -opened*) - os=-openedition + opened*) + os=openedition ;; - -os400*) - os=-os400 + os400*) + os=os400 ;; - -wince*) - os=-wince + sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; - -osfrose*) - os=-osfrose + sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; - -osf*) - os=-osf + wince*) + os=wince ;; - -utek*) - os=-bsd + utek*) + os=bsd ;; - -dynix*) - os=-bsd + dynix*) + os=bsd ;; - -acis*) - os=-aos + acis*) + os=aos ;; - -atheos*) - os=-atheos + atheos*) + os=atheos ;; - -syllable*) - os=-syllable + syllable*) + os=syllable ;; - -386bsd) - os=-bsd + 386bsd) + os=bsd ;; - -ctix* | -uts*) - os=-sysv + ctix* | uts*) + os=sysv ;; - -nova*) - os=-rtmk-nova + nova*) + os=rtmk-nova ;; - -ns2 ) - os=-nextstep2 + ns2) + os=nextstep2 ;; - -nsk*) - os=-nsk + nsk*) + os=nsk ;; # Preserve the version number of sinix5. - -sinix5.*) + sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf + sinix*) + os=sysv4 ;; - -triton*) - os=-sysv3 + tpf*) + os=tpf ;; - -oss*) - os=-sysv3 + triton*) + os=sysv3 ;; - -svr4) - os=-sysv4 + oss*) + os=sysv3 ;; - -svr3) - os=-sysv3 + svr4*) + os=sysv4 ;; - -sysvr4) - os=-sysv4 + svr3) + os=sysv3 ;; - # This must come after -sysvr4. - -sysv*) + sysvr4) + os=sysv4 ;; - -ose*) - os=-ose + # This must come after sysvr4. + sysv*) ;; - -es1800*) - os=-ose + ose*) + os=ose ;; - -xenix) - os=-xenix + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + os=mint ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint + zvmoe) + os=zvmoe ;; - -aros*) - os=-aros + dicos*) + os=dicos ;; - -zvmoe) - os=-zvmoe + pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=eabi + ;; + *) + os=elf + ;; + esac ;; - -dicos*) - os=-dicos + nacl*) ;; - -nacl*) + ios) ;; - -ios) + none) ;; - -none) + *-eabi) ;; *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac @@ -1574,179 +1543,179 @@ else case $basic_machine in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + os=linux ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff ;; c8051-*) - os=-elf + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 ;; pru-*) - os=-elf + os=elf ;; *-be) - os=-beos - ;; - *-haiku) - os=-haiku + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna + os=luna ;; - *-next ) - os=-nextstep + *-next) + os=nextstep ;; *-sequent) - os=-ptx + os=ptx ;; *-crds) - os=-unos + os=unos ;; *-ns) - os=-genix + os=genix ;; i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac fi @@ -1757,79 +1726,82 @@ vendor=unknown case $basic_machine in *-unknown) case $os in - -riscix*) + riscix*) vendor=acorn ;; - -sunos*) + sunos*) vendor=sun ;; - -cnk*|-aix*) + cnk*|-aix*) vendor=ibm ;; - -beos*) + beos*) vendor=be ;; - -hpux*) + hpux*) vendor=hp ;; - -mpeix*) + mpeix*) vendor=hp ;; - -hiux*) + hiux*) vendor=hitachi ;; - -unos*) + unos*) vendor=crds ;; - -dgux*) + dgux*) vendor=dg ;; - -luna*) + luna*) vendor=omron ;; - -genix*) + genix*) vendor=ns ;; - -mvs* | -opened*) + clix*) + vendor=intergraph + ;; + mvs* | opened*) vendor=ibm ;; - -os400*) + os400*) vendor=ibm ;; - -ptx*) + ptx*) vendor=sequent ;; - -tpf*) + tpf*) vendor=ibm ;; - -vxsim* | -vxworks* | -windiss*) + vxsim* | vxworks* | windiss*) vendor=wrs ;; - -aux*) + aux*) vendor=apple ;; - -hms*) + hms*) vendor=hitachi ;; - -mpw* | -macos*) + mpw* | macos*) vendor=apple ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) vendor=atari ;; - -vos*) + vos*) vendor=stratus ;; esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` ;; esac -echo $basic_machine$os +echo "$basic_machine-$os" exit # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/depends/description.md b/depends/description.md index 74f9ef3f205e..9fc7093be4f3 100644 --- a/depends/description.md +++ b/depends/description.md @@ -7,7 +7,7 @@ In theory, binaries for any target OS/architecture can be created, from a builder running any OS/architecture. In practice, build-side tools must be specified when the defaults don't fit, and packages must be amended to work on new hosts. For now, a build architecture of x86_64 is assumed, either on -Linux or OSX. +Linux or macOS. ### No reliance on timestamps diff --git a/depends/funcs.mk b/depends/funcs.mk index 15e404e42dcf..8f03c5f37a00 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -76,8 +76,9 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) #default commands +# The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior $(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) -$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --no-same-owner --strip-components=1 -xf $$($(1)_source) $(1)_preprocess_cmds ?= $(1)_build_cmds ?= $(1)_config_cmds ?= @@ -170,15 +171,15 @@ $($(1)_extracted): | $($(1)_fetched) $(AT)mkdir -p $$(@D) $(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1)) $(AT)touch $$@ -$($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted) +$($(1)_preprocessed): | $($(1)_extracted) $(AT)echo Preprocessing $(1)... $(AT)mkdir -p $$(@D) $($(1)_patch_dir) $(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) $(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1)) $(AT)touch $$@ -$($(1)_configured): | $($(1)_preprocessed) +$($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed) $(AT)echo Configuring $(1)... - $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); ) + $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar --no-same-owner -xf $($(package)_cached); ) $(AT)mkdir -p $$(@D) $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) $(AT)touch $$@ @@ -213,6 +214,14 @@ $(1): | $($(1)_cached_checksum) endef +stages = fetched extracted preprocessed configured built staged postprocessed cached cached_checksum + +define ext_add_stages +$(foreach stage,$(stages), + $(1)_$(stage): $($(1)_$(stage)) + .PHONY: $(1)_$(stage)) +endef + # These functions create the build targets for each package. They must be # broken down into small steps so that each part is done for all packages # before moving on to the next step. Otherwise, a package's info diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 4e58bec74e39..a1c943d60bbd 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,4 +1,4 @@ -OSX_MIN_VERSION=10.8 +OSX_MIN_VERSION=10.10 OSX_SDK_VERSION=10.11 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk LD64_VERSION=253.9 diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk index 6f60d6b3fd00..144e5f88b782 100644 --- a/depends/hosts/default.mk +++ b/depends/hosts/default.mk @@ -1,3 +1,7 @@ +ifneq ($(host),$(build)) +host_toolchain:=$(host)- +endif + default_host_CC = $(host_toolchain)gcc default_host_CXX = $(host_toolchain)g++ default_host_AR = $(host_toolchain)ar diff --git a/depends/packages.md b/depends/packages.md index 7c80362509e9..7d2bd4670d42 100644 --- a/depends/packages.md +++ b/depends/packages.md @@ -14,8 +14,9 @@ Each package is required to define at least these variables: placeholder such as 1.0 can be used. $(package)_download_path: - Location of the upstream source, without the file-name. Usually http or - ftp. + Location of the upstream source, without the file-name. Usually http, https + or ftp. Secure transmission options like https should be preferred if + available. $(package)_file_name: The upstream source filename available at the download path. diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 6c9876c2c7c7..6cdb79592b61 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -1,6 +1,6 @@ package=bdb $(package)_version=4.8.30 -$(package)_download_path=http://download.oracle.com/berkeley-db +$(package)_download_path=https://download.oracle.com/berkeley-db $(package)_file_name=db-$($(package)_version).NC.tar.gz $(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef $(package)_build_subdir=build_unix @@ -10,6 +10,7 @@ $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 +$(package)_cppflags_mingw32=-DUNICODE -D_UNICODE endef define $(package)_preprocess_cmds diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index 7f484724a490..8d06882cdb50 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -1,11 +1,11 @@ package=expat -$(package)_version=2.2.1 -$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version) +$(package)_version=2.2.6 +$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_6/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=1868cadae4c82a018e361e2b2091de103cd820aaacb0d6cfa49bd2cd83978885 +$(package)_sha256_hash=17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2 define $(package)_set_vars -$(package)_config_opts=--disable-static +$(package)_config_opts=--disable-static --without-docbook endef define $(package)_config_cmds diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk index 12695db4b9f7..d0996b4534eb 100644 --- a/depends/packages/fontconfig.mk +++ b/depends/packages/fontconfig.mk @@ -1,6 +1,6 @@ package=fontconfig $(package)_version=2.12.1 -$(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/ +$(package)_download_path=https://www.freedesktop.org/software/fontconfig/release/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=b449a3e10c47e1d1c7a6ec6e2016cca73d3bd68fbbd4f0ae5cc6b573f7d6c7f3 $(package)_dependencies=freetype expat diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index 76b025c46318..a98e82ed168b 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -1,11 +1,11 @@ package=freetype $(package)_version=2.7.1 -$(package)_download_path=http://download.savannah.gnu.org/releases/$(package) +$(package)_download_path=https://download.savannah.gnu.org/releases/$(package) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88 define $(package)_set_vars - $(package)_config_opts=--without-zlib --without-png --disable-static + $(package)_config_opts=--without-zlib --without-png --without-harfbuzz --without-bzip2 --disable-static $(package)_config_opts_linux=--with-pic endef diff --git a/depends/packages/libICE.mk b/depends/packages/libICE.mk deleted file mode 100644 index fc60323b1c91..000000000000 --- a/depends/packages/libICE.mk +++ /dev/null @@ -1,23 +0,0 @@ -package=libICE -$(package)_version=1.0.9 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=8f7032f2c1c64352b5423f6b48a8ebdc339cc63064af34d66a6c9aa79759e202 -$(package)_dependencies=xtrans xproto - -define $(package)_set_vars - $(package)_config_opts=--disable-static --disable-docs --disable-specs --without-xsltproc - $(package)_config_opts_linux=--with-pic -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install -endef diff --git a/depends/packages/libSM.mk b/depends/packages/libSM.mk deleted file mode 100644 index 0f9307ca76ac..000000000000 --- a/depends/packages/libSM.mk +++ /dev/null @@ -1,23 +0,0 @@ -package=libSM -$(package)_version=1.2.2 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=0baca8c9f5d934450a70896c4ad38d06475521255ca63b717a6510fdb6e287bd -$(package)_dependencies=xtrans xproto libICE - -define $(package)_set_vars - $(package)_config_opts=--without-libuuid --without-xsltproc --disable-docs --disable-static - $(package)_config_opts_linux=--with-pic -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install -endef diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk index 178d592ee63f..a013da51925e 100644 --- a/depends/packages/libX11.mk +++ b/depends/packages/libX11.mk @@ -1,6 +1,6 @@ package=libX11 $(package)_version=1.6.2 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16 $(package)_dependencies=libxcb xtrans xextproto xproto @@ -10,6 +10,10 @@ $(package)_config_opts=--disable-xkb --disable-static $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk index e87df2e4de67..ce42140689c2 100644 --- a/depends/packages/libXau.mk +++ b/depends/packages/libXau.mk @@ -1,6 +1,6 @@ package=libXau $(package)_version=1.0.8 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=fdd477320aeb5cdd67272838722d6b7d544887dfe7de46e1e7cc0c27c2bea4f2 $(package)_dependencies=xproto @@ -10,6 +10,10 @@ define $(package)_set_vars $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk index 4db836066f96..458b96778418 100644 --- a/depends/packages/libXext.mk +++ b/depends/packages/libXext.mk @@ -1,6 +1,6 @@ package=libXext $(package)_version=1.3.2 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=f829075bc646cdc085fa25d98d5885d83b1759ceb355933127c257e8e50432e0 $(package)_dependencies=xproto xextproto libX11 libXau @@ -9,6 +9,10 @@ define $(package)_set_vars $(package)_config_opts=--disable-static endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index 28f2bd6f2534..3ddd5a7dd99c 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -1,6 +1,6 @@ package=libxcb $(package)_version=1.10 -$(package)_download_path=http://xcb.freedesktop.org/dist +$(package)_download_path=https://xcb.freedesktop.org/dist $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5 $(package)_dependencies=xcb_proto libXau xproto @@ -10,6 +10,7 @@ $(package)_config_opts=--disable-static endef define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux &&\ sed "s/pthread-stubs//" -i configure endef diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 1bb8cb5d2664..fdbe22cda63d 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,12 +1,12 @@ package=miniupnpc -$(package)_version=2.0.20170509 -$(package)_download_path=http://miniupnp.free.fr/files +$(package)_version=2.0.20180203 +$(package)_download_path=https://miniupnp.tuxfamily.org/files/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=d3c368627f5cdfb66d3ebd64ca39ba54d6ff14a61966dbecb8dd296b7039f16a +$(package)_sha256_hash=90dda8c7563ca6cd4a83e23b3c66dbbea89603a1675bfdb852897c2c9cc220b7 define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" -$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)" +$(package)_build_opts_darwin=LIBTOOL="$($(package)_libtool)" $(package)_build_opts_mingw32=-f Makefile.mingw $(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)" endef diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk index 3c6e8900f664..c3054cbd1a16 100644 --- a/depends/packages/native_biplist.mk +++ b/depends/packages/native_biplist.mk @@ -1,20 +1,15 @@ package=native_biplist -$(package)_version=0.9 -$(package)_download_path=https://pypi.python.org/packages/source/b/biplist +$(package)_version=1.0.3 +$(package)_download_path=https://bitbucket.org/wooster/biplist/downloads $(package)_file_name=biplist-$($(package)_version).tar.gz -$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=sorted_list.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/sorted_list.patch -endef +$(package)_sha256_hash=4c0549764c5fe50b28042ec21aa2e14fe1a2224e239a1dae77d9e7f3932aa4c6 +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk deleted file mode 100644 index 966804ce8bbf..000000000000 --- a/depends/packages/native_ccache.mk +++ /dev/null @@ -1,25 +0,0 @@ -package=native_ccache -$(package)_version=3.3.4 -$(package)_download_path=https://samba.org/ftp/ccache -$(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567 - -define $(package)_set_vars -$(package)_config_opts= -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install -endef - -define $(package)_postprocess_cmds - rm -rf lib include -endef diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk index 44d238cc4c2a..a065256c1c1e 100644 --- a/depends/packages/native_cctools.mk +++ b/depends/packages/native_cctools.mk @@ -5,7 +5,7 @@ $(package)_file_name=$($(package)_version).tar.gz $(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a $(package)_build_subdir=cctools $(package)_clang_version=3.7.1 -$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version) +$(package)_clang_download_path=https://llvm.org/releases/$($(package)_clang_version) $(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz $(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz $(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9 @@ -22,12 +22,12 @@ define $(package)_extract_cmds echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ - tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ + tar --no-same-owner --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ rm -f toolchain/lib/libc++abi.so* && \ echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \ chmod +x toolchain/bin/$(host)-dsymutil && \ - tar --strip-components=1 -xf $($(package)_source) + tar --no-same-owner --strip-components=1 -xf $($(package)_source) endef define $(package)_set_vars diff --git a/depends/packages/native_cdrkit.mk b/depends/packages/native_cdrkit.mk index cf694edb30e9..8243458ec858 100644 --- a/depends/packages/native_cdrkit.mk +++ b/depends/packages/native_cdrkit.mk @@ -1,6 +1,6 @@ package=native_cdrkit $(package)_version=1.1.11 -$(package)_download_path=http://distro.ibiblio.org/fatdog/source/600/c +$(package)_download_path=https://distro.ibiblio.org/fatdog/source/600/c $(package)_file_name=cdrkit-$($(package)_version).tar.bz2 $(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564 $(package)_patches=cdrkit-deterministic.patch diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk index 116fa25d3819..f99b689ecdc7 100644 --- a/depends/packages/native_ds_store.mk +++ b/depends/packages/native_ds_store.mk @@ -3,14 +3,14 @@ $(package)_version=1.1.2 $(package)_download_path=https://github.com/al45tair/ds_store/archive/ $(package)_file_name=v$($(package)_version).tar.gz $(package)_sha256_hash=3b3ecb7bf0a5157f5b6010bc3af7c141fb0ad3527084e63336220d22744bc20c -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages $(package)_dependencies=native_biplist define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk index 488ec8b59c97..e60b99dccc98 100644 --- a/depends/packages/native_mac_alias.mk +++ b/depends/packages/native_mac_alias.mk @@ -1,20 +1,15 @@ package=native_mac_alias -$(package)_version=2.0.6 +$(package)_version=2.0.7 $(package)_download_path=https://github.com/al45tair/mac_alias/archive/ $(package)_file_name=v$($(package)_version).tar.gz -$(package)_sha256_hash=78a3332d9a597eebf09ae652d38ad1e263b28db5c2e6dd725fad357b03b77371 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=python3.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/python3.patch -endef +$(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838 +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk index 260db6f6b235..23c2534b8c92 100644 --- a/depends/packages/native_protobuf.mk +++ b/depends/packages/native_protobuf.mk @@ -6,7 +6,7 @@ $(package)_file_name=protobuf-cpp-$($(package)_version).tar.gz $(package)_sha256_hash=c28dba8782da2cfea1e11c61d335958c31a9c1bc553063546af9cbe98f204092 define $(package)_set_vars -$(package)_config_opts=--disable-shared +$(package)_config_opts=--disable-shared --without-zlib endef define $(package)_config_cmds diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 5ee9f17a6323..db47113b2f9b 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -47,10 +47,13 @@ $(package)_config_opts_linux=-fPIC -Wa,--noexecstack $(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_arm_linux=linux-generic32 +$(package)_config_opts_armv7l_linux=linux-generic32 $(package)_config_opts_aarch64_linux=linux-generic64 $(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32 $(package)_config_opts_powerpc_linux=linux-generic32 +$(package)_config_opts_riscv32_linux=linux-generic32 +$(package)_config_opts_riscv64_linux=linux-generic64 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 11c2e55b36b9..ffa0ae3e0c4b 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,19 +1,17 @@ -packages:=boost openssl libevent zeromq -native_packages := native_ccache +packages:=boost openssl libevent qt_native_packages = native_protobuf qt_packages = qrencode protobuf zlib -qt_x86_64_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans -qt_i686_linux_packages:=$(qt_x86_64_linux_packages) -qt_arm_linux_packages:=$(qt_x86_64_linux_packages) -qt_aarch64_linux_packages:=$(qt_x86_64_linux_packages) +qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans qt_darwin_packages=qt qt_mingw32_packages=qt wallet_packages=bdb +zmq_packages=zeromq + upnp_packages=miniupnpc darwin_native_packages = native_biplist native_ds_store native_mac_alias diff --git a/depends/packages/protobuf.mk b/depends/packages/protobuf.mk index 54d3fd924519..7b7e90a429e8 100644 --- a/depends/packages/protobuf.mk +++ b/depends/packages/protobuf.mk @@ -11,6 +11,10 @@ define $(package)_set_vars $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index 44fdf1c2952b..313e4adf2ae6 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -9,6 +9,10 @@ $(package)_config_opts=--disable-shared -without-tools --disable-sdltest $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub use +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index cd0d6cca4bc7..f381dd53943c 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,21 +1,20 @@ PACKAGE=qt -$(package)_version=5.7.1 -$(package)_download_path=https://download.qt.io/archive/qt/5.7/$($(package)_version)/submodules -$(package)_suffix=opensource-src-$($(package)_version).tar.gz +$(package)_version=5.9.7 +$(package)_download_path=https://download.qt.io/official_releases/qt/5.9/$($(package)_version)/submodules +$(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410 +$(package)_sha256_hash=36dd9574f006eaa1e5af780e4b33d11fe39d09fd7c12f3b9d83294174bd28f00 $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib -$(package)_patches=mac-qmake.conf aarch32-qmake.conf aarch64-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qt_pkgconfig.patch +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d - +$(package)_qttranslations_sha256_hash=b36da7d93c3ab6fca56b32053bb73bc619c8b192bb89b74e3bcde2705f1c2a14 $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=22d67de915cb8cd93e16fdd38fa006224ad9170bd217c2be1e53045a8dd02f0f +$(package)_qttools_sha256_hash=d62e0f70d99645d6704dbb8976fb2222443061743689943d40970c52c49367a1 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) @@ -28,25 +27,19 @@ $(package)_config_opts += -c++std c++11 $(package)_config_opts += -confirm-license $(package)_config_opts += -dbus-runtime $(package)_config_opts += -hostprefix $(build_prefix) -$(package)_config_opts += -no-alsa -$(package)_config_opts += -no-audio-backend +$(package)_config_opts += -no-compile-examples $(package)_config_opts += -no-cups $(package)_config_opts += -no-egl $(package)_config_opts += -no-eglfs -$(package)_config_opts += -no-feature-style-windowsmobile -$(package)_config_opts += -no-feature-style-windowsce $(package)_config_opts += -no-freetype $(package)_config_opts += -no-gif $(package)_config_opts += -no-glib -$(package)_config_opts += -no-gstreamer $(package)_config_opts += -no-icu $(package)_config_opts += -no-iconv $(package)_config_opts += -no-kms $(package)_config_opts += -no-linuxfb $(package)_config_opts += -no-libudev -$(package)_config_opts += -no-mitshm $(package)_config_opts += -no-mtdev -$(package)_config_opts += -no-pulseaudio $(package)_config_opts += -no-openvg $(package)_config_opts += -no-reduce-relocations $(package)_config_opts += -no-qml-debug @@ -61,7 +54,6 @@ $(package)_config_opts += -no-sql-sqlite $(package)_config_opts += -no-sql-sqlite2 $(package)_config_opts += -no-use-gold-linker $(package)_config_opts += -no-xinput2 -$(package)_config_opts += -no-xrender $(package)_config_opts += -nomake examples $(package)_config_opts += -nomake tests $(package)_config_opts += -opensource @@ -73,13 +65,26 @@ $(package)_config_opts += -prefix $(host_prefix) $(package)_config_opts += -qt-libpng $(package)_config_opts += -qt-libjpeg $(package)_config_opts += -qt-pcre +$(package)_config_opts += -qt-harfbuzz $(package)_config_opts += -system-zlib -$(package)_config_opts += -reduce-exports $(package)_config_opts += -static $(package)_config_opts += -silent $(package)_config_opts += -v +$(package)_config_opts += -no-feature-dial +$(package)_config_opts += -no-feature-ftp +$(package)_config_opts += -no-feature-lcdnumber +$(package)_config_opts += -no-feature-pdf $(package)_config_opts += -no-feature-printer $(package)_config_opts += -no-feature-printdialog +$(package)_config_opts += -no-feature-concurrent +$(package)_config_opts += -no-feature-sql +$(package)_config_opts += -no-feature-statemachine +$(package)_config_opts += -no-feature-syntaxhighlighter +$(package)_config_opts += -no-feature-textbrowser +$(package)_config_opts += -no-feature-textodfwriter +$(package)_config_opts += -no-feature-udpsocket +$(package)_config_opts += -no-feature-wizard +$(package)_config_opts += -no-feature-xml ifneq ($(build_os),darwin) $(package)_config_opts_darwin = -xplatform macx-clang-linux @@ -91,17 +96,20 @@ $(package)_config_opts_darwin += -device-option MAC_TARGET=$(host) $(package)_config_opts_darwin += -device-option MAC_LD64_VERSION=$(LD64_VERSION) endif -$(package)_config_opts_linux = -qt-xkbcommon +$(package)_config_opts_linux = -qt-xkbcommon-x11 $(package)_config_opts_linux += -qt-xcb $(package)_config_opts_linux += -system-freetype -$(package)_config_opts_linux += -no-sm +$(package)_config_opts_linux += -no-feature-sessionmanager $(package)_config_opts_linux += -fontconfig $(package)_config_opts_linux += -no-opengl -$(package)_config_opts_arm_linux = -platform linux-g++ -xplatform $(host) -$(package)_config_opts_aarch64_linux = -platform linux-g++ -xplatform $(host) +$(package)_config_opts_arm_linux += -platform linux-g++ -xplatform phore-linux-g++ $(package)_config_opts_i686_linux = -xplatform linux-g++-32 +$(package)_config_opts_x86_64_linux = -xplatform linux-g++-64 +$(package)_config_opts_aarch64_linux = -xplatform linux-aarch64-gnu-g++ +$(package)_config_opts_riscv64_linux = -platform linux-g++ -xplatform phore-linux-g++ $(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" $(package)_build_env = QT_RCC_TEST=1 +$(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 endef define $(package)_fetch_cmds @@ -117,43 +125,42 @@ define $(package)_extract_cmds echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir qtbase && \ - tar --strip-components=1 -xf $($(package)_source) -C qtbase && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \ mkdir qttranslations && \ - tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ mkdir qttools && \ - tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools endef - define $(package)_preprocess_cmds + sed -i.old "s|FT_Get_Font_Format|FT_Get_X11_Font_Format|" qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ - sed -i.old "s/src_plugins.depends = src_sql src_xml src_network/src_plugins.depends = src_xml src_network/" qtbase/src/src.pro && \ + sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ - sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \ + sed -i.old -e 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' -e 's|/bin/pwd|pwd|' qtbase/configure && \ sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/Info.plist.lib qtbase/mkspecs/macx-clang-linux/ &&\ cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ - mkdir -p qtbase/mkspecs/arm-linux-gnueabihf &&\ - cp -f qtbase/mkspecs/linux-arm-gnueabi-g++/qplatformdefs.h qtbase/mkspecs/arm-linux-gnueabihf/ &&\ - cp -f $($(package)_patch_dir)/aarch32-qmake.conf qtbase/mkspecs/arm-linux-gnueabihf/qmake.conf &&\ - mkdir -p qtbase/mkspecs/aarch64-linux-gnu &&\ - cp -f qtbase/mkspecs/linux-arm-gnueabi-g++/qplatformdefs.h qtbase/mkspecs/aarch64-linux-gnu/ &&\ - cp -f $($(package)_patch_dir)/aarch64-qmake.conf qtbase/mkspecs/aarch64-linux-gnu/qmake.conf &&\ - patch -p1 < $($(package)_patch_dir)/mingw-uuidof.patch && \ - patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ - patch -p1 < $($(package)_patch_dir)/fix-xcb-include-order.patch && \ - patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ + cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/phore-linux-g++ && \ + sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/phore-linux-g++/qmake.conf && \ + patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch &&\ + patch -p1 -i $($(package)_patch_dir)/xkb-default.patch &&\ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + patch -p1 -i $($(package)_patch_dir)/fix_riscv64_arch.patch &&\ + echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ + echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS = |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ sed -i.old "s|QMAKE_LFLAGS = |!host_build: QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ sed -i.old "s|QMAKE_CXXFLAGS = |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf - endef define $(package)_config_cmds @@ -165,19 +172,22 @@ define $(package)_config_cmds echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \ $(MAKE) sub-src-clean && \ cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \ - cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. &&\ - cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile + cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. && \ + cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile && \ + cd ../lupdate/ && ../../../../qtbase/bin/qmake lupdate.pro -o Makefile && cd ../../../.. endef define $(package)_build_cmds $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ $(MAKE) -C ../qttools/src/linguist/lrelease && \ + $(MAKE) -C ../qttools/src/linguist/lupdate && \ $(MAKE) -C ../qttranslations endef define $(package)_stage_cmds - $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. &&\ + $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. && \ $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttools/src/linguist/lupdate INSTALL_ROOT=$($(package)_staging_dir) install_target && \ $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ if `test -f qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a`; then \ cp qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a $($(package)_staging_prefix_dir)/lib; \ diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk index 0c7c958d62d4..44110394bdda 100644 --- a/depends/packages/xcb_proto.mk +++ b/depends/packages/xcb_proto.mk @@ -1,6 +1,6 @@ package=xcb_proto $(package)_version=1.10 -$(package)_download_path=http://xcb.freedesktop.org/dist +$(package)_download_path=https://xcb.freedesktop.org/dist $(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 $(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05 diff --git a/depends/packages/xextproto.mk b/depends/packages/xextproto.mk index 65b6489c3348..157b76edf6fc 100644 --- a/depends/packages/xextproto.mk +++ b/depends/packages/xextproto.mk @@ -1,12 +1,11 @@ package=xextproto $(package)_version=7.3.0 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=f3f4b23ac8db9c3a9e0d8edb591713f3d70ef9c3b175970dd8823dfc92aa5bb0 -$(package)_patches=fix_aarch64_build.patch define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/fix_aarch64_build.patch + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . endef define $(package)_set_vars diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk index 50a90b26850a..23ad5ffa1088 100644 --- a/depends/packages/xproto.mk +++ b/depends/packages/xproto.mk @@ -1,6 +1,6 @@ package=xproto $(package)_version=7.0.26 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f @@ -8,6 +8,10 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk index 99eefa6d5ea2..67d2d976c413 100644 --- a/depends/packages/xtrans.mk +++ b/depends/packages/xtrans.mk @@ -1,6 +1,6 @@ package=xtrans $(package)_version=1.3.4 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc33544f583a $(package)_dependencies= @@ -9,6 +9,10 @@ define $(package)_set_vars $(package)_config_opts_linux=--with-pic --disable-static endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 3f97221e10ee..dfbc50580cb2 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,19 +1,20 @@ package=zeromq -$(package)_version=4.2.2 +$(package)_version=4.3.1 $(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=5b23f4ca9ef545d5bd3af55d305765e3ee06b986263b31967435d285a3e6df6b -$(package)_patches=0001-fix-build-with-older-mingw64.patch +$(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb +$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars - $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf + $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 endef define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/0001-fix-build-with-older-mingw64.patch && \ - ./autogen.sh + patch -p1 < $($(package)_patch_dir)/0002-disable-pthread_set_name_np.patch && \ + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config endef define $(package)_config_cmds diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index 589490800f8b..1600b11a01ec 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -1,6 +1,6 @@ package=zlib $(package)_version=1.2.11 -$(package)_download_path=http://www.zlib.net +$(package)_download_path=https://www.zlib.net $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 diff --git a/depends/patches/native_biplist/sorted_list.patch b/depends/patches/native_biplist/sorted_list.patch deleted file mode 100644 index 89abdb1b71ff..000000000000 --- a/depends/patches/native_biplist/sorted_list.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/biplist/__init__.py 2014-10-26 19:03:11.000000000 +0000 -+++ b/biplist/__init__.py 2016-07-19 19:30:17.663521999 +0000 -@@ -541,7 +541,7 @@ - return HashableWrapper(n) - elif isinstance(root, dict): - n = {} -- for key, value in iteritems(root): -+ for key, value in sorted(iteritems(root)): - n[self.wrapRoot(key)] = self.wrapRoot(value) - return HashableWrapper(n) - elif isinstance(root, list): -@@ -616,7 +616,7 @@ - elif isinstance(obj, dict): - size = proc_size(len(obj)) - self.incrementByteCount('dictBytes', incr=1+size) -- for key, value in iteritems(obj): -+ for key, value in sorted(iteritems(obj)): - check_key(key) - self.computeOffsets(key, asReference=True) - self.computeOffsets(value, asReference=True) -@@ -714,7 +714,7 @@ - keys = [] - values = [] - objectsToWrite = [] -- for key, value in iteritems(obj): -+ for key, value in sorted(iteritems(obj)): - keys.append(key) - values.append(value) - for key in keys: diff --git a/depends/patches/native_mac_alias/python3.patch b/depends/patches/native_mac_alias/python3.patch deleted file mode 100644 index 6f2f5534a275..000000000000 --- a/depends/patches/native_mac_alias/python3.patch +++ /dev/null @@ -1,56 +0,0 @@ -diff -dur a/mac_alias/alias.py b/mac_alias/alias.py ---- a/mac_alias/alias.py -+++ b/mac_alias/alias.py -@@ -258,10 +258,10 @@ - alias = Alias() - alias.appinfo = appinfo - -- alias.volume = VolumeInfo (volname.replace('/',':'), -+ alias.volume = VolumeInfo (volname.decode().replace('/',':'), - voldate, fstype, disktype, - volattrs, volfsid) -- alias.target = TargetInfo (kind, filename.replace('/',':'), -+ alias.target = TargetInfo (kind, filename.decode().replace('/',':'), - folder_cnid, cnid, - crdate, creator_code, type_code) - alias.target.levels_from = levels_from -@@ -276,9 +276,9 @@ - b.read(1) - - if tag == TAG_CARBON_FOLDER_NAME: -- alias.target.folder_name = value.replace('/',':') -+ alias.target.folder_name = value.decode().replace('/',':') - elif tag == TAG_CNID_PATH: -- alias.target.cnid_path = struct.unpack(b'>%uI' % (length // 4), -+ alias.target.cnid_path = struct.unpack('>%uI' % (length // 4), - value) - elif tag == TAG_CARBON_PATH: - alias.target.carbon_path = value -@@ -313,9 +313,9 @@ - alias.target.creation_date \ - = mac_epoch + datetime.timedelta(seconds=seconds) - elif tag == TAG_POSIX_PATH: -- alias.target.posix_path = value -+ alias.target.posix_path = value.decode() - elif tag == TAG_POSIX_PATH_TO_MOUNTPOINT: -- alias.volume.posix_path = value -+ alias.volume.posix_path = value.decode() - elif tag == TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE: - alias.volume.disk_image_alias = Alias.from_bytes(value) - elif tag == TAG_USER_HOME_LENGTH_PREFIX: -@@ -467,12 +467,12 @@ - - b.write(struct.pack(b'>hhQhhQ', - TAG_HIGH_RES_VOLUME_CREATION_DATE, -- 8, long(voldate * 65536), -+ 8, int(voldate * 65536), - TAG_HIGH_RES_CREATION_DATE, -- 8, long(crdate * 65536))) -+ 8, int(crdate * 65536))) - - if self.target.cnid_path: -- cnid_path = struct.pack(b'>%uI' % len(self.target.cnid_path), -+ cnid_path = struct.pack('>%uI' % len(self.target.cnid_path), - *self.target.cnid_path) - b.write(struct.pack(b'>hh', TAG_CNID_PATH, - len(cnid_path))) diff --git a/depends/patches/qt/aarch32-qmake.conf b/depends/patches/qt/aarch32-qmake.conf deleted file mode 100644 index da3f2990ca27..000000000000 --- a/depends/patches/qt/aarch32-qmake.conf +++ /dev/null @@ -1,24 +0,0 @@ -# -# qmake configuration for building with arm-linux-gnueabi-g++ -# - -MAKEFILE_GENERATOR = UNIX -CONFIG += incremental -QMAKE_INCREMENTAL_STYLE = sublib - -include(../common/linux.conf) -include(../common/gcc-base-unix.conf) -include(../common/g++-unix.conf) - -# modifications to g++.conf -QMAKE_CC = arm-linux-gnueabihf-gcc -QMAKE_CXX = arm-linux-gnueabihf-g++ -QMAKE_LINK = arm-linux-gnueabihf-g++ -QMAKE_LINK_SHLIB = arm-linux-gnueabihf-g++ - -# modifications to linux.conf -QMAKE_AR = arm-linux-gnueabihf-ar cqs -QMAKE_OBJCOPY = arm-linux-gnueabihf-objcopy -QMAKE_NM = arm-linux-gnueabihf-nm -P -QMAKE_STRIP = arm-linux-gnueabihf-strip -load(qt_config) diff --git a/depends/patches/qt/aarch64-qmake.conf b/depends/patches/qt/aarch64-qmake.conf deleted file mode 100644 index 8e68a66d8a16..000000000000 --- a/depends/patches/qt/aarch64-qmake.conf +++ /dev/null @@ -1,20 +0,0 @@ -MAKEFILE_GENERATOR = UNIX -CONFIG += incremental -QMAKE_INCREMENTAL_STYLE = sublib - -include(../common/linux.conf) -include(../common/gcc-base-unix.conf) -include(../common/g++-unix.conf) - -# modifications to g++.conf -QMAKE_CC = aarch64-linux-gnu-gcc -QMAKE_CXX = aarch64-linux-gnu-g++ -QMAKE_LINK = aarch64-linux-gnu-g++ -QMAKE_LINK_SHLIB = aarch64-linux-gnu-g++ - -# modifications to linux.conf -QMAKE_AR = aarch64-linux-gnu-ar cqs -QMAKE_OBJCOPY = aarch64-linux-gnu-objcopy -QMAKE_NM = aarch64-linux-gnu-nm -P -QMAKE_STRIP = aarch64-linux-gnu-strip -load(qt_config) diff --git a/depends/patches/qt/fix-xcb-include-order.patch b/depends/patches/qt/fix-xcb-include-order.patch deleted file mode 100644 index ec2bc17d9bd9..000000000000 --- a/depends/patches/qt/fix-xcb-include-order.patch +++ /dev/null @@ -1,49 +0,0 @@ ---- old/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17 -+++ new/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17 -@@ -76,8 +76,6 @@ - - DEFINES += $$QMAKE_DEFINES_XCB - LIBS += $$QMAKE_LIBS_XCB --QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB --QMAKE_CFLAGS += $$QMAKE_CFLAGS_XCB - - CONFIG += qpa/genericunixfontdatabase - -@@ -89,7 +87,8 @@ - contains(QT_CONFIG, xcb-qt) { - DEFINES += XCB_USE_RENDER - XCB_DIR = ../../../3rdparty/xcb -- INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude -+ QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB -+ QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB - LIBS += -lxcb -L$$MODULE_BASE_OUTDIR/lib -lxcb-static$$qtPlatformTargetSuffix() - } else { - LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms -lxcb-xinerama ---- old/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro -+++ new/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro -@@ -9,7 +9,8 @@ - - XCB_DIR = ../../../../3rdparty/xcb - --INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/include/xcb $$XCB_DIR/sysinclude -+QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/include/xcb -I$$XCB_DIR/sysinclude -+QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/include/xcb -I$$XCB_DIR/sysinclude - - QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB - QMAKE_CFLAGS += $$QMAKE_CFLAGS_XCB ---- old/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro -+++ new/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro -@@ -6,6 +6,13 @@ - qxcbmain.cpp - OTHER_FILES += xcb.json README - -+contains(QT_CONFIG, xcb-qt) { -+ DEFINES += XCB_USE_RENDER -+ XCB_DIR = ../../../3rdparty/xcb -+ QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB -+ QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB -+} -+ - PLUGIN_TYPE = platforms - PLUGIN_CLASS_NAME = QXcbIntegrationPlugin - !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - diff --git a/depends/patches/qt/fix_configure_mac.patch b/depends/patches/qt/fix_configure_mac.patch new file mode 100644 index 000000000000..0d7dd647debc --- /dev/null +++ b/depends/patches/qt/fix_configure_mac.patch @@ -0,0 +1,50 @@ +--- old/qtbase/mkspecs/features/mac/sdk.prf 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/mkspecs/features/mac/sdk.prf 2018-03-23 10:38:56.000000000 -0700 +@@ -8,21 +8,21 @@ + defineReplace(xcodeSDKInfo) { + info = $$1 + equals(info, "Path"): \ +- info = --show-sdk-path ++ infoarg = --show-sdk-path + equals(info, "PlatformPath"): \ +- info = --show-sdk-platform-path ++ infoarg = --show-sdk-platform-path + equals(info, "SDKVersion"): \ +- info = --show-sdk-version ++ infoarg = --show-sdk-version + sdk = $$2 + isEmpty(sdk): \ + sdk = $$QMAKE_MAC_SDK + + isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}) { +- QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$info 2>/dev/null") ++ QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$infoarg 2>/dev/null") + # --show-sdk-platform-path won't work for Command Line Tools; this is fine + # only used by the XCTest backend to testlib +- isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(info, "--show-sdk-platform-path")): \ +- error("Could not resolve SDK $$info for \'$$sdk\'") ++ isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(infoarg, "--show-sdk-platform-path")): \ ++ error("Could not resolve SDK $$info for \'$$sdk\' using $$infoarg") + cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info}) + } + +--- old/qtbase/configure 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/configure 2018-03-23 05:42:29.000000000 -0700 +@@ -232,8 +232,13 @@ + + sdk=$(getSingleQMakeVariable "QMAKE_MAC_SDK" "$1") + if [ -z "$sdk" ]; then echo "QMAKE_MAC_SDK must be set when building on Mac" >&2; exit 1; fi +- sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) +- if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ sysroot=$(getSingleQMakeVariable "QMAKE_MAC_SDK_PATH" "$1") ++ ++ echo "sysroot pre-configured as $sysroot"; ++ if [ -z "$sysroot" ]; then ++ sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) ++ if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ fi + + case "$sdk" in + macosx*) + + diff --git a/depends/patches/qt/fix_no_printer.patch b/depends/patches/qt/fix_no_printer.patch new file mode 100644 index 000000000000..f868ca257755 --- /dev/null +++ b/depends/patches/qt/fix_no_printer.patch @@ -0,0 +1,19 @@ +--- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h ++++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h +@@ -52,6 +52,7 @@ + // + + #include ++#include + + #ifndef QT_NO_PRINTER + +--- x/qtbase/src/plugins/plugins.pro ++++ y/qtbase/src/plugins/plugins.pro +@@ -8,6 +8,3 @@ qtHaveModule(gui) { + qtConfig(imageformatplugin): SUBDIRS *= imageformats + !android:qtConfig(library): SUBDIRS *= generic + } +- +-!winrt:qtHaveModule(printsupport): \ +- SUBDIRS += printsupport diff --git a/depends/patches/qt/fix_rcc_determinism.patch b/depends/patches/qt/fix_rcc_determinism.patch new file mode 100644 index 000000000000..c1b07fe23afd --- /dev/null +++ b/depends/patches/qt/fix_rcc_determinism.patch @@ -0,0 +1,15 @@ +--- old/qtbase/src/tools/rcc/rcc.cpp ++++ new/qtbase/src/tools/rcc/rcc.cpp +@@ -207,7 +207,11 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) + if (lib.formatVersion() >= 2) { + // last modified time stamp + const QDateTime lastModified = m_fileInfo.lastModified(); +- lib.writeNumber8(quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0)); ++ quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0); ++ static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong(); ++ if (sourceDate != 0) ++ lastmod = sourceDate; ++ lib.writeNumber8(lastmod); + if (text || pass1) + lib.writeChar('\n'); + } diff --git a/depends/patches/qt/fix_riscv64_arch.patch b/depends/patches/qt/fix_riscv64_arch.patch new file mode 100644 index 000000000000..e7f29f01f9cd --- /dev/null +++ b/depends/patches/qt/fix_riscv64_arch.patch @@ -0,0 +1,14 @@ +diff --git a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h +index 20bfd36..93729fa 100644 +--- a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h ++++ b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h +@@ -65,7 +65,8 @@ + defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ + defined(__SH4__) || defined(__alpha__) || \ + defined(_MIPS_ARCH_MIPS32R2) || \ +- defined(__AARCH64EL__) ++ defined(__AARCH64EL__) || defined(__aarch64__) || \ ++ defined(__riscv) + #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 + #elif defined(_M_IX86) || defined(__i386__) || defined(__i386) + #if defined(_WIN32) diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt/mac-qmake.conf index 236988fd1521..337d0eb9caf6 100644 --- a/depends/patches/qt/mac-qmake.conf +++ b/depends/patches/qt/mac-qmake.conf @@ -1,7 +1,6 @@ MAKEFILE_GENERATOR = UNIX CONFIG += app_bundle incremental global_init_link_order lib_version_first plugin_no_soname absolute_library_soname QMAKE_INCREMENTAL_STYLE = sublib -QMAKE_APPLE_DEVICE_ARCHS = x86_64 include(../common/macx.conf) include(../common/gcc-base-mac.conf) include(../common/clang.conf) @@ -9,12 +8,13 @@ include(../common/clang-mac.conf) QMAKE_MAC_SDK_PATH=$${MAC_SDK_PATH} QMAKE_XCODE_VERSION=4.3 QMAKE_XCODE_DEVELOPER_PATH=/Developer +QMAKE_MACOSX_DEPLOYMENT_TARGET = $${MAC_MIN_VERSION} QMAKE_MAC_SDK=macosx QMAKE_MAC_SDK.macosx.Path = $${MAC_SDK_PATH} QMAKE_MAC_SDK.macosx.platform_name = macosx QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION} QMAKE_MAC_SDK.macosx.PlatformPath = /phony -QMAKE_MACOSX_DEPLOYMENT_TARGET = $${MAC_MIN_VERSION} +QMAKE_APPLE_DEVICE_ARCHS=x86_64 !host_build: QMAKE_CFLAGS += -target $${MAC_TARGET} !host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS !host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS diff --git a/depends/patches/qt/mingw-uuidof.patch b/depends/patches/qt/mingw-uuidof.patch deleted file mode 100644 index fb21923c8c36..000000000000 --- a/depends/patches/qt/mingw-uuidof.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- old/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp -+++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp -@@ -77,7 +77,7 @@ - #include - #include - #include --#ifndef Q_OS_WINCE -+#if !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) - # include - #endif - -@@ -814,7 +814,7 @@ - HWND_MESSAGE, NULL, static_cast(GetModuleHandle(0)), NULL); - } - --#ifndef Q_OS_WINCE -+#if !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) - // Re-engineered from the inline function _com_error::ErrorMessage(). - // We cannot use it directly since it uses swprintf_s(), which is not - // present in the MSVCRT.DLL found on Windows XP (QTBUG-35617). -@@ -833,7 +833,7 @@ - return QString::asprintf("IDispatch error #%u", uint(wCode)); - return QString::asprintf("Unknown error 0x0%x", uint(comError.Error())); - } --#endif // !Q_OS_WINCE -+#endif // !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) - - /*! - \brief Common COM error strings. -@@ -901,12 +901,12 @@ - default: - break; - } --#ifndef Q_OS_WINCE -+#if !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) - _com_error error(hr); - result += QByteArrayLiteral(" ("); - result += errorMessageFromComError(error); - result += ')'; --#endif // !Q_OS_WINCE -+#endif // !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) - return result; - } - diff --git a/depends/patches/qt/pidlist_absolute.patch b/depends/patches/qt/pidlist_absolute.patch deleted file mode 100644 index c79282417905..000000000000 --- a/depends/patches/qt/pidlist_absolute.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h ---- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h -+++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h -@@ -136,10 +136,18 @@ - inline void init(); - - typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); -+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) -+ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, ITEMIDLIST **); -+#else - typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *); -+#endif - typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); - typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); -+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) -+ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(const ITEMIDLIST *, REFIID, void **); -+#else - typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **); -+#endif - - SHCreateItemFromParsingName sHCreateItemFromParsingName; - SHGetKnownFolderIDList sHGetKnownFolderIDList; -diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp ---- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -+++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -@@ -1016,7 +1016,11 @@ - qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path(); - return Q_NULLPTR; - } -+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) -+ ITEMIDLIST *idList; -+#else - PIDLIST_ABSOLUTE idList; -+#endif - HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList); - if (FAILED(hr)) { - qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString())); diff --git a/depends/patches/qt/xkb-default.patch b/depends/patches/qt/xkb-default.patch new file mode 100644 index 000000000000..165abf3e2e7a --- /dev/null +++ b/depends/patches/qt/xkb-default.patch @@ -0,0 +1,26 @@ +--- old/qtbase/src/gui/configure.pri 2018-06-06 17:28:10.000000000 -0400 ++++ new/qtbase/src/gui/configure.pri 2018-08-17 18:43:01.589384567 -0400 +@@ -43,18 +43,11 @@ + } + + defineTest(qtConfTest_xkbConfigRoot) { +- qtConfTest_getPkgConfigVariable($${1}): return(true) +- +- for (dir, $$list("/usr/share/X11/xkb", "/usr/local/share/X11/xkb")) { +- exists($$dir) { +- $${1}.value = $$dir +- export($${1}.value) +- $${1}.cache += value +- export($${1}.cache) +- return(true) +- } +- } +- return(false) ++ $${1}.value = "/usr/share/X11/xkb" ++ export($${1}.value) ++ $${1}.cache += value ++ export($${1}.cache) ++ return(true) + } + + defineTest(qtConfTest_qpaDefaultPlatform) { diff --git a/depends/patches/xextproto/fix_aarch64_build.patch b/depends/patches/xextproto/fix_aarch64_build.patch deleted file mode 100644 index 372bbe5a165a..000000000000 --- a/depends/patches/xextproto/fix_aarch64_build.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- old/config.sub 2010-12-06 19:52:05.000000000 -0800 -+++ new/config.sub 2017-03-10 14:46:55.525827000 -0800 -@@ -246,6 +246,7 @@ - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ -+ | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ -@@ -328,6 +329,7 @@ - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ -+ | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ - ---- old/config.guess 2010-12-06 19:52:05.000000000 -0800 -+++ new/config.guess 2017-03-10 14:50:10.221827000 -0800 -@@ -858,6 +858,13 @@ - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; -+ aarch64:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; -+ aarch64_be:Linux:*:*) -+ UNAME_MACHINE=aarch64_be -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; diff --git a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch index a6c508fb8a1e..b911ac56724b 100644 --- a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch +++ b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch @@ -1,6 +1,6 @@ -From 1a159c128c69a42d90819375c06a39994f3fbfc1 Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Tue, 28 Nov 2017 20:33:25 -0500 +From f6866b0f166ad168618aae64c7fbee8775d3eb23 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:44:58 -0400 Subject: [PATCH] fix build with older mingw64 --- @@ -8,10 +8,10 @@ Subject: [PATCH] fix build with older mingw64 1 file changed, 7 insertions(+) diff --git a/src/windows.hpp b/src/windows.hpp -index 99e889d..e69038e 100644 +index 6c3839fd..2c32ec79 100644 --- a/src/windows.hpp +++ b/src/windows.hpp -@@ -55,6 +55,13 @@ +@@ -58,6 +58,13 @@ #include #include #include @@ -23,8 +23,8 @@ index 99e889d..e69038e 100644 +#include +#endif #include - + #if !defined __MINGW32__ --- -2.7.4 +-- +2.17.1 diff --git a/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch new file mode 100644 index 000000000000..022e311977e7 --- /dev/null +++ b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch @@ -0,0 +1,35 @@ +From c9bbdd6581d07acfe8971e4bcebe278a3676cf03 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:57:18 -0400 +Subject: [PATCH] disable pthread_set_name_np + +pthread_set_name_np adds a Glibc requirement on >= 2.12. +--- + src/thread.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/thread.cpp b/src/thread.cpp +index a1086b0c..9943f354 100644 +--- a/src/thread.cpp ++++ b/src/thread.cpp +@@ -307,7 +307,7 @@ void zmq::thread_t::setThreadName (const char *name_) + */ + if (!name_) + return; +- ++#if 0 + #if defined(ZMQ_HAVE_PTHREAD_SETNAME_1) + int rc = pthread_setname_np (name_); + if (rc) +@@ -323,6 +323,8 @@ void zmq::thread_t::setThreadName (const char *name_) + #elif defined(ZMQ_HAVE_PTHREAD_SET_NAME) + pthread_set_name_np (descriptor, name_); + #endif ++#endif ++ return; + } + + #endif +-- +2.17.1 + diff --git a/doc/build-unix.md b/doc/build-unix.md index 9a25ca326010..f7ca2558dcb9 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -59,7 +59,7 @@ Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- Build requirements: - sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev + sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev automake For Ubuntu 12.04 and later or Debian 7 and later libboost-all-dev has to be installed: diff --git a/doc/keepass.md b/doc/keepass.md index ecdde1a97907..fb88499be20d 100644 --- a/doc/keepass.md +++ b/doc/keepass.md @@ -7,7 +7,7 @@ KeePass integration use KeePassHttp (https://github.com/pfn/keepasshttp/) to fac The implementation is dependent on the following: - crypter.h for AES encryption helper functions. - - rpcprotocol.h for handling RPC communications. Could only be used partially however due some static values in the code. + - rpc/protocol.h for handling RPC communications. Could only be used partially however due some static values in the code. - OpenSSL for base64 encoding. regular util.h libraries were not used for base64 encoding/decoding since they do not use secure allocation. - JSON Spirit for reading / writing RPC communications diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am new file mode 100644 index 000000000000..3637ce6be1d7 --- /dev/null +++ b/doc/man/Makefile.am @@ -0,0 +1,13 @@ +dist_man1_MANS= + +if BUILD_BITCOIND + dist_man1_MANS+=phored.1 +endif + +if ENABLE_QT + dist_man1_MANS+=phore-qt.1 +endif + +if BUILD_BITCOIN_UTILS + dist_man1_MANS+=phore-cli.1 phore-tx.1 +endif diff --git a/doc/man/phore-cli.1 b/doc/man/phore-cli.1 new file mode 100644 index 000000000000..60477f9bc6e0 --- /dev/null +++ b/doc/man/phore-cli.1 @@ -0,0 +1,78 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH PHORE-CLI "1" "July 2018" "phore-cli v3.1.99.0" "User Commands" +.SH NAME +phore-cli \- manual page for phore-cli v3.1.99.0 +.SH DESCRIPTION +PHORE Core RPC client version v3.1.99.0\-11f4a2bba4\-dirty +.SS "Usage:" +.TP +phore\-cli [options] [params] +Send command to PHORE Core +.TP +phore\-cli [options] help +List commands +.TP +phore\-cli [options] help +Get help for a command +.SH OPTIONS +.HP +\-? +.IP +This help message +.HP +\fB\-conf=\fR +.IP +Specify configuration file (default: phore.conf) +.HP +\fB\-datadir=\fR +.IP +Specify data directory +.HP +\fB\-testnet\fR +.IP +Use the test network +.HP +\fB\-regtest\fR +.IP +Enter regression test mode, which uses a special chain in which blocks +can be solved instantly. This is intended for regression testing tools +and app development. +.HP +\fB\-rpcconnect=\fR +.IP +Send commands to node running on (default: 127.0.0.1) +.HP +\fB\-rpcport=\fR +.IP +Connect to JSON\-RPC on (default: 51473 or testnet: 51475) +.HP +\fB\-rpcwait\fR +.IP +Wait for RPC server to start +.HP +\fB\-rpcuser=\fR +.IP +Username for JSON\-RPC connections +.HP +\fB\-rpcpassword=\fR +.IP +Password for JSON\-RPC connections +.HP +\fB\-rpcclienttimeout=\fR +.IP +Timeout during HTTP requests (default: 900) +.SH COPYRIGHT +Copyright (C) 2009-2018 The Bitcoin Core Developers + +Copyright (C) 2014-2018 The Dash Core Developers + +Copyright (C) 2015-2018 The PHORE Core Developers + +This is experimental software. + +Distributed under the MIT software license, see the accompanying file COPYING +or . + +This product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit and cryptographic software written +by Eric Young and UPnP software written by Thomas Bernard. diff --git a/doc/man/phore-qt.1 b/doc/man/phore-qt.1 new file mode 100644 index 000000000000..d69e13d88d90 --- /dev/null +++ b/doc/man/phore-qt.1 @@ -0,0 +1,576 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH PHORE-QT "1" "July 2018" "phore-qt v3.1.99.0" "User Commands" +.SH NAME +phore-qt \- manual page for phore-qt v3.1.99.0 +.SH DESCRIPTION +PHORE Core version v3.1.99.0\-11f4a2bba4\-dirty (64\-bit) +Usage: +.IP +phore\-qt [command\-line options] +.SH OPTIONS +.HP +\-? +.IP +This help message +.HP +\fB\-version\fR +.IP +Print version and exit +.HP +\fB\-alertnotify=\fR +.IP +Execute command when a relevant alert is received or we see a really +long fork (%s in cmd is replaced by message) +.HP +\fB\-alerts\fR +.IP +Receive and display P2P network alerts (default: 1) +.HP +\fB\-blocknotify=\fR +.IP +Execute command when the best block changes (%s in cmd is replaced by +block hash) +.HP +\fB\-blocksizenotify=\fR +.IP +Execute command when the best block changes and its size is over (%s in +cmd is replaced by block hash, %d with the block size) +.HP +\fB\-checkblocks=\fR +.IP +How many blocks to check at startup (default: 500, 0 = all) +.HP +\fB\-conf=\fR +.IP +Specify configuration file (default: phore.conf) +.HP +\fB\-datadir=\fR +.IP +Specify data directory +.HP +\fB\-dbcache=\fR +.IP +Set database cache size in megabytes (4 to 4096, default: 100) +.HP +\fB\-loadblock=\fR +.IP +Imports blocks from external blk000??.dat file on startup +.HP +\fB\-maxreorg=\fR +.IP +Set the Maximum reorg depth (default: 100) +.HP +\fB\-maxorphantx=\fR +.IP +Keep at most unconnectable transactions in memory (default: 100) +.HP +\fB\-par=\fR +.IP +Set the number of script verification threads (\fB\-8\fR to 16, 0 = auto, <0 = +leave that many cores free, default: 0) +.HP +\fB\-pid=\fR +.IP +Specify pid file (default: phored.pid) +.HP +\fB\-reindex\fR +.IP +Rebuild block chain index from current blk000??.dat files on startup +.HP +\fB\-reindexaccumulators\fR +.IP +Reindex the accumulator database on startup +.HP +\fB\-reindexmoneysupply\fR +.IP +Reindex the PHR and zPHR money supply statistics on startup +.HP +\fB\-resync\fR +.IP +Delete blockchain folders and resync from scratch on startup +.HP +\fB\-sysperms\fR +.IP +Create new files with system default permissions, instead of umask 077 +(only effective with disabled wallet functionality) +.HP +\fB\-txindex\fR +.IP +Maintain a full transaction index, used by the getrawtransaction rpc +call (default: 0) +.HP +\fB\-forcestart\fR +.IP +Attempt to force blockchain corruption recovery on startup +.PP +Connection options: +.HP +\fB\-addnode=\fR +.IP +Add a node to connect to and attempt to keep the connection open +.HP +\fB\-banscore=\fR +.IP +Threshold for disconnecting misbehaving peers (default: 100) +.HP +\fB\-bantime=\fR +.IP +Number of seconds to keep misbehaving peers from reconnecting (default: +86400) +.HP +\fB\-bind=\fR +.IP +Bind to given address and always listen on it. Use [host]:port notation +for IPv6 +.HP +\fB\-connect=\fR +.IP +Connect only to the specified node(s) +.HP +\fB\-discover\fR +.IP +Discover own IP address (default: 1 when listening and no \fB\-externalip\fR) +.HP +\fB\-dns\fR +.IP +Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1) +.HP +\fB\-dnsseed\fR +.IP +Query for peer addresses via DNS lookup, if low on addresses (default: 1 +unless \fB\-connect\fR) +.HP +\fB\-externalip=\fR +.IP +Specify your own public address +.HP +\fB\-forcednsseed\fR +.IP +Always query for peer addresses via DNS lookup (default: 0) +.HP +\fB\-listen\fR +.IP +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) +.HP +\fB\-listenonion\fR +.IP +Automatically create Tor hidden service (default: 1) +.HP +\fB\-maxconnections=\fR +.IP +Maintain at most connections to peers (default: 125) +.HP +\fB\-maxreceivebuffer=\fR +.IP +Maximum per\-connection receive buffer, *1000 bytes (default: 5000) +.HP +\fB\-maxsendbuffer=\fR +.IP +Maximum per\-connection send buffer, *1000 bytes (default: 1000) +.HP +\fB\-onion=\fR +.IP +Use separate SOCKS5 proxy to reach peers via Tor hidden services +(default: \fB\-proxy\fR) +.HP +\fB\-onlynet=\fR +.IP +Only connect to nodes in network (ipv4, ipv6 or onion) +.HP +\fB\-permitbaremultisig\fR +.IP +Relay non\-P2SH multisig (default: 1) +.HP +\fB\-peerbloomfilters\fR +.IP +Support filtering of blocks and transaction with bloom filters (default: +1) +.HP +\fB\-port=\fR +.IP +Listen for connections on (default: 51472 or testnet: 51474) +.HP +\fB\-proxy=\fR +.IP +Connect through SOCKS5 proxy +.HP +\fB\-proxyrandomize\fR +.IP +Randomize credentials for every proxy connection. This enables Tor +stream isolation (default: 1) +.HP +\fB\-seednode=\fR +.IP +Connect to a node to retrieve peer addresses, and disconnect +.HP +\fB\-timeout=\fR +.IP +Specify connection timeout in milliseconds (minimum: 1, default: 5000) +.HP +\fB\-torcontrol=\fR: +.IP +Tor control port to use if onion listening enabled (default: +127.0.0.1:9051) +.HP +\fB\-torpassword=\fR +.IP +Tor control port password (default: empty) +.HP +\fB\-upnp\fR +.IP +Use UPnP to map the listening port (default: 0) +.HP +\fB\-whitebind=\fR +.IP +Bind to given address and whitelist peers connecting to it. Use +[host]:port notation for IPv6 +.HP +\fB\-whitelist=\fR +.IP +Whitelist peers connecting from the given netmask or IP address. Can be +specified multiple times. Whitelisted peers cannot be DoS banned and +their transactions are always relayed, even if they are already in the +mempool, useful e.g. for a gateway +.PP +Wallet options: +.HP +\fB\-backuppath=\fR +.IP +Specify custom backup path to add a copy of any wallet backup. If set as +dir, every backup generates a timestamped file. If set as file, will +rewrite to that file every backup. +.HP +\fB\-createwalletbackups=\fR +.IP +Number of automatic wallet backups (default: 10) +.HP +\fB\-custombackupthreshold=\fR +.IP +Number of custom location backups to retain (default: 1) +.HP +\fB\-disablewallet\fR +.IP +Do not load the wallet and disable wallet RPC calls +.HP +\fB\-keypool=\fR +.IP +Set key pool size to (default: 100) +.HP +\fB\-paytxfee=\fR +.IP +Fee (in PHR/Kb) to add to transactions you send (default: 0.00) +.HP +\fB\-rescan\fR +.IP +Rescan the block chain for missing wallet transactions on startup +.HP +\fB\-salvagewallet\fR +.IP +Attempt to recover private keys from a corrupt wallet.dat on startup +.HP +\fB\-sendfreetransactions\fR +.IP +Send transactions as zero\-fee transactions if possible (default: 0) +.HP +\fB\-spendzeroconfchange\fR +.IP +Spend unconfirmed change when sending transactions (default: 1) +.HP +\fB\-disablesystemnotifications\fR +.IP +Disable OS notifications for incoming transactions (default: 0) +.HP +\fB\-txconfirmtarget=\fR +.IP +If paytxfee is not set, include enough fee so transactions begin +confirmation on average within n blocks (default: 1) +.HP +\fB\-maxtxfee=\fR +.IP +Maximum total fees to use in a single wallet transaction, setting too +low may abort large transactions (default: 1.00) +.HP +\fB\-upgradewallet\fR +.IP +Upgrade wallet to latest format on startup +.HP +\fB\-wallet=\fR +.IP +Specify wallet file (within data directory) (default: wallet.dat) +.HP +\fB\-walletnotify=\fR +.IP +Execute command when a wallet transaction changes (%s in cmd is replaced +by TxID) +.HP +\fB\-windowtitle=\fR +.IP +Wallet window title +.HP +\fB\-zapwallettxes=\fR +.IP +Delete all wallet transactions and only recover those parts of the +blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g. +account owner and payment request information, 2 = drop tx meta data) +.PP +ZeroMQ notification options: +.HP +\fB\-zmqpubhashblock=\fR
+.IP +Enable publish hash block in
+.HP +\fB\-zmqpubhashtx=\fR
+.IP +Enable publish hash transaction in
+.HP +\fB\-zmqpubhashtxlock=\fR
+.IP +Enable publish hash transaction (locked via SwiftX) in
+.HP +\fB\-zmqpubrawblock=\fR
+.IP +Enable publish raw block in
+.HP +\fB\-zmqpubrawtx=\fR
+.IP +Enable publish raw transaction in
+.HP +\fB\-zmqpubrawtxlock=\fR
+.IP +Enable publish raw transaction (locked via SwiftX) in
+.PP +Debugging/Testing options: +.HP +\fB\-debug=\fR +.IP +Output debugging information (default: 0, supplying is +optional). If is not supplied, output all debugging +information. can be: addrman, alert, bench, coindb, db, lock, +rand, rpc, selectcoins, tor, mempool, net, proxy, http, libevent, phore, +(obfuscation, swiftx, masternode, mnpayments, mnbudget, zero), qt. +.HP +\fB\-gen\fR +.IP +Generate coins (default: 0) +.HP +\fB\-genproclimit=\fR +.IP +Set the number of threads for coin generation if enabled (\fB\-1\fR = all +cores, default: 1) +.HP +\fB\-help\-debug\fR +.IP +Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR) +.HP +\fB\-logips\fR +.IP +Include IP addresses in debug output (default: 0) +.HP +\fB\-logtimestamps\fR +.IP +Prepend debug output with timestamp (default: 1) +.HP +\fB\-minrelaytxfee=\fR +.IP +Fees (in PHR/Kb) smaller than this are considered zero fee for relaying +(default: 0.0001) +.HP +\fB\-printtoconsole\fR +.IP +Send trace/debug info to console instead of debug.log file (default: 0) +.HP +\fB\-shrinkdebugfile\fR +.IP +Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR) +.HP +\fB\-testnet\fR +.IP +Use the test network +.HP +\fB\-litemode=\fR +.IP +Disable all PHORE specific functionality (Masternodes, Zerocoin, SwiftX, +Budgeting) (0\-1, default: 0) +.PP +Staking options: +.HP +\fB\-staking=\fR +.IP +Enable staking functionality (0\-1, default: 1) +.HP +\fB\-phrstake=\fR +.IP +Enable or disable staking functionality for PHR inputs (0\-1, default: 1) +.HP +\fB\-reservebalance=\fR +.IP +Keep the specified amount available for spending at all times (default: +0) +.PP +Masternode options: +.HP +\fB\-masternode=\fR +.IP +Enable the client to act as a masternode (0\-1, default: 0) +.HP +\fB\-mnconf=\fR +.IP +Specify masternode configuration file (default: masternode.conf) +.HP +\fB\-mnconflock=\fR +.IP +Lock masternodes from masternode configuration file (default: 1) +.HP +\fB\-masternodeprivkey=\fR +.IP +Set the masternode private key +.HP +\fB\-masternodeaddr=\fR +.IP +Set external address:port to get to this masternode (example: +128.127.106.235:51472) +.HP +\fB\-budgetvotemode=\fR +.IP +Change automatic finalized budget voting behavior. mode=auto: Vote for +only exact finalized budget match to my generated budget. (string, +default: auto) +.PP +Zerocoin options: +.HP +\fB\-enablezeromint=\fR +.IP +Enable automatic Zerocoin minting (0\-1, default: 1) +.HP +\fB\-zeromintpercentage=\fR +.IP +Percentage of automatically minted Zerocoin (1\-100, default: 10) +.HP +\fB\-preferredDenom=\fR +.IP +Preferred Denomination for automatically minted Zerocoin +(1/5/10/50/100/500/1000/5000), 0 for no preference. default: 0) +.HP +\fB\-reindexzerocoin=\fR +.IP +Delete all zerocoin spends and mints that have been recorded to the +blockchain database and reindex them (0\-1, default: 0) +.PP +SwiftX options: +.HP +\fB\-enableswifttx=\fR +.IP +Enable SwiftX, show confirmations for locked transactions (bool, +default: true) +.HP +\fB\-swifttxdepth=\fR +.IP +Show N confirmations for a successfully locked transaction (0\-9999, +default: 5) +.PP +Node relay options: +.HP +\fB\-datacarrier\fR +.IP +Relay and mine data carrier transactions (default: 1) +.HP +\fB\-datacarriersize\fR +.IP +Maximum size of data in data carrier transactions we relay and mine +(default: 83) +.PP +Block creation options: +.HP +\fB\-blockminsize=\fR +.IP +Set minimum block size in bytes (default: 0) +.HP +\fB\-blockmaxsize=\fR +.IP +Set maximum block size in bytes (default: 750000) +.HP +\fB\-blockprioritysize=\fR +.IP +Set maximum size of high\-priority/low\-fee transactions in bytes +(default: 50000) +.PP +RPC server options: +.HP +\fB\-server\fR +.IP +Accept command line and JSON\-RPC commands +.HP +\fB\-rest\fR +.IP +Accept public REST requests (default: 0) +.HP +\fB\-rpcbind=\fR +.IP +Bind to given address to listen for JSON\-RPC connections. Use +[host]:port notation for IPv6. This option can be specified multiple +times (default: bind to all interfaces) +.HP +\fB\-rpccookiefile=\fR +.IP +Location of the auth cookie (default: data dir) +.HP +\fB\-rpcuser=\fR +.IP +Username for JSON\-RPC connections +.HP +\fB\-rpcpassword=\fR +.IP +Password for JSON\-RPC connections +.HP +\fB\-rpcport=\fR +.IP +Listen for JSON\-RPC connections on (default: 51473 or testnet: +51475) +.HP +\fB\-rpcallowip=\fR +.IP +Allow JSON\-RPC connections from specified source. Valid for are a +single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) +or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified +multiple times +.HP +\fB\-rpcthreads=\fR +.IP +Set the number of threads to service RPC calls (default: 4) +.PP +UI Options: +.HP +\fB\-choosedatadir\fR +.IP +Choose data directory on startup (default: 0) +.HP +\fB\-lang=\fR +.IP +Set language, for example "de_DE" (default: system locale) +.HP +\fB\-min\fR +.IP +Start minimized +.HP +\fB\-rootcertificates=\fR +.IP +Set SSL root certificates for payment request (default: \fB\-system\-\fR) +.HP +\fB\-splash\fR +.IP +Show splash screen on startup (default: 1) +.SH COPYRIGHT +Copyright (C) 2009-2018 The Bitcoin Core Developers + +Copyright (C) 2014-2018 The Dash Core Developers + +Copyright (C) 2015-2018 The PHORE Core Developers + +This is experimental software. + +Distributed under the MIT software license, see the accompanying file COPYING +or . + +This product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit and cryptographic software written +by Eric Young and UPnP software written by Thomas Bernard. diff --git a/doc/man/phore-tx.1 b/doc/man/phore-tx.1 new file mode 100644 index 000000000000..a749d5aa3afb --- /dev/null +++ b/doc/man/phore-tx.1 @@ -0,0 +1,100 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH PHORE-TX "1" "July 2018" "phore-tx v3.1.99.0" "User Commands" +.SH NAME +phore-tx \- manual page for phore-tx v3.1.99.0 +.SH DESCRIPTION +Phore Core phore\-tx utility version v3.1.99.0\-11f4a2bba4\-dirty +.SS "Usage:" +.TP +phore\-tx [options] [commands] +Update hex\-encoded phore transaction +.TP +phore\-tx [options] \fB\-create\fR [commands] +Create hex\-encoded phore transaction +.SH OPTIONS +.HP +\-? +.IP +This help message +.HP +\fB\-create\fR +.IP +Create new, empty TX. +.HP +\fB\-json\fR +.IP +Select JSON output +.HP +\fB\-txid\fR +.IP +Output only the hex\-encoded transaction id of the resultant transaction. +.HP +\fB\-regtest\fR +.IP +Enter regression test mode, which uses a special chain in which blocks +can be solved instantly. +.HP +\fB\-testnet\fR +.IP +Use the test network +.PP +Commands: +.IP +delin=N +.IP +Delete input N from TX +.IP +delout=N +.IP +Delete output N from TX +.IP +in=TXID:VOUT +.IP +Add input to TX +.IP +locktime=N +.IP +Set TX lock time to N +.IP +nversion=N +.IP +Set TX version to N +.IP +outaddr=VALUE:ADDRESS +.IP +Add address\-based output to TX +.IP +outscript=VALUE:SCRIPT +.IP +Add raw script output to TX +.IP +sign=SIGHASH\-FLAGS +.IP +Add zero or more signatures to transaction. This command requires JSON +registers:prevtxs=JSON object, privatekeys=JSON object. See +signrawtransaction docs for format of sighash flags, JSON objects. +.PP +Register Commands: +.IP +load=NAME:FILENAME +.IP +Load JSON file FILENAME into register NAME +.IP +set=NAME:JSON\-STRING +.IP +Set register NAME to given JSON\-STRING +.SH COPYRIGHT +Copyright (C) 2009-2018 The Bitcoin Core Developers + +Copyright (C) 2014-2018 The Dash Core Developers + +Copyright (C) 2015-2018 The PHORE Core Developers + +This is experimental software. + +Distributed under the MIT software license, see the accompanying file COPYING +or . + +This product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit and cryptographic software written +by Eric Young and UPnP software written by Thomas Bernard. diff --git a/doc/man/phored.1 b/doc/man/phored.1 new file mode 100644 index 000000000000..b301b51395ff --- /dev/null +++ b/doc/man/phored.1 @@ -0,0 +1,567 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH PHORED "1" "July 2018" "phored v3.1.99.0" "User Commands" +.SH NAME +phored \- manual page for phored v3.1.99.0 +.SH DESCRIPTION +Phore Core Daemon version v3.1.99.0\-11f4a2bba4\-dirty +.SS "Usage:" +.TP +phored [options] +Start Phore Core Daemon +.SH OPTIONS +.HP +\-? +.IP +This help message +.HP +\fB\-version\fR +.IP +Print version and exit +.HP +\fB\-alertnotify=\fR +.IP +Execute command when a relevant alert is received or we see a really +long fork (%s in cmd is replaced by message) +.HP +\fB\-alerts\fR +.IP +Receive and display P2P network alerts (default: 1) +.HP +\fB\-blocknotify=\fR +.IP +Execute command when the best block changes (%s in cmd is replaced by +block hash) +.HP +\fB\-blocksizenotify=\fR +.IP +Execute command when the best block changes and its size is over (%s in +cmd is replaced by block hash, %d with the block size) +.HP +\fB\-checkblocks=\fR +.IP +How many blocks to check at startup (default: 500, 0 = all) +.HP +\fB\-conf=\fR +.IP +Specify configuration file (default: phore.conf) +.HP +\fB\-daemon\fR +.IP +Run in the background as a daemon and accept commands +.HP +\fB\-datadir=\fR +.IP +Specify data directory +.HP +\fB\-dbcache=\fR +.IP +Set database cache size in megabytes (4 to 4096, default: 100) +.HP +\fB\-loadblock=\fR +.IP +Imports blocks from external blk000??.dat file on startup +.HP +\fB\-maxreorg=\fR +.IP +Set the Maximum reorg depth (default: 100) +.HP +\fB\-maxorphantx=\fR +.IP +Keep at most unconnectable transactions in memory (default: 100) +.HP +\fB\-par=\fR +.IP +Set the number of script verification threads (\fB\-8\fR to 16, 0 = auto, <0 = +leave that many cores free, default: 0) +.HP +\fB\-pid=\fR +.IP +Specify pid file (default: phored.pid) +.HP +\fB\-reindex\fR +.IP +Rebuild block chain index from current blk000??.dat files on startup +.HP +\fB\-reindexaccumulators\fR +.IP +Reindex the accumulator database on startup +.HP +\fB\-reindexmoneysupply\fR +.IP +Reindex the PHR and zPHR money supply statistics on startup +.HP +\fB\-resync\fR +.IP +Delete blockchain folders and resync from scratch on startup +.HP +\fB\-sysperms\fR +.IP +Create new files with system default permissions, instead of umask 077 +(only effective with disabled wallet functionality) +.HP +\fB\-txindex\fR +.IP +Maintain a full transaction index, used by the getrawtransaction rpc +call (default: 0) +.HP +\fB\-forcestart\fR +.IP +Attempt to force blockchain corruption recovery on startup +.PP +Connection options: +.HP +\fB\-addnode=\fR +.IP +Add a node to connect to and attempt to keep the connection open +.HP +\fB\-banscore=\fR +.IP +Threshold for disconnecting misbehaving peers (default: 100) +.HP +\fB\-bantime=\fR +.IP +Number of seconds to keep misbehaving peers from reconnecting (default: +86400) +.HP +\fB\-bind=\fR +.IP +Bind to given address and always listen on it. Use [host]:port notation +for IPv6 +.HP +\fB\-connect=\fR +.IP +Connect only to the specified node(s) +.HP +\fB\-discover\fR +.IP +Discover own IP address (default: 1 when listening and no \fB\-externalip\fR) +.HP +\fB\-dns\fR +.IP +Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1) +.HP +\fB\-dnsseed\fR +.IP +Query for peer addresses via DNS lookup, if low on addresses (default: 1 +unless \fB\-connect\fR) +.HP +\fB\-externalip=\fR +.IP +Specify your own public address +.HP +\fB\-forcednsseed\fR +.IP +Always query for peer addresses via DNS lookup (default: 0) +.HP +\fB\-listen\fR +.IP +Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) +.HP +\fB\-listenonion\fR +.IP +Automatically create Tor hidden service (default: 1) +.HP +\fB\-maxconnections=\fR +.IP +Maintain at most connections to peers (default: 125) +.HP +\fB\-maxreceivebuffer=\fR +.IP +Maximum per\-connection receive buffer, *1000 bytes (default: 5000) +.HP +\fB\-maxsendbuffer=\fR +.IP +Maximum per\-connection send buffer, *1000 bytes (default: 1000) +.HP +\fB\-onion=\fR +.IP +Use separate SOCKS5 proxy to reach peers via Tor hidden services +(default: \fB\-proxy\fR) +.HP +\fB\-onlynet=\fR +.IP +Only connect to nodes in network (ipv4, ipv6 or onion) +.HP +\fB\-permitbaremultisig\fR +.IP +Relay non\-P2SH multisig (default: 1) +.HP +\fB\-peerbloomfilters\fR +.IP +Support filtering of blocks and transaction with bloom filters (default: +1) +.HP +\fB\-port=\fR +.IP +Listen for connections on (default: 51472 or testnet: 51474) +.HP +\fB\-proxy=\fR +.IP +Connect through SOCKS5 proxy +.HP +\fB\-proxyrandomize\fR +.IP +Randomize credentials for every proxy connection. This enables Tor +stream isolation (default: 1) +.HP +\fB\-seednode=\fR +.IP +Connect to a node to retrieve peer addresses, and disconnect +.HP +\fB\-timeout=\fR +.IP +Specify connection timeout in milliseconds (minimum: 1, default: 5000) +.HP +\fB\-torcontrol=\fR: +.IP +Tor control port to use if onion listening enabled (default: +127.0.0.1:9051) +.HP +\fB\-torpassword=\fR +.IP +Tor control port password (default: empty) +.HP +\fB\-upnp\fR +.IP +Use UPnP to map the listening port (default: 0) +.HP +\fB\-whitebind=\fR +.IP +Bind to given address and whitelist peers connecting to it. Use +[host]:port notation for IPv6 +.HP +\fB\-whitelist=\fR +.IP +Whitelist peers connecting from the given netmask or IP address. Can be +specified multiple times. Whitelisted peers cannot be DoS banned and +their transactions are always relayed, even if they are already in the +mempool, useful e.g. for a gateway +.PP +Wallet options: +.HP +\fB\-backuppath=\fR +.IP +Specify custom backup path to add a copy of any wallet backup. If set as +dir, every backup generates a timestamped file. If set as file, will +rewrite to that file every backup. +.HP +\fB\-createwalletbackups=\fR +.IP +Number of automatic wallet backups (default: 10) +.HP +\fB\-custombackupthreshold=\fR +.IP +Number of custom location backups to retain (default: 1) +.HP +\fB\-disablewallet\fR +.IP +Do not load the wallet and disable wallet RPC calls +.HP +\fB\-keypool=\fR +.IP +Set key pool size to (default: 100) +.HP +\fB\-paytxfee=\fR +.IP +Fee (in PHR/Kb) to add to transactions you send (default: 0.00) +.HP +\fB\-rescan\fR +.IP +Rescan the block chain for missing wallet transactions on startup +.HP +\fB\-salvagewallet\fR +.IP +Attempt to recover private keys from a corrupt wallet.dat on startup +.HP +\fB\-sendfreetransactions\fR +.IP +Send transactions as zero\-fee transactions if possible (default: 0) +.HP +\fB\-spendzeroconfchange\fR +.IP +Spend unconfirmed change when sending transactions (default: 1) +.HP +\fB\-disablesystemnotifications\fR +.IP +Disable OS notifications for incoming transactions (default: 0) +.HP +\fB\-txconfirmtarget=\fR +.IP +If paytxfee is not set, include enough fee so transactions begin +confirmation on average within n blocks (default: 1) +.HP +\fB\-maxtxfee=\fR +.IP +Maximum total fees to use in a single wallet transaction, setting too +low may abort large transactions (default: 1.00) +.HP +\fB\-upgradewallet\fR +.IP +Upgrade wallet to latest format on startup +.HP +\fB\-wallet=\fR +.IP +Specify wallet file (within data directory) (default: wallet.dat) +.HP +\fB\-walletnotify=\fR +.IP +Execute command when a wallet transaction changes (%s in cmd is replaced +by TxID) +.HP +\fB\-zapwallettxes=\fR +.IP +Delete all wallet transactions and only recover those parts of the +blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g. +account owner and payment request information, 2 = drop tx meta data) +.PP +ZeroMQ notification options: +.HP +\fB\-zmqpubhashblock=\fR
+.IP +Enable publish hash block in
+.HP +\fB\-zmqpubhashtx=\fR
+.IP +Enable publish hash transaction in
+.HP +\fB\-zmqpubhashtxlock=\fR
+.IP +Enable publish hash transaction (locked via SwiftX) in
+.HP +\fB\-zmqpubrawblock=\fR
+.IP +Enable publish raw block in
+.HP +\fB\-zmqpubrawtx=\fR
+.IP +Enable publish raw transaction in
+.HP +\fB\-zmqpubrawtxlock=\fR
+.IP +Enable publish raw transaction (locked via SwiftX) in
+.PP +Debugging/Testing options: +.HP +\fB\-debug=\fR +.IP +Output debugging information (default: 0, supplying is +optional). If is not supplied, output all debugging +information. can be: addrman, alert, bench, coindb, db, lock, +rand, rpc, selectcoins, tor, mempool, net, proxy, http, libevent, phore, +(obfuscation, swiftx, masternode, mnpayments, mnbudget, zero). +.HP +\fB\-gen\fR +.IP +Generate coins (default: 0) +.HP +\fB\-genproclimit=\fR +.IP +Set the number of threads for coin generation if enabled (\fB\-1\fR = all +cores, default: 1) +.HP +\fB\-help\-debug\fR +.IP +Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR) +.HP +\fB\-logips\fR +.IP +Include IP addresses in debug output (default: 0) +.HP +\fB\-logtimestamps\fR +.IP +Prepend debug output with timestamp (default: 1) +.HP +\fB\-minrelaytxfee=\fR +.IP +Fees (in PHR/Kb) smaller than this are considered zero fee for relaying +(default: 0.0001) +.HP +\fB\-printtoconsole\fR +.IP +Send trace/debug info to console instead of debug.log file (default: 0) +.HP +\fB\-shrinkdebugfile\fR +.IP +Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR) +.HP +\fB\-testnet\fR +.IP +Use the test network +.HP +\fB\-litemode=\fR +.IP +Disable all PHORE specific functionality (Masternodes, Zerocoin, SwiftX, +Budgeting) (0\-1, default: 0) +.PP +Staking options: +.HP +\fB\-staking=\fR +.IP +Enable staking functionality (0\-1, default: 1) +.HP +\fB\-phrstake=\fR +.IP +Enable or disable staking functionality for PHR inputs (0\-1, default: 1) +.HP +\fB\-reservebalance=\fR +.IP +Keep the specified amount available for spending at all times (default: +0) +.PP +Masternode options: +.HP +\fB\-masternode=\fR +.IP +Enable the client to act as a masternode (0\-1, default: 0) +.HP +\fB\-mnconf=\fR +.IP +Specify masternode configuration file (default: masternode.conf) +.HP +\fB\-mnconflock=\fR +.IP +Lock masternodes from masternode configuration file (default: 1) +.HP +\fB\-masternodeprivkey=\fR +.IP +Set the masternode private key +.HP +\fB\-masternodeaddr=\fR +.IP +Set external address:port to get to this masternode (example: +128.127.106.235:51472) +.HP +\fB\-budgetvotemode=\fR +.IP +Change automatic finalized budget voting behavior. mode=auto: Vote for +only exact finalized budget match to my generated budget. (string, +default: auto) +.PP +Zerocoin options: +.HP +\fB\-enablezeromint=\fR +.IP +Enable automatic Zerocoin minting (0\-1, default: 1) +.HP +\fB\-zeromintpercentage=\fR +.IP +Percentage of automatically minted Zerocoin (1\-100, default: 10) +.HP +\fB\-preferredDenom=\fR +.IP +Preferred Denomination for automatically minted Zerocoin +(1/5/10/50/100/500/1000/5000), 0 for no preference. default: 0) +.HP +\fB\-backupzpiv=\fR +.IP +Enable automatic wallet backups triggered after each zPIV minting (0\-1, +default: 1) +.HP +\fB\-zpivbackuppath=\fR +.IP +Specify custom backup path to add a copy of any automatic zPIV backup. +If set as dir, every backup generates a timestamped file. If set as +file, will rewrite to that file every backup. If backuppath is set as +well, 4 backups will happen +.HP +\fB\-reindexzerocoin=\fR +.IP +Delete all zerocoin spends and mints that have been recorded to the +blockchain database and reindex them (0\-1, default: 0) +.PP +SwiftX options: +.HP +\fB\-enableswifttx=\fR +.IP +Enable SwiftX, show confirmations for locked transactions (bool, +default: true) +.HP +\fB\-swifttxdepth=\fR +.IP +Show N confirmations for a successfully locked transaction (0\-9999, +default: 5) +.PP +Node relay options: +.HP +\fB\-datacarrier\fR +.IP +Relay and mine data carrier transactions (default: 1) +.HP +\fB\-datacarriersize\fR +.IP +Maximum size of data in data carrier transactions we relay and mine +(default: 83) +.PP +Block creation options: +.HP +\fB\-blockminsize=\fR +.IP +Set minimum block size in bytes (default: 0) +.HP +\fB\-blockmaxsize=\fR +.IP +Set maximum block size in bytes (default: 750000) +.HP +\fB\-blockprioritysize=\fR +.IP +Set maximum size of high\-priority/low\-fee transactions in bytes +(default: 50000) +.PP +RPC server options: +.HP +\fB\-server\fR +.IP +Accept command line and JSON\-RPC commands +.HP +\fB\-rest\fR +.IP +Accept public REST requests (default: 0) +.HP +\fB\-rpcbind=\fR +.IP +Bind to given address to listen for JSON\-RPC connections. Use +[host]:port notation for IPv6. This option can be specified multiple +times (default: bind to all interfaces) +.HP +\fB\-rpccookiefile=\fR +.IP +Location of the auth cookie (default: data dir) +.HP +\fB\-rpcuser=\fR +.IP +Username for JSON\-RPC connections +.HP +\fB\-rpcpassword=\fR +.IP +Password for JSON\-RPC connections +.HP +\fB\-rpcport=\fR +.IP +Listen for JSON\-RPC connections on (default: 51473 or testnet: +51475) +.HP +\fB\-rpcallowip=\fR +.IP +Allow JSON\-RPC connections from specified source. Valid for are a +single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) +or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified +multiple times +.HP +\fB\-rpcthreads=\fR +.IP +Set the number of threads to service RPC calls (default: 4) +.SH COPYRIGHT +Copyright (C) 2009-2018 The Bitcoin Core Developers + +Copyright (C) 2014-2018 The Dash Core Developers + +Copyright (C) 2015-2018 The PHORE Core Developers + +This is experimental software. + +Distributed under the MIT software license, see the accompanying file COPYING +or . + +This product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit and cryptographic software written +by Eric Young and UPnP software written by Thomas Bernard. diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in new file mode 100644 index 000000000000..eb920c47eb52 --- /dev/null +++ b/libbitcoinconsensus.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ consensus library +Description: Library for the Bitcoin consensus protocol. +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbitcoinconsensus +Cflags: -I${includedir} +Requires.private: libcrypto diff --git a/pkg.m4 b/pkg.m4 deleted file mode 100644 index c5b26b52e6cd..000000000000 --- a/pkg.m4 +++ /dev/null @@ -1,214 +0,0 @@ -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# serial 1 (pkg-config-0.24) -# -# Copyright © 2004 Scott James Remnant . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# PKG_PROG_PKG_CONFIG([MIN-VERSION]) -# ---------------------------------- -AC_DEFUN([PKG_PROG_PKG_CONFIG], -[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) -AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) -AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi -fi[]dnl -])# PKG_PROG_PKG_CONFIG - -# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# -# Check to see whether a particular set of modules exists. Similar -# to PKG_CHECK_MODULES(), but does not set variables or print errors. -# -# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -# only at the first occurence in configure.ac, so if the first place -# it's called might be skipped (such as if it is within an "if", you -# have to call PKG_CHECK_EXISTS manually -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_EXISTS], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_default([$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) - -# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) -# --------------------------------------------- -m4_define([_PKG_CONFIG], -[if test -n "$$1"; then - pkg_cv_[]$1="$$1" - elif test -n "$PKG_CONFIG"; then - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], - [pkg_failed=yes]) - else - pkg_failed=untried -fi[]dnl -])# _PKG_CONFIG - -# _PKG_SHORT_ERRORS_SUPPORTED -# ----------------------------- -AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -])# _PKG_SHORT_ERRORS_SUPPORTED - - -# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -# [ACTION-IF-NOT-FOUND]) -# -# -# Note that if there is a possibility the first call to -# PKG_CHECK_MODULES might not happen, you should be sure to include an -# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac -# -# -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_MODULES], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $1]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - m4_default([$4], [AC_MSG_ERROR( -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT])[]dnl - ]) -elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see .])[]dnl - ]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - $3 -fi[]dnl -])# PKG_CHECK_MODULES - - -# PKG_INSTALLDIR(DIRECTORY) -# ------------------------- -# Substitutes the variable pkgconfigdir as the location where a module -# should install pkg-config .pc files. By default the directory is -# $libdir/pkgconfig, but the default can be changed by passing -# DIRECTORY. The user can override through the --with-pkgconfigdir -# parameter. -AC_DEFUN([PKG_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([pkgconfigdir], - [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, - [with_pkgconfigdir=]pkg_default) -AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) dnl PKG_INSTALLDIR - - -# PKG_NOARCH_INSTALLDIR(DIRECTORY) -# ------------------------- -# Substitutes the variable noarch_pkgconfigdir as the location where a -# module should install arch-independent pkg-config .pc files. By -# default the directory is $datadir/pkgconfig, but the default can be -# changed by passing DIRECTORY. The user can override through the -# --with-noarch-pkgconfigdir parameter. -AC_DEFUN([PKG_NOARCH_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([noarch-pkgconfigdir], - [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, - [with_noarch_pkgconfigdir=]pkg_default) -AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) dnl PKG_NOARCH_INSTALLDIR - - -# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, -# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# ------------------------------------------- -# Retrieves the value of the pkg-config variable for the given module. -AC_DEFUN([PKG_CHECK_VAR], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl - -_PKG_CONFIG([$1], [variable="][$3]["], [$2]) -AS_VAR_COPY([$1], [pkg_cv_][$1]) - -AS_VAR_IF([$1], [""], [$5], [$4])dnl -])# PKG_CHECK_VAR diff --git a/share/genbuild.sh b/share/genbuild.sh index c217242f6405..30045edb4d6e 100755 --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -1,7 +1,11 @@ #!/bin/sh -LC_ALL=C +# Copyright (c) 2012-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C if [ $# -gt 1 ]; then - cd "$2" + cd "$2" || exit 1 fi if [ $# -gt 0 ]; then FILE="$1" @@ -14,17 +18,29 @@ else exit 1 fi +git_check_in_repo() { + ! { git status --porcelain -uall --ignored "$@" 2>/dev/null || echo '??'; } | grep -q '?' +} + DESC="" SUFFIX="" LAST_COMMIT_DATE="" -if [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then +if [ "${BITCOIN_GENBUILD_NO_GIT}" != "1" -a -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ] && git_check_in_repo share/genbuild.sh; then # clean 'dirty' status of touched files that haven't been modified git diff >/dev/null 2>/dev/null # if latest commit is tagged and not dirty, then override using the tag name DESC=$(git describe 2>/dev/null) RAWDESC=$(git describe --abbrev=0 2>/dev/null) - git diff-index --quiet HEAD -- || DESC="$DESC-dirty" + + + if [ "$(git rev-parse HEAD)" = "$(git rev-list -1 $RAWDESC 2>/dev/null)" ]; then + git diff-index --quiet HEAD -- && DESC=$RAWDESC + fi + + # otherwise generate suffix from git, i.e. string like "59887e8-dirty" + SUFFIX=$(git rev-parse --short HEAD) + git diff-index --quiet HEAD -- || SUFFIX="$SUFFIX-dirty" # get a string like "2012-04-10 16:27:19 +0200" LAST_COMMIT_DATE="$(git log -n 1 --format="%ci")" diff --git a/share/rpcauth/README.md b/share/rpcauth/README.md new file mode 100644 index 000000000000..20d16f0a974f --- /dev/null +++ b/share/rpcauth/README.md @@ -0,0 +1,14 @@ +RPC Tools +--------------------- + +### [RPCAuth](/share/rpcauth) ### + +Create login credentials for a JSON-RPC user. + +Usage: + + ./rpcauth.py + +in which case the script will generate a password. To specify a custom password do: + + ./rpcauth.py diff --git a/share/rpcauth/rpcauth.py b/share/rpcauth/rpcauth.py new file mode 100755 index 000000000000..566c55aba98a --- /dev/null +++ b/share/rpcauth/rpcauth.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import sys +import os +from random import SystemRandom +import base64 +import hmac + +def generate_salt(): + # This uses os.urandom() underneath + cryptogen = SystemRandom() + + # Create 16 byte hex salt + salt_sequence = [cryptogen.randrange(256) for _ in range(16)] + return ''.join([format(r, 'x') for r in salt_sequence]) + +def generate_password(): + """Create 32 byte b64 password""" + return base64.urlsafe_b64encode(os.urandom(32)).decode('utf-8') + +def password_to_hmac(salt, password): + m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256') + return m.hexdigest() + +def main(): + if len(sys.argv) < 2: + sys.stderr.write('Please include username (and an optional password, will generate one if not provided) as an argument.\n') + sys.exit(0) + + username = sys.argv[1] + + salt = generate_salt() + if len(sys.argv) > 2: + password = sys.argv[2] + else: + password = generate_password() + password_hmac = password_to_hmac(salt, password) + + print('String to be appended to bitcoin.conf:') + print('rpcauth={0}:{1}${2}'.format(username, salt, password_hmac)) + print('Your password:\n{0}'.format(password)) + +if __name__ == '__main__': + main() diff --git a/src/Makefile.am b/src/Makefile.am index 82831d29ac0e..ab8a83c8dc12 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,9 +4,10 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) -AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) -AM_CPPFLAGS = $(HARDENED_CPPFLAGS) +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) +AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) +AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) +AM_LIBTOOLFLAGS = --preserve-dup-deps EXTRA_LIBRARIES = if EMBEDDED_UNIVALUE @@ -18,23 +19,7 @@ else LIBUNIVALUE = $(UNIVALUE_LIBS) endif -if EMBEDDED_LEVELDB -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv -LIBLEVELDB += $(builddir)/leveldb/libleveldb.a -LIBMEMENV += $(builddir)/leveldb/libmemenv.a - -# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race -$(LIBLEVELDB): $(LIBMEMENV) - -$(LIBLEVELDB) $(LIBMEMENV): - @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ - CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" -endif - -BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config -BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) +BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) @@ -58,7 +43,7 @@ if ENABLE_WALLET LIBBITCOIN_WALLET=libbitcoin_wallet.a endif -$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) +$(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) # Make is not made aware of per-object dependencies to avoid limiting building parallelization @@ -78,6 +63,7 @@ lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) bin_PROGRAMS = noinst_PROGRAMS = TESTS = +BENCHMARKS = if BUILD_BITCOIND bin_PROGRAMS += phored @@ -87,7 +73,7 @@ if BUILD_BITCOIN_UTILS bin_PROGRAMS += phore-cli phore-tx endif -.PHONY: FORCE +.PHONY: FORCE check-symbols check-security # phore core # BITCOIN_CORE_H = \ activemasternode.h \ @@ -112,6 +98,8 @@ BITCOIN_CORE_H = \ clientversion.h \ coins.h \ compat.h \ + compat/byteswap.h \ + compat/endian.h \ compat/sanity.h \ consensus/merkle.h \ consensus/validation.h \ @@ -124,8 +112,6 @@ BITCOIN_CORE_H = \ denomination_functions.h \ obfuscation.h \ obfuscation-relay.h \ - eccryptoverify.h \ - ecwrapper.h \ hash.h \ httprpc.h \ httpserver.h \ @@ -156,9 +142,9 @@ BITCOIN_CORE_H = \ random.h \ reverselock.h \ reverse_iterate.h \ - rpcclient.h \ - rpcprotocol.h \ - rpcserver.h \ + rpc/client.h \ + rpc/protocol.h \ + rpc/server.h \ scheduler.h \ script/interpreter.h \ script/script.h \ @@ -232,14 +218,14 @@ libbitcoin_server_a_SOURCES = \ noui.cpp \ pow.cpp \ rest.cpp \ - rpcblockchain.cpp \ - rpcmasternode.cpp \ - rpcmasternode-budget.cpp \ - rpcmining.cpp \ - rpcmisc.cpp \ - rpcnet.cpp \ - rpcrawtransaction.cpp \ - rpcserver.cpp \ + rpc/blockchain.cpp \ + rpc/masternode.cpp \ + rpc/masternode-budget.cpp \ + rpc/mining.cpp \ + rpc/misc.cpp \ + rpc/net.cpp \ + rpc/rawtransaction.cpp \ + rpc/server.cpp \ script/sigcache.cpp \ sporkdb.cpp \ timedata.cpp \ @@ -292,8 +278,8 @@ libbitcoin_wallet_a_SOURCES = \ $(BITCOIN_CORE_H) # crypto primitives library -crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) -crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIC_FLAGS) +crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha1.cpp \ crypto/sha256.cpp \ @@ -330,7 +316,7 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sph_types.h # libzerocoin library -libzerocoin_libbitcoin_zerocin_a_CPPFLAGS = $(AM_CPPFLAGS) +libzerocoin_libbitcoin_zerocin_a_CPPFLAGS = $(AM_CPPFLAGS) $(BOOST_CPPFLAGS) libzerocoin_libbitcoin_zerocin_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ libzerocoin/Accumulator.h \ @@ -378,8 +364,6 @@ libbitcoin_common_a_SOURCES = \ primitives/zerocoin.cpp \ core_read.cpp \ core_write.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ hash.cpp \ key.cpp \ keystore.cpp \ @@ -404,31 +388,32 @@ libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ allocators.cpp \ - compat/strnlen.cpp \ - compat/glibc_sanity.cpp \ - compat/glibcxx_sanity.cpp \ chainparamsbase.cpp \ clientversion.cpp \ + compat/glibc_sanity.cpp \ + compat/glibcxx_sanity.cpp \ + compat/strnlen.cpp \ random.cpp \ - rpcprotocol.cpp \ + rpc/protocol.cpp \ support/cleanse.cpp \ sync.cpp \ uint256.cpp \ util.cpp \ - utilstrencodings.cpp \ utilmoneystr.cpp \ + utilstrencodings.cpp \ utiltime.cpp \ $(BITCOIN_CORE_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp +AM_LDFLAGS += $(COMPAT_LDFLAGS) endif # cli: shared between phore-cli and phore-qt libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ - rpcclient.cpp \ + rpc/client.cpp \ $(BITCOIN_CORE_H) nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h @@ -445,14 +430,15 @@ phored_SOURCES += phored-res.rc endif phored_LDADD = \ $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_ZEROCOIN) \ $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_ZMQ) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ + $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ $(LIBSECP256K1) @@ -510,8 +496,6 @@ libbitcoinconsensus_la_SOURCES = \ crypto/sha256.cpp \ crypto/sha512.cpp \ crypto/ripemd160.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ hash.cpp \ pubkey.cpp \ script/script.cpp \ @@ -525,45 +509,71 @@ if GLIBC_BACK_COMPAT endif libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) -libbitcoinconsensus_la_LIBADD = $(CRYPTO_LIBS) $(BOOST_LIBS) -libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL -if USE_LIBSECP256K1 -libbitcoinconsensus_la_LIBADD += secp256k1/libsecp256k1.la -endif +libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) + endif +# CLEANFILES = $(EXTRA_LIBRARIES) -CLEANFILES += leveldb/libleveldb.a leveldb/libmemenv.a + CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += libzerocoin/*.gcda libzerocoin/*.gcno CLEANFILES += primitives/*.gcda primitives/*.gcno -CLEANFILES += consensus/*.gcda consensus/*.gcno +CLEANFILES += rpc/*.gcda rpc/*.gcno CLEANFILES += script/*.gcda script/*.gcno +CLEANFILES += support/*.gcda support/*.gcno CLEANFILES += univalue/*.gcda univalue/*.gcno +CLEANFILES += wallet/*.gcda wallet/*.gcno +CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno CLEANFILES += zmq/*.gcda zmq/*.gcno CLEANFILES += obj/build.h +EXTRA_DIST = + -EXTRA_DIST = leveldb +config/phore-config.h: config/stamp-h1 + @$(MAKE) -C $(top_builddir) $(subdir)/$(@) +config/stamp-h1: $(top_srcdir)/$(subdir)/config/phore-config.h.in $(top_builddir)/config.status + $(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@) +$(top_srcdir)/$(subdir)/config/phore-config.h.in: $(am__configure_deps) + $(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/phore-config.h.in clean-local: - -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean - rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno + -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -f config.h + -rm -rf test/__pycache__ .rc.o: @test -f $(WINDRES) ## FIXME: How to get the appropriate modulename_CPPFLAGS in here? $(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@ +check-symbols: $(bin_PROGRAMS) +if GLIBC_BACK_COMPAT + @echo "Checking glibc back compat..." + $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) +endif + +check-security: $(bin_PROGRAMS) +if HARDEN + @echo "Checking binary security..." + $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) +endif %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$( locale/foo.qm QT_QM=$(QT_TS:.ts=.qm) @@ -480,7 +479,7 @@ $(srcdir)/qt/phorestrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_walle @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" $(PYTHON) ../share/qt/extract_strings_qt.py $^ -translate: $(srcdir)/qt/phorestrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) +translate: $(srcdir)/qt/phorestrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/phore.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/phore_en.ts diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 3761eb3342e3..541be6f0bec0 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -31,13 +31,13 @@ nodist_qt_test_test_phore_qt_SOURCES = $(TEST_QT_MOC_CPP) qt_test_test_phore_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) if ENABLE_WALLET -qt_test_test_phore_qt_LDADD += $(LIBBITCOIN_WALLET) +qt_test_test_phore_qt_LDADD += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET) endif if ENABLE_ZMQ qt_test_test_phore_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif qt_test_test_phore_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) $(LIBLEVELDB) \ - $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ + $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_test_test_phore_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 551ce66272d9..677f010cfb0c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,23 +1,11 @@ # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -TESTS += test/test_phore + bin_PROGRAMS += test/test_phore TEST_SRCDIR = test TEST_BINARY=test/test_phore$(EXEEXT) - -EXTRA_DIST += \ - test/data/bitcoin-util-test.json \ - test/data/blanktx.hex \ - test/data/tt-delin1-out.hex \ - test/data/tt-delout1-out.hex \ - test/data/tt-locktime317000-out.hex \ - test/data/tx394b54bb.hex \ - test/data/txcreate1.hex \ - test/data/txcreate2.hex \ - test/data/txcreatesign.hex - JSON_TEST_FILES = \ test/data/script_valid.json \ test/data/base58_keys_valid.json \ @@ -35,6 +23,9 @@ RAW_TEST_FILES = test/data/alertTests.raw GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) +BITCOIN_TEST_SUITE = \ + test/test_phore.h \ + test/test_phore.cpp # test_phore binary # BITCOIN_TESTS =\ test/zerocoin_implementation_tests.cpp\ @@ -43,6 +34,7 @@ BITCOIN_TESTS =\ test/benchmark_zerocoin.cpp \ test/tutorial_zerocoin.cpp \ test/libzerocoin_tests.cpp \ + test/addrman_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ @@ -76,7 +68,6 @@ BITCOIN_TESTS =\ test/sighash_tests.cpp \ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ - test/test_phore.cpp \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ @@ -90,14 +81,15 @@ BITCOIN_TESTS += \ test/wallet_tests.cpp endif -test_test_phore_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) -test_test_phore_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) -test_test_phore_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) +test_test_phore_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) +test_test_phore_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_FLAGS) +test_test_phore_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) \ + $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) if ENABLE_WALLET test_test_phore_LDADD += $(LIBBITCOIN_WALLET) endif -test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) + +test_test_phore_LDADD = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_phore_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) test_test_phore_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static @@ -105,6 +97,7 @@ test_test_phore_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -sta if ENABLE_ZMQ test_test_phore_LDADD += $(ZMQ_LIBS) endif +# nodist_test_test_phore_SOURCES = $(GENERATED_TEST_FILES) @@ -122,18 +115,28 @@ phore_test_check: $(TEST_BINARY) FORCE phore_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_phore_OBJECTS) $(TEST_BINARY) -check-local: +check-local: $(BITCOIN_TESTS:.cpp=.cpp.test) + @echo "Running test/util/bitcoin-util-test.py..." + $(top_builddir)/test/util/bitcoin-util-test.py + @echo "Running test/util/rpcauth-test.py..." + $(PYTHON) $(top_builddir)/test/util/rpcauth-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check endif +%.cpp.test: %.cpp + @echo Running tests: `cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $< + $(AM_V_at)$(TEST_BINARY) -l test_suite -t "`cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" > $<.log 2>&1 || (cat $<.log && false) + %.json.h: %.json @$(MKDIR_P) $(@D) - @echo "namespace json_tests{" > $@ - @echo "static unsigned const char $(*F)[] = {" >> $@ - @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ - @echo "};};" >> $@ + @{ \ + echo "namespace json_tests{" && \ + echo "static unsigned const char $(*F)[] = {" && \ + $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ + echo "};};"; \ + } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" %.raw.h: %.raw diff --git a/src/accumulatorcheckpoints.cpp b/src/accumulatorcheckpoints.cpp index 77dd4847009b..df501557b78a 100644 --- a/src/accumulatorcheckpoints.cpp +++ b/src/accumulatorcheckpoints.cpp @@ -60,7 +60,7 @@ namespace AccumulatorCheckpoints checkpoint.insert(std::make_pair(denom, bn)); } - mapCheckpoints.insert(make_pair(nHeight, checkpoint)); + mapCheckpoints.insert(std::make_pair(nHeight, checkpoint)); } return true; } diff --git a/src/accumulatormap.cpp b/src/accumulatormap.cpp index a5d214538443..495976ec0228 100644 --- a/src/accumulatormap.cpp +++ b/src/accumulatormap.cpp @@ -8,17 +8,15 @@ #include "txdb.h" #include "libzerocoin/Denominations.h" -using namespace libzerocoin; -using namespace std; //Construct accumulators for all denominations AccumulatorMap::AccumulatorMap(libzerocoin::ZerocoinParams* currentParams) { params = currentParams; - for (auto& denom : zerocoinDenomList) { - unique_ptr uptr(new Accumulator(params, denom)); - mapAccumulators.insert(make_pair(denom, std::move(uptr))); + for (auto& denom : libzerocoin::zerocoinDenomList) { + std::unique_ptr uptr(new libzerocoin::Accumulator(params, denom)); + mapAccumulators.insert(std::make_pair(denom, std::move(uptr))); } } @@ -26,16 +24,16 @@ AccumulatorMap::AccumulatorMap(libzerocoin::ZerocoinParams* currentParams) void AccumulatorMap::Reset() { mapAccumulators.clear(); - for (auto& denom : zerocoinDenomList) { - unique_ptr uptr(new Accumulator(params, denom)); - mapAccumulators.insert(make_pair(denom, std::move(uptr))); + for (auto& denom : libzerocoin::zerocoinDenomList) { + std::unique_ptr uptr(new libzerocoin::Accumulator(params, denom)); + mapAccumulators.insert(std::make_pair(denom, std::move(uptr))); } } //Load a checkpoint containing 8 32bit checksums of accumulator values. bool AccumulatorMap::Load(uint256 nCheckpoint) { - for (auto& denom : zerocoinDenomList) { + for (auto& denom : libzerocoin::zerocoinDenomList) { uint32_t nChecksum = ParseChecksum(nCheckpoint, denom); CBigNum bnValue; @@ -57,10 +55,10 @@ void AccumulatorMap::Load(const AccumulatorCheckpoints::Checkpoint& checkpoint) } //Add a zerocoin to the accumulator of its denomination. -bool AccumulatorMap::Accumulate(PublicCoin pubCoin, bool fSkipValidation) +bool AccumulatorMap::Accumulate(libzerocoin::PublicCoin pubCoin, bool fSkipValidation) { - CoinDenomination denom = pubCoin.getDenomination(); - if (denom == CoinDenomination::ZQ_ERROR) + libzerocoin::CoinDenomination denom = pubCoin.getDenomination(); + if (denom == libzerocoin::CoinDenomination::ZQ_ERROR) return false; if (fSkipValidation) @@ -71,9 +69,9 @@ bool AccumulatorMap::Accumulate(PublicCoin pubCoin, bool fSkipValidation) } //Get the value of a specific accumulator -CBigNum AccumulatorMap::GetValue(CoinDenomination denom) +CBigNum AccumulatorMap::GetValue(libzerocoin::CoinDenomination denom) { - if (denom == CoinDenomination::ZQ_ERROR) + if (denom == libzerocoin::CoinDenomination::ZQ_ERROR) return CBigNum(0); return mapAccumulators.at(denom)->getValue(); } @@ -84,8 +82,8 @@ uint256 AccumulatorMap::GetCheckpoint() uint256 nCheckpoint; //Prevent possible overflows from future changes to the list and forgetting to update this code - assert(zerocoinDenomList.size() == 8); - for (auto& denom : zerocoinDenomList) { + assert(libzerocoin::zerocoinDenomList.size() == 8); + for (auto& denom : libzerocoin::zerocoinDenomList) { CBigNum bnValue = mapAccumulators.at(denom)->getValue(); uint32_t nCheckSum = GetChecksum(bnValue); nCheckpoint = nCheckpoint << 32 | nCheckSum; diff --git a/src/accumulators.cpp b/src/accumulators.cpp index f555da9acf0b..faeb3f9969c8 100644 --- a/src/accumulators.cpp +++ b/src/accumulators.cpp @@ -13,16 +13,15 @@ #include -using namespace libzerocoin; std::map mapAccumulatorValues; std::list listAccCheckpointsNoDB; -uint32_t ParseChecksum(uint256 nChecksum, CoinDenomination denomination) +uint32_t ParseChecksum(uint256 nChecksum, libzerocoin::CoinDenomination denomination) { //shift to the beginning bit of this denomination and trim any remaining bits by returning 32 bits only - int pos = distance(zerocoinDenomList.begin(), find(zerocoinDenomList.begin(), zerocoinDenomList.end(), denomination)); - nChecksum = nChecksum >> (32*((zerocoinDenomList.size() - 1) - pos)); + int pos = distance(libzerocoin::zerocoinDenomList.begin(), find(libzerocoin::zerocoinDenomList.begin(), libzerocoin::zerocoinDenomList.end(), denomination)); + nChecksum = nChecksum >> (32*((libzerocoin::zerocoinDenomList.size() - 1) - pos)); return nChecksum.Get32(); } @@ -36,7 +35,7 @@ uint32_t GetChecksum(const CBigNum &bnValue) } // Find the first occurance of a certain accumulator checksum. Return 0 if not found. -int GetChecksumHeight(uint32_t nChecksum, CoinDenomination denomination) +int GetChecksumHeight(uint32_t nChecksum, libzerocoin::CoinDenomination denomination) { CBlockIndex* pindex = chainActive[Params().Zerocoin_StartHeight()]; if (!pindex) @@ -78,7 +77,7 @@ bool GetAccumulatorValueFromChecksum(uint32_t nChecksum, bool fMemoryOnly, CBigN return true; } -bool GetAccumulatorValueFromDB(uint256 nCheckpoint, CoinDenomination denom, CBigNum& bnAccValue) +bool GetAccumulatorValueFromDB(uint256 nCheckpoint, libzerocoin::CoinDenomination denom, CBigNum& bnAccValue) { uint32_t nChecksum = ParseChecksum(nCheckpoint, denom); return GetAccumulatorValueFromChecksum(nChecksum, false, bnAccValue); @@ -89,14 +88,14 @@ void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue) //Since accumulators are switching at v2, stop databasing v1 because its useless. Only focus on v2. if (chainActive.Height() > Params().Zerocoin_LastOldParams()) { zerocoinDB->WriteAccumulatorValue(nChecksum, bnValue); - mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); + mapAccumulatorValues.insert(std::make_pair(nChecksum, bnValue)); } } void DatabaseChecksums(AccumulatorMap& mapAccumulators) { uint256 nCheckpoint = 0; - for (auto& denom : zerocoinDenomList) { + for (auto& denom : libzerocoin::zerocoinDenomList) { CBigNum bnValue = mapAccumulators.GetValue(denom); uint32_t nCheckSum = GetChecksum(bnValue); AddAccumulatorChecksum(nCheckSum, bnValue); @@ -113,7 +112,7 @@ bool EraseChecksum(uint32_t nChecksum) bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious) { - for (auto& denomination : zerocoinDenomList) { + for (auto& denomination : libzerocoin::zerocoinDenomList) { uint32_t nChecksumErase = ParseChecksum(nCheckpointErase, denomination); uint32_t nChecksumPrevious = ParseChecksum(nCheckpointPrevious, denomination); @@ -130,7 +129,7 @@ bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nChe bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint) { - for (auto& denomination : zerocoinDenomList) { + for (auto& denomination : libzerocoin::zerocoinDenomList) { uint32_t nChecksum = ParseChecksum(nCheckpoint, denomination); //if read is not successful then we are not in a state to verify zerocoin transactions @@ -138,10 +137,9 @@ bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint) if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), nCheckpoint)) listAccCheckpointsNoDB.push_back(nCheckpoint); - LogPrint("zero", "%s : Missing databased value for checksum %d", __func__, nChecksum); - return false; + LogPrint("zero", "%s : Missing databased value for checksum %d\n", __func__, nChecksum); return false; } - mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); + mapAccumulatorValues.insert(std::make_pair(nChecksum, bnValue)); } return true; } @@ -152,20 +150,20 @@ bool EraseCheckpoints(int nStartHeight, int nEndHeight) if (chainActive.Height() < nStartHeight) return false; - nEndHeight = min(chainActive.Height(), nEndHeight); + nEndHeight = std::min(chainActive.Height(), nEndHeight); CBlockIndex* pindex = chainActive[nStartHeight]; uint256 nCheckpointPrev = pindex->pprev->nAccumulatorCheckpoint; //Keep a list of checkpoints from the previous block so that we don't delete them - list listCheckpointsPrev; - for (auto denom : zerocoinDenomList) + std::list listCheckpointsPrev; + for (auto denom : libzerocoin::zerocoinDenomList) listCheckpointsPrev.emplace_back(ParseChecksum(nCheckpointPrev, denom)); while (true) { uint256 nCheckpointDelete = pindex->nAccumulatorCheckpoint; - for (auto denom : zerocoinDenomList) { + for (auto denom : libzerocoin::zerocoinDenomList) { uint32_t nChecksumDelete = ParseChecksum(nCheckpointDelete, denom); if (count(listCheckpointsPrev.begin(), listCheckpointsPrev.end(), nCheckpointDelete)) continue; @@ -255,7 +253,7 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint, Accumulat if(!ReadBlockFromDisk(block, pindex)) return error("%s: failed to read block from disk", __func__); - std::list listPubcoins; + std::list listPubcoins; if (!BlockToPubcoinList(block, listPubcoins)) return error("%s: failed to get zerocoin mintlist from block %d", __func__, pindex->nHeight); @@ -263,7 +261,7 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint, Accumulat LogPrint("zero", "%s found %d mints\n", __func__, listPubcoins.size()); //add the pubcoins to accumulator - for (const PublicCoin& pubcoin : listPubcoins) { + for (const libzerocoin::PublicCoin& pubcoin : listPubcoins) { if(!mapAccumulators.Accumulate(pubcoin, true)) return error("%s: failed to add pubcoin to accumulator at height %d", __func__, pindex->nHeight); } @@ -346,12 +344,12 @@ int AddBlockMintsToAccumulator(const libzerocoin::PublicCoin& coin, const int nH if(!ReadBlockFromDisk(block, pindex)) return error("%s: failed to read block from disk while adding pubcoins to witness", __func__); - list listPubcoins; + std::list listPubcoins; if(!BlockToPubcoinList(block, listPubcoins)) return error("%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight); //add the mints to the witness - for (const PublicCoin& pubcoin : listPubcoins) { + for (const libzerocoin::PublicCoin& pubcoin : listPubcoins) { if (pubcoin.getDenomination() != coin.getDenomination()) continue; @@ -392,7 +390,7 @@ bool GetAccumulatorValue(int& nHeight, const libzerocoin::CoinDenomination denom return true; } -bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator, AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, string& strError, CBlockIndex* pindexCheckpoint) +bool GenerateAccumulatorWitness(const libzerocoin::PublicCoin &coin, libzerocoin::Accumulator& accumulator, libzerocoin::AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, std::string& strError, CBlockIndex* pindexCheckpoint) { LogPrint("zero", "%s: generating\n", __func__); int nLockAttempts = 0; @@ -483,11 +481,11 @@ bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator return true; } -map GetMintMaturityHeight() +std::map GetMintMaturityHeight() { - map > mapDenomMaturity; + std::map > mapDenomMaturity; for (auto denom : libzerocoin::zerocoinDenomList) - mapDenomMaturity.insert(make_pair(denom, make_pair(0, 0))); + mapDenomMaturity.insert(std::make_pair(denom, std::make_pair(0, 0))); int nConfirmedHeight = chainActive.Height() - Params().Zerocoin_MintRequiredConfirmations(); @@ -518,9 +516,9 @@ map GetMintMaturityHeight() } //Generate final map - map mapRet; + std::map mapRet; for (auto denom : libzerocoin::zerocoinDenomList) - mapRet.insert(make_pair(denom, mapDenomMaturity.at(denom).second)); + mapRet.insert(std::make_pair(denom, mapDenomMaturity.at(denom).second)); return mapRet; } diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index dfff5aa556a8..5611b67f063d 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -184,7 +184,7 @@ bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) } pmn->lastPing = mnp; - mnodeman.mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp)); + mnodeman.mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp)); //mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it CMasternodeBroadcast mnb(*pmn); @@ -218,7 +218,7 @@ bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) LogPrint("masternode", "dseep - relaying from active mn, %s \n", vin.ToString().c_str()); LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage(NetMsgType::DSEEP, vin, vchMasterNodeSignature, masterNodeSignatureTime, false); /* @@ -275,8 +275,8 @@ bool CActiveMasternode::CreateBroadcast(std::string strService, std::string strK bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string& errorMessage, CMasternodeBroadcast &mnb) { - // wait for reindex and/or import to finish - if (fImporting || fReindex) return false; + // wait for reindex and/or import to finish + if (fImporting || fReindex) return false; CMasternodePing mnp(vin); if (!mnp.Sign(keyMasternode, pubKeyMasternode)) { @@ -326,7 +326,7 @@ bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCol } LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage("dsee", vin, service, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyCollateralAddress, pubKeyMasternode, -1, -1, masterNodeSignatureTime, PROTOCOL_VERSION, donationAddress, donationPercantage); /* @@ -347,7 +347,7 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr TRY_LOCK(pwalletMain->cs_wallet, fWallet); if (!fWallet) return false; - vector possibleCoins = SelectCoinsMasternode(); + std::vector possibleCoins = SelectCoinsMasternode(); COutput* selectedOutput; // Find the vin @@ -363,7 +363,7 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr } bool found = false; - BOOST_FOREACH (COutput& out, possibleCoins) { + for (COutput& out : possibleCoins) { if (out.tx->GetHash() == txHash && out.i == outputIndex) { selectedOutput = &out; found = true; @@ -416,16 +416,16 @@ bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubke } // get all possible outputs for running Masternode -vector CActiveMasternode::SelectCoinsMasternode() +std::vector CActiveMasternode::SelectCoinsMasternode() { - vector vCoins; - vector filteredCoins; - vector confLockedCoins; + std::vector vCoins; + std::vector filteredCoins; + std::vector confLockedCoins; // Temporary unlock MN coins from masternode.conf if (GetBoolArg("-mnconflock", true)) { uint256 mnTxHash; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { mnTxHash.SetHex(mne.getTxHash()); int nIndex; @@ -443,12 +443,12 @@ vector CActiveMasternode::SelectCoinsMasternode() // Lock MN coins from masternode.conf back if they where temporary unlocked if (!confLockedCoins.empty()) { - BOOST_FOREACH (COutPoint outpoint, confLockedCoins) + for (COutPoint outpoint : confLockedCoins) pwalletMain->LockCoin(outpoint); } // Filter - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { if (out.tx->vout[out.i].nValue == 10000 * COIN) { //exactly filteredCoins.push_back(out); } diff --git a/src/activemasternode.h b/src/activemasternode.h index 988f7c373fee..c8e43d506d42 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -63,7 +63,7 @@ class CActiveMasternode /// Get 10000 PHR input that can be used for the Masternode bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey); - vector SelectCoinsMasternode(); + std::vector SelectCoinsMasternode(); /// Enable cold wallet mode (run a Masternode with no funds) bool EnableHotColdMasterNode(CTxIn& vin, CService& addr); diff --git a/src/addrman.cpp b/src/addrman.cpp index 5da3e89a51ae..ea8f9aba1b75 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -8,7 +8,6 @@ #include "serialize.h" #include "streams.h" -using namespace std; int CAddrInfo::GetTriedBucket(const uint256& nKey) const { @@ -68,7 +67,7 @@ double CAddrInfo::GetChance(int64_t nNow) const fChance *= 0.01; // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. - fChance *= pow(0.66, min(nAttempts, 8)); + fChance *= pow(0.66, std::min(nAttempts, 8)); return fChance; } @@ -222,7 +221,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime) return; // find a bucket it is in now - int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); + int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucket = -1; for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT; @@ -258,7 +257,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) - pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty); + pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); // add services pinfo->nServices |= addr.nServices; @@ -279,11 +278,11 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP int nFactor = 1; for (int n = 0; n < pinfo->nRefCount; n++) nFactor *= 2; - if (nFactor > 1 && (GetRandInt(nFactor) != 0)) + if (nFactor > 1 && (RandomInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); - pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); + pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); nNew++; fNew = true; } @@ -331,24 +330,29 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime) info.nAttempts++; } -CAddress CAddrMan::Select_() +CAddrInfo CAddrMan::Select_(bool newOnly) { if (size() == 0) - return CAddress(); + return CAddrInfo(); + + if (newOnly && nNew == 0) + return CAddrInfo(); // Use a 50% chance for choosing between tried and new table entries. - if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) { + if (!newOnly && (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { // use a tried node double fChanceFactor = 1.0; while (1) { - int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT); - int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); - if (vvTried[nKBucket][nKBucketPos] == -1) - continue; + int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT); + int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); + while (vvTried[nKBucket][nKBucketPos] == -1) { + nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT; + nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; + } int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -356,14 +360,16 @@ CAddress CAddrMan::Select_() // use a new node double fChanceFactor = 1.0; while (1) { - int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); - int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); - if (vvNew[nUBucket][nUBucketPos] == -1) - continue; + int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); + int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); + while (vvNew[nUBucket][nUBucketPos] == -1) { + nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT; + nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; + } int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -459,7 +465,7 @@ void CAddrMan::GetAddr_(std::vector& vAddr) if (vAddr.size() >= nNodes) break; - int nRndPos = GetRandInt(vRandom.size() - n) + n; + int nRndPos = RandomInt(vRandom.size() - n) + n; SwapRandom(n, nRndPos); assert(mapInfo.count(vRandom[n]) == 1); @@ -489,17 +495,19 @@ void CAddrMan::Connected_(const CService& addr, int64_t nTime) info.nTime = nTime; } -void CAddrMan::SetServices_(const CService& addr, uint64_t nServices) -{ - CAddrInfo* pinfo = Find(addr); +void CAddrMan::SetServices_(const CService& addr, uint64_t nServices) { + CAddrInfo *pinfo = Find(addr); if (!pinfo) return; - - CAddrInfo& info = *pinfo; - if (info != addr) + CAddrInfo &info = *pinfo; + + if (info != addr) return; info.nServices = nServices; +} +int CAddrMan::RandomInt(int nMax){ + return GetRandInt(nMax); } \ No newline at end of file diff --git a/src/addrman.h b/src/addrman.h index 27bbb1a65559..947ab6dd900a 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -17,11 +17,17 @@ #include #include -/** - * Extended statistics about a CAddress +/** + * Extended statistics about a CAddress */ class CAddrInfo : public CAddress { + + +public: + //! last try whatsoever by us (memory only) + int64_t nLastTry; + private: //! where knowledge about this address first came from CNetAddr source; @@ -29,9 +35,6 @@ class CAddrInfo : public CAddress //! last successful connection by us int64_t nLastSuccess; - //! last try whatsoever by us: - // int64_t CAddress::nLastTry - //! connection attempts since last successful attempt int nAttempts; @@ -162,8 +165,8 @@ class CAddrInfo : public CAddress //! the maximum number of nodes to return in a getaddr call #define ADDRMAN_GETADDR_MAX 2500 -/** - * Stochastical (IP) address manager +/** + * Stochastical (IP) address manager */ class CAddrMan { @@ -171,9 +174,6 @@ class CAddrMan //! critical section to protect the inner data structures mutable CCriticalSection cs; - //! secret key to randomize bucket select with - uint256 nKey; - //! last used nId int nIdCount; @@ -199,6 +199,9 @@ class CAddrMan int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; protected: + //! secret key to randomize bucket select with + uint256 nKey; + //! Find an entry. CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL); @@ -227,9 +230,11 @@ class CAddrMan //! Mark an entry as attempted to connect. void Attempt_(const CService& addr, int64_t nTime); - //! Select an address to connect to. - //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) - CAddress Select_(); + //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. + CAddrInfo Select_(bool newOnly); + + //! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic. + virtual int RandomInt(int nMax); #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. @@ -534,13 +539,13 @@ class CAddrMan * Choose an address to connect to. * nUnkBias determines how much "new" entries are favored over "tried" ones (0-100). */ - CAddress Select() + CAddrInfo Select(bool newOnly = false) { - CAddress addrRet; + CAddrInfo addrRet; { LOCK(cs); Check(); - addrRet = Select_(); + addrRet = Select_(newOnly); Check(); } return addrRet; diff --git a/src/alert.cpp b/src/alert.cpp index 7722f365f669..4f384cc05497 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -20,12 +20,11 @@ #include #include -#include + #include -using namespace std; -map mapAlerts; +std::map mapAlerts; CCriticalSection cs_mapAlerts; void CUnsignedAlert::SetNull() @@ -52,7 +51,7 @@ std::string CUnsignedAlert::ToString() const for (auto& n: setCancel) strSetCancel += strprintf("%d ", n); std::string strSetSubVer; - BOOST_FOREACH (std::string str, setSubVer) + for (std::string str : setSubVer) strSetSubVer += "\"" + str + "\" "; return strprintf( "CAlert(\n" @@ -161,7 +160,7 @@ CAlert CAlert::getAlertByHash(const uint256& hash) CAlert retval; { LOCK(cs_mapAlerts); - map::iterator mi = mapAlerts.find(hash); + std::map::iterator mi = mapAlerts.find(hash); if (mi != mapAlerts.end()) retval = mi->second; } @@ -198,7 +197,7 @@ bool CAlert::ProcessAlert(bool fThread) { LOCK(cs_mapAlerts); // Cancel previous alerts - for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) { + for (std::map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) { const CAlert& alert = (*mi).second; if (Cancels(alert)) { LogPrint("alert", "cancelling alert %d\n", alert.nID); @@ -213,7 +212,7 @@ bool CAlert::ProcessAlert(bool fThread) } // Check if this alert has been cancelled - BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) { + for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) { const CAlert& alert = item.second; if (alert.Cancels(*this)) { LogPrint("alert", "alert already cancelled by %d\n", alert.nID); @@ -222,7 +221,7 @@ bool CAlert::ProcessAlert(bool fThread) } // Add to mapAlerts - mapAlerts.insert(make_pair(GetHash(), *this)); + mapAlerts.insert(std::make_pair(GetHash(), *this)); // Notify UI and -alertnotify if it applies to me if (AppliesToMe()) { uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); diff --git a/src/allocators.h b/src/allocators.h index ae7e0639e487..1e84427e442a 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -127,7 +127,7 @@ class MemoryPageLocker * std::allocator templates. * * Some implementations of the STL allocate memory in some constructors (i.e., see - * MSVC's vector implementation where it allocates 1 byte of memory in the allocator.) + * MSVC's std::vector implementation where it allocates 1 byte of memory in the allocator.) * Due to the unpredictable order of static initializers, we have to make sure the * LockedPageManager instance exists before any other STL-based objects that use * secure_allocator are created. So instead of having LockedPageManager also be diff --git a/src/bip38.cpp b/src/bip38.cpp index b094c3ccc8e0..07c856b80344 100644 --- a/src/bip38.cpp +++ b/src/bip38.cpp @@ -8,6 +8,7 @@ #include "pubkey.h" #include "util.h" #include "utilstrencodings.h" +#include "random.h" #include #include @@ -48,15 +49,40 @@ void ComputePassfactor(std::string ownersalt, uint256 prefactor, uint256& passfa bool ComputePasspoint(uint256 passfactor, CPubKey& passpoint) { + size_t clen = 65; + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + assert(ctx != nullptr); + { + // Pass in a random blinding seed to the secp256k1 context. + std::vector> vseed(32); + GetRandBytes(vseed.data(), 32); + bool ret = secp256k1_context_randomize(ctx, vseed.data()); + assert(ret); + } + secp256k1_pubkey pubkey; + //passpoint is the ec_mult of passfactor on secp256k1 - int clen = 65; - return secp256k1_ec_pubkey_create(UBEGIN(passpoint), &clen, passfactor.begin(), true) != 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, passfactor.begin())) { + secp256k1_context_destroy(ctx); + return false; + } + + secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)passpoint.begin(), &clen, &pubkey, SECP256K1_EC_COMPRESSED); + secp256k1_context_destroy(ctx); + + if (passpoint.size() != clen) + return false; + + if (!passpoint.IsValid()) + return false; + + return true; } void ComputeSeedBPass(CPubKey passpoint, std::string strAddressHash, std::string strOwnerSalt, uint512& seedBPass) { // Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownerentropy - string salt = ReverseEndianString(strAddressHash + strOwnerSalt); + std::string salt = ReverseEndianString(strAddressHash + strOwnerSalt); uint256 s2(salt); scrypt_hash(BEGIN(passpoint), HexStr(passpoint).size() / 2, BEGIN(s2), salt.size() / 2, BEGIN(seedBPass), 1024, 1, 1, 64); } @@ -79,7 +105,7 @@ std::string AddressToBip38Hash(std::string address) std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uint256 privKey, bool fCompressed) { - string strAddressHash = AddressToBip38Hash(strAddress); + std::string strAddressHash = AddressToBip38Hash(strAddress); uint512 hashed; uint64_t salt = uint256(ReverseEndianString(strAddressHash)).Get64(); @@ -106,7 +132,7 @@ std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uin uint512 encrypted2; AES_encrypt(block2.begin(), encrypted2.begin(), &key); - string strPrefix = "0142"; + std::string strPrefix = "0142"; strPrefix += (fCompressed ? "E0" : "C0"); uint512 encryptedKey(ReverseEndianString(strPrefix + strAddressHash)); @@ -225,15 +251,27 @@ bool BIP38_Decrypt(std::string strPassphrase, std::string strKey, uint256& privK ComputeFactorB(seedB, factorB); //multiply passfactor by factorb mod N to yield the priv key + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + assert(ctx != nullptr); + { + // Pass in a random blinding seed to the secp256k1 context. + std::vector> vseed(32); + GetRandBytes(vseed.data(), 32); + bool ret = secp256k1_context_randomize(ctx, vseed.data()); + assert(ret); + } privKey = factorB; - if (!secp256k1_ec_privkey_tweak_mul(privKey.begin(), passfactor.begin())) + if (!secp256k1_ec_privkey_tweak_mul(ctx, privKey.begin(), passfactor.begin())) { + secp256k1_context_destroy(ctx); return false; + } + secp256k1_context_destroy(ctx); //double check that the address hash matches our final privkey CKey k; k.Set(privKey.begin(), privKey.end(), fCompressed); CPubKey pubkey = k.GetPubKey(); - string address = EncodeDestination(pubkey.GetID()); + std::string address = EncodeDestination(pubkey.GetID()); return strAddressHash == AddressToBip38Hash(address); } diff --git a/src/bloom.cpp b/src/bloom.cpp index eb6ec01a69ed..264da8ec29b9 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -13,28 +13,27 @@ #include #include -#include + #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455 #define LN2 0.6931471805599453094172321214581765680755001343602552 -using namespace std; CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) : - /** + /** * The ideal size for a bloom filter with a given number of elements and false positive rate is: * - nElements * log(fp rate) / ln(2)^2 * We ignore filter parameters which will create a bloom filter larger than the protocol limits */ - vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), + vData(std::min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), /** * The ideal number of hash functions is filter size * ln(2) / number of elements * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas */ - isFull(false), - isEmpty(false), - nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), + isFull(false), + isEmpty(false), + nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), nTweak(nTweakIn), nFlags(nFlagsIn) { @@ -46,7 +45,7 @@ inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector< return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8); } -void CBloomFilter::insert(const vector& vKey) +void CBloomFilter::insert(const std::vector& vKey) { if (isFull) return; @@ -62,17 +61,17 @@ void CBloomFilter::insert(const COutPoint& outpoint) { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << outpoint; - vector data(stream.begin(), stream.end()); + std::vector data(stream.begin(), stream.end()); insert(data); } void CBloomFilter::insert(const uint256& hash) { - vector data(hash.begin(), hash.end()); + std::vector data(hash.begin(), hash.end()); insert(data); } -bool CBloomFilter::contains(const vector& vKey) const +bool CBloomFilter::contains(const std::vector& vKey) const { if (isFull) return true; @@ -91,13 +90,13 @@ bool CBloomFilter::contains(const COutPoint& outpoint) const { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << outpoint; - vector data(stream.begin(), stream.end()); + std::vector data(stream.begin(), stream.end()); return contains(data); } bool CBloomFilter::contains(const uint256& hash) const { - vector data(hash.begin(), hash.end()); + std::vector data(hash.begin(), hash.end()); return contains(data); } @@ -133,7 +132,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) // This means clients don't have to update the filter themselves when a new relevant tx // is discovered in order to find spending transactions, which avoids round-tripping and race conditions. CScript::const_iterator pc = txout.scriptPubKey.begin(); - vector data; + std::vector data; while (pc < txout.scriptPubKey.end()) { opcodetype opcode; if (!txout.scriptPubKey.GetOp(pc, opcode, data)) @@ -144,7 +143,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) insert(COutPoint(hash, i)); else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY) { txnouttype type; - vector > vSolutions; + std::vector > vSolutions; if (Solver(txout.scriptPubKey, type, vSolutions) && (type == TX_PUBKEY || type == TX_MULTISIG)) insert(COutPoint(hash, i)); @@ -157,14 +156,14 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) if (fFound) return true; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { // Match if the filter contains an outpoint tx spends if (contains(txin.prevout)) return true; // Match if the filter contains any arbitrary script data element in any scriptSig in tx CScript::const_iterator pc = txin.scriptSig.begin(); - vector data; + std::vector data; while (pc < txin.scriptSig.end()) { opcodetype opcode; if (!txin.scriptSig.GetOp(pc, opcode, data)) diff --git a/src/chain.cpp b/src/chain.cpp index d0314308edba..78f20ad2453a 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -5,8 +5,6 @@ #include "chain.h" -using namespace std; - /** * CChain implementation */ diff --git a/src/chain.h b/src/chain.h index 1ea390c07fb9..b14455256bb3 100644 --- a/src/chain.h +++ b/src/chain.h @@ -16,7 +16,7 @@ #include -#include + struct CDiskBlockPos { int nFile; @@ -214,7 +214,7 @@ class CBlockIndex nAccumulatorCheckpoint = 0; // Start supply of each denomination with 0s for (auto& denom : libzerocoin::zerocoinDenomList) { - mapZerocoinSupply.insert(make_pair(denom, 0)); + mapZerocoinSupply.insert(std::make_pair(denom, 0)); } vMintDenominationsInBlock.clear(); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c06d017fb820..8f4fd52c80ab 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -16,8 +16,6 @@ #include -using namespace std; -using namespace boost::assign; struct SeedSpec6 { uint8_t addr[16]; @@ -174,7 +172,7 @@ class CMainParams : public CChainParams CMutableTransaction txNew; txNew.vin.resize(1); txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vout[0].SetEmpty(); genesis.vtx.push_back(txNew); genesis.hashPrevBlock = 0; @@ -196,7 +194,7 @@ class CMainParams : public CChainParams base58Prefixes[SECRET_KEY] = std::vector(1, 212); base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x02)(0x2D)(0x25)(0x33).convert_to_container >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x02)(0x21)(0x31)(0x2B).convert_to_container >(); - // BIP44 coin type is from https://github.com/satoshilabs/slips/blob/master/slip-0044.md + // BIP44 coin type is from https://github.com/satoshilabs/slips/blob/master/slip-0044.md nExtCoinType = 444; bech32_hrp = "ph"; @@ -213,6 +211,7 @@ class CMainParams : public CChainParams fHeadersFirstSyncingActive = false; nPoolMaxTransactions = 3; + nBudgetCycleBlocks = 43200; //!< Amount of blocks in a months period of time (using 1 minutes per) = (60*24*30) strSporkKey = "04659d53bd8f7ad9d34a17281febedac754e5a6eb136142d3a9c6c0ea21b6ed7498ceb3d872eed00ae755f7aeadaeb1d9ab5e1a8f1e7efcd0ddcb39d4623c12790"; strObfuscationPoolDummyAddress = "PCYiHgGJJ6xGHqivmdZrYjRnhaYf6AJ2Mp"; @@ -306,6 +305,7 @@ class CTestNetParams : public CMainParams fTestnetToBeDeprecatedFieldRPC = true; nPoolMaxTransactions = 2; + nBudgetCycleBlocks = 864; //!< 1.6 Cycles a day on the testnet it used to be 10 times a day, but this was changed by Michael strSporkKey = "040d2595becca91020213bf94735fa26bb92a206aa21be45b0e95f205ff8588ecb9398c5c7d8cfaf78149d230b8dc066c3660573ff2104dac98e43283d6dc882d6"; strObfuscationPoolDummyAddress = "PCYiHgGJJ6xGHqivmdZrYjRnhaYf6AJ2Mp"; nBudgetFeeConfirmations = 3; // Number of confirmations for the finalization fee. We have to make this very short diff --git a/src/chainparams.h b/src/chainparams.h index 77d1a81f5377..71bca2a28e9f 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -91,6 +91,10 @@ class CChainParams const std::vector& FixedSeeds() const { return vFixedSeeds; } virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0; int PoolMaxTransactions() const { return nPoolMaxTransactions; } + /** Return the number of blocks in a budget cycle */ + int GetBudgetCycleBlocks() const { return nBudgetCycleBlocks; } + + /** Spork key and Masternode Handling **/ std::string SporkKey() const { return strSporkKey; } std::string ObfuscationPoolDummyAddress() const { return strObfuscationPoolDummyAddress; } int64_t BudgetFeeConfirmations() const { return nBudgetFeeConfirmations; } @@ -153,6 +157,7 @@ class CChainParams bool fTestnetToBeDeprecatedFieldRPC; bool fHeadersFirstSyncingActive; int nPoolMaxTransactions; + int nBudgetCycleBlocks; std::string strSporkKey; std::string strObfuscationPoolDummyAddress; std::string zerocoinModulus; diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index ec18b5f29cf7..7eaa218051f9 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -11,7 +11,6 @@ #include -using namespace boost::assign; /** * Main network diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 9411b410c592..b43e5dff30ea 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -10,10 +10,10 @@ #include "chainparams.h" #include "main.h" #include "uint256.h" - +#include #include -#include + namespace Checkpoints { diff --git a/src/checkqueue.h b/src/checkqueue.h index 9648347c6653..994b1729a8ca 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -8,7 +8,7 @@ #include #include -#include + #include #include #include @@ -119,7 +119,7 @@ class CCheckQueue fOk = fAllOk; } // execute work - BOOST_FOREACH (T& check, vChecks) + for (T& check : vChecks) if (fOk) fOk = check(); vChecks.clear(); @@ -146,7 +146,7 @@ class CCheckQueue void Add(std::vector& vChecks) { boost::unique_lock lock(mutex); - BOOST_FOREACH (T& check, vChecks) { + for (T& check : vChecks) { queue.push_back(T()); check.swap(queue.back()); } diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 74695de2ff5b..8c899fec88f3 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin developers +// Copyright (c) 2012-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,7 +6,6 @@ #include "tinyformat.h" -#include /** * Name of client reported in the 'version' message. Report the same name @@ -39,13 +38,13 @@ const std::string CLIENT_NAME("Phore Core"); //! First, include build.h if requested #ifdef HAVE_BUILD_INFO -#include "build.h" +#include "obj/build.h" #endif -//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. +//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$ #ifdef GIT_ARCHIVE -#define GIT_COMMIT_ID "cbcb549" -#define GIT_COMMIT_DATE "Tue, 9 Feb 2016 16:54:57 -0500" +#define GIT_COMMIT_ID "$Format:%H$" +#define GIT_COMMIT_DATE "$Format:%cD$" #endif #define BUILD_DESC_WITH_SUFFIX(maj, min, rev, build, suffix) \ diff --git a/src/coins.h b/src/coins.h index f23236e6039a..debf504ab0ae 100644 --- a/src/coins.h +++ b/src/coins.h @@ -15,7 +15,7 @@ #include #include -#include + #include /** @@ -127,7 +127,7 @@ class CCoins void ClearUnspendable() { - BOOST_FOREACH (CTxOut& txout, vout) { + for (CTxOut& txout : vout) { if (txout.scriptPubKey.IsUnspendable()) txout.SetNull(); } @@ -278,7 +278,7 @@ class CCoins //! note that only !IsPruned() CCoins can be serialized bool IsPruned() const { - BOOST_FOREACH (const CTxOut& out, vout) + for (const CTxOut& out : vout) if (!out.IsNull()) return false; return true; @@ -461,8 +461,8 @@ class CCoinsViewCache : public CCoinsViewBacked * Note that lightweight clients may not know anything besides the hash of previous transactions, * so may not be able to calculate this. * - * @param[in] tx transaction for which we are checking input total - * @return Sum of value of all inputs (scriptSigs) + * @param[in] tx transaction for which we are checking input total + * @return Sum of value of all inputs (scriptSigs) */ CAmount GetValueIn(const CTransaction& tx) const; diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h new file mode 100644 index 000000000000..ae2e080faec0 --- /dev/null +++ b/src/compat/byteswap.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMPAT_BYTESWAP_H +#define BITCOIN_COMPAT_BYTESWAP_H + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#if defined(HAVE_BYTESWAP_H) +#include +#endif + +#if defined(__APPLE__) + +#if !defined(bswap_16) + +// Mac OS X / Darwin features; we include a check for bswap_16 because if it is already defined, protobuf has +// defined these macros for us already; if it isn't, we do it ourselves. In either case, we get the exact same +// result regardless which path was taken +#include +#define bswap_16(x) OSSwapInt16(x) +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) + +#endif // !defined(bswap_16) + +#else +// Non-Mac OS X / non-Darwin + +#if HAVE_DECL_BSWAP_16 == 0 +inline uint16_t bswap_16(uint16_t x) +{ + return (x >> 8) | (x << 8); +} +#endif // HAVE_DECL_BSWAP16 == 0 + +#if HAVE_DECL_BSWAP_32 == 0 +inline uint32_t bswap_32(uint32_t x) +{ + return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >> 8) | + ((x & 0x0000ff00U) << 8) | ((x & 0x000000ffU) << 24)); +} +#endif // HAVE_DECL_BSWAP32 == 0 + +#if HAVE_DECL_BSWAP_64 == 0 +inline uint64_t bswap_64(uint64_t x) +{ + return (((x & 0xff00000000000000ull) >> 56) + | ((x & 0x00ff000000000000ull) >> 40) + | ((x & 0x0000ff0000000000ull) >> 24) + | ((x & 0x000000ff00000000ull) >> 8) + | ((x & 0x00000000ff000000ull) << 8) + | ((x & 0x0000000000ff0000ull) << 24) + | ((x & 0x000000000000ff00ull) << 40) + | ((x & 0x00000000000000ffull) << 56)); +} +#endif // HAVE_DECL_BSWAP64 == 0 + +#endif // defined(__APPLE__) + +#endif // BITCOIN_COMPAT_BYTESWAP_H diff --git a/src/compat/endian.h b/src/compat/endian.h new file mode 100644 index 000000000000..df05e029a6c1 --- /dev/null +++ b/src/compat/endian.h @@ -0,0 +1,241 @@ +// Copyright (c) 2014-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMPAT_ENDIAN_H +#define BITCOIN_COMPAT_ENDIAN_H + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#include + +#if defined(HAVE_ENDIAN_H) +#include +#elif defined(HAVE_SYS_ENDIAN_H) +#include +#endif + +#ifndef HAVE_CONFIG_H +// While not technically a supported configuration, defaulting to defining these +// DECLs when we were compiled without autotools makes it easier for other build +// systems to build things like libbitcoinconsensus for strange targets. +#ifdef htobe16 +#define HAVE_DECL_HTOBE16 1 +#endif +#ifdef htole16 +#define HAVE_DECL_HTOLE16 1 +#endif +#ifdef be16toh +#define HAVE_DECL_BE16TOH 1 +#endif +#ifdef le16toh +#define HAVE_DECL_LE16TOH 1 +#endif + +#ifdef htobe32 +#define HAVE_DECL_HTOBE32 1 +#endif +#ifdef htole32 +#define HAVE_DECL_HTOLE32 1 +#endif +#ifdef be32toh +#define HAVE_DECL_BE32TOH 1 +#endif +#ifdef le32toh +#define HAVE_DECL_LE32TOH 1 +#endif + +#ifdef htobe64 +#define HAVE_DECL_HTOBE64 1 +#endif +#ifdef htole64 +#define HAVE_DECL_HTOLE64 1 +#endif +#ifdef be64toh +#define HAVE_DECL_BE64TOH 1 +#endif +#ifdef le64toh +#define HAVE_DECL_LE64TOH 1 +#endif + +#endif // HAVE_CONFIG_H + +#if defined(WORDS_BIGENDIAN) + +#if HAVE_DECL_HTOBE16 == 0 +inline uint16_t htobe16(uint16_t host_16bits) +{ + return host_16bits; +} +#endif // HAVE_DECL_HTOBE16 + +#if HAVE_DECL_HTOLE16 == 0 +inline uint16_t htole16(uint16_t host_16bits) +{ + return bswap_16(host_16bits); +} +#endif // HAVE_DECL_HTOLE16 + +#if HAVE_DECL_BE16TOH == 0 +inline uint16_t be16toh(uint16_t big_endian_16bits) +{ + return big_endian_16bits; +} +#endif // HAVE_DECL_BE16TOH + +#if HAVE_DECL_LE16TOH == 0 +inline uint16_t le16toh(uint16_t little_endian_16bits) +{ + return bswap_16(little_endian_16bits); +} +#endif // HAVE_DECL_LE16TOH + +#if HAVE_DECL_HTOBE32 == 0 +inline uint32_t htobe32(uint32_t host_32bits) +{ + return host_32bits; +} +#endif // HAVE_DECL_HTOBE32 + +#if HAVE_DECL_HTOLE32 == 0 +inline uint32_t htole32(uint32_t host_32bits) +{ + return bswap_32(host_32bits); +} +#endif // HAVE_DECL_HTOLE32 + +#if HAVE_DECL_BE32TOH == 0 +inline uint32_t be32toh(uint32_t big_endian_32bits) +{ + return big_endian_32bits; +} +#endif // HAVE_DECL_BE32TOH + +#if HAVE_DECL_LE32TOH == 0 +inline uint32_t le32toh(uint32_t little_endian_32bits) +{ + return bswap_32(little_endian_32bits); +} +#endif // HAVE_DECL_LE32TOH + +#if HAVE_DECL_HTOBE64 == 0 +inline uint64_t htobe64(uint64_t host_64bits) +{ + return host_64bits; +} +#endif // HAVE_DECL_HTOBE64 + +#if HAVE_DECL_HTOLE64 == 0 +inline uint64_t htole64(uint64_t host_64bits) +{ + return bswap_64(host_64bits); +} +#endif // HAVE_DECL_HTOLE64 + +#if HAVE_DECL_BE64TOH == 0 +inline uint64_t be64toh(uint64_t big_endian_64bits) +{ + return big_endian_64bits; +} +#endif // HAVE_DECL_BE64TOH + +#if HAVE_DECL_LE64TOH == 0 +inline uint64_t le64toh(uint64_t little_endian_64bits) +{ + return bswap_64(little_endian_64bits); +} +#endif // HAVE_DECL_LE64TOH + +#else // WORDS_BIGENDIAN + +#if HAVE_DECL_HTOBE16 == 0 +inline uint16_t htobe16(uint16_t host_16bits) +{ + return bswap_16(host_16bits); +} +#endif // HAVE_DECL_HTOBE16 + +#if HAVE_DECL_HTOLE16 == 0 +inline uint16_t htole16(uint16_t host_16bits) +{ + return host_16bits; +} +#endif // HAVE_DECL_HTOLE16 + +#if HAVE_DECL_BE16TOH == 0 +inline uint16_t be16toh(uint16_t big_endian_16bits) +{ + return bswap_16(big_endian_16bits); +} +#endif // HAVE_DECL_BE16TOH + +#if HAVE_DECL_LE16TOH == 0 +inline uint16_t le16toh(uint16_t little_endian_16bits) +{ + return little_endian_16bits; +} +#endif // HAVE_DECL_LE16TOH + +#if HAVE_DECL_HTOBE32 == 0 +inline uint32_t htobe32(uint32_t host_32bits) +{ + return bswap_32(host_32bits); +} +#endif // HAVE_DECL_HTOBE32 + +#if HAVE_DECL_HTOLE32 == 0 +inline uint32_t htole32(uint32_t host_32bits) +{ + return host_32bits; +} +#endif // HAVE_DECL_HTOLE32 + +#if HAVE_DECL_BE32TOH == 0 +inline uint32_t be32toh(uint32_t big_endian_32bits) +{ + return bswap_32(big_endian_32bits); +} +#endif // HAVE_DECL_BE32TOH + +#if HAVE_DECL_LE32TOH == 0 +inline uint32_t le32toh(uint32_t little_endian_32bits) +{ + return little_endian_32bits; +} +#endif // HAVE_DECL_LE32TOH + +#if HAVE_DECL_HTOBE64 == 0 +inline uint64_t htobe64(uint64_t host_64bits) +{ + return bswap_64(host_64bits); +} +#endif // HAVE_DECL_HTOBE64 + +#if HAVE_DECL_HTOLE64 == 0 +inline uint64_t htole64(uint64_t host_64bits) +{ + return host_64bits; +} +#endif // HAVE_DECL_HTOLE64 + +#if HAVE_DECL_BE64TOH == 0 +inline uint64_t be64toh(uint64_t big_endian_64bits) +{ + return bswap_64(big_endian_64bits); +} +#endif // HAVE_DECL_BE64TOH + +#if HAVE_DECL_LE64TOH == 0 +inline uint64_t le64toh(uint64_t little_endian_64bits) +{ + return little_endian_64bits; +} +#endif // HAVE_DECL_LE64TOH + +#endif // WORDS_BIGENDIAN + +#endif // BITCOIN_COMPAT_ENDIAN_H diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp index f2772beec2fe..88f71ef1dbf4 100644 --- a/src/compat/glibc_compat.cpp +++ b/src/compat/glibc_compat.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #endif #include +#include #if defined(HAVE_SYS_SELECT_H) #include @@ -27,3 +28,49 @@ extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a) return a / __NFDBITS; } extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn"))); + +#if defined(__i386__) || defined(__arm__) + +extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp); + +extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp) +{ + int32_t c1 = 0, c2 = 0; + int64_t uu = u, vv = v; + int64_t w; + int64_t r; + + if (uu < 0) { + c1 = ~c1, c2 = ~c2, uu = -uu; + } + if (vv < 0) { + c1 = ~c1, vv = -vv; + } + + w = __udivmoddi4(uu, vv, (uint64_t*)&r); + if (c1) + w = -w; + if (c2) + r = -r; + + *rp = r; + return w; +} +#endif + +extern "C" float log2f_old(float x); +#ifdef __i386__ +__asm(".symver log2f_old,log2f@GLIBC_2.1"); +#elif defined(__amd64__) +__asm(".symver log2f_old,log2f@GLIBC_2.2.5"); +#elif defined(__arm__) +__asm(".symver log2f_old,log2f@GLIBC_2.4"); +#elif defined(__aarch64__) +__asm(".symver log2f_old,log2f@GLIBC_2.17"); +#elif defined(__riscv) +__asm(".symver log2f_old,log2f@GLIBC_2.27"); +#endif +extern "C" float __wrap_log2f(float x) +{ + return log2f_old(x); +} diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp index ae3c5e3e8e64..6cad47849e60 100644 --- a/src/compat/glibc_sanity.cpp +++ b/src/compat/glibc_sanity.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/glibcxx_sanity.cpp b/src/compat/glibcxx_sanity.cpp index aafa4a6aef86..342f621e9fc5 100644 --- a/src/compat/glibcxx_sanity.cpp +++ b/src/compat/glibcxx_sanity.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/sanity.h b/src/compat/sanity.h index 7f5bc1a4fb53..909c4f6da82f 100644 --- a/src/compat/sanity.h +++ b/src/compat/sanity.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/strnlen.cpp b/src/compat/strnlen.cpp index c6d68940f8d3..54637e204763 100644 --- a/src/compat/strnlen.cpp +++ b/src/compat/strnlen.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_read.cpp b/src/core_read.cpp index 8dcf55364d58..4cd072bf63ae 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -21,15 +21,12 @@ #include #include -using namespace boost; -using namespace boost::algorithm; -using namespace std; CScript ParseScript(std::string s) { CScript result; - static map mapOpNames; + static std::map mapOpNames; if (mapOpNames.empty()) { for (int op = 0; op <= OP_ZEROCOINSPEND; op++) { @@ -40,30 +37,30 @@ CScript ParseScript(std::string s) const char* name = GetOpName((opcodetype)op); if (strcmp(name, "OP_UNKNOWN") == 0) continue; - string strName(name); + std::string strName(name); mapOpNames[strName] = (opcodetype)op; // Convenience: OP_ADD and just ADD are both recognized: - replace_first(strName, "OP_", ""); + boost::algorithm::replace_first(strName, "OP_", ""); mapOpNames[strName] = (opcodetype)op; } } - vector words; - split(words, s, is_any_of(" \t\n"), token_compress_on); + std::vector words; + split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on); for (std::vector::const_iterator w = words.begin(); w != words.end(); ++w) { if (w->empty()) { // Empty string, ignore. (boost::split given '' will return one word) - } else if (all(*w, is_digit()) || - (starts_with(*w, "-") && all(string(w->begin() + 1, w->end()), is_digit()))) { + } else if (all(*w, boost::algorithm::is_digit()) || + (boost::algorithm::starts_with(*w, "-") && all(std::string(w->begin() + 1, w->end()), boost::algorithm::is_digit()))) { // Number int64_t n = atoi64(*w); result << n; - } else if (starts_with(*w, "0x") && (w->begin() + 2 != w->end()) && IsHex(string(w->begin() + 2, w->end()))) { + } else if (boost::algorithm::starts_with(*w, "0x") && (w->begin() + 2 != w->end()) && IsHex(std::string(w->begin() + 2, w->end()))) { // Raw hex data, inserted NOT pushed onto stack: - std::vector raw = ParseHex(string(w->begin() + 2, w->end())); + std::vector raw = ParseHex(std::string(w->begin() + 2, w->end())); result.insert(result.end(), raw.begin(), raw.end()); - } else if (w->size() >= 2 && starts_with(*w, "'") && ends_with(*w, "'")) { + } else if (w->size() >= 2 && boost::algorithm::starts_with(*w, "'") && boost::algorithm::ends_with(*w, "'")) { // Single-quoted string, pushed as data. NOTE: this is poor-man's // parsing, spaces/tabs/newlines in single-quoted strings won't work. std::vector value(w->begin() + 1, w->end() - 1); @@ -72,7 +69,7 @@ CScript ParseScript(std::string s) // opcode, e.g. OP_ADD or ADD: result << mapOpNames[*w]; } else { - throw runtime_error("script parse error"); + throw std::runtime_error("script parse error"); } } @@ -84,7 +81,7 @@ bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitne if (!IsHex(strHexTx)) return false; - vector txData(ParseHex(strHexTx)); + std::vector txData(ParseHex(strHexTx)); if (fTryNoWitness) { CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); @@ -125,30 +122,30 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk) return true; } -uint256 ParseHashUV(const UniValue& v, const string& strName) +uint256 ParseHashUV(const UniValue& v, const std::string& strName) { - string strHex; + std::string strHex; if (v.isStr()) strHex = v.getValStr(); - return ParseHashStr(strHex, strName); // Note: ParseHashStr("") throws a runtime_error + return ParseHashStr(strHex, strName); // Note: ParseHashStr("") throws a std::runtime_error } uint256 ParseHashStr(const std::string& strHex, const std::string& strName) { if (!IsHex(strHex)) // Note: IsHex("") is false - throw runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); + throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); uint256 result; result.SetHex(strHex); return result; } -vector ParseHexUV(const UniValue& v, const string& strName) +std::vector ParseHexUV(const UniValue& v, const std::string& strName) { - string strHex; + std::string strHex; if (v.isStr()) strHex = v.getValStr(); if (!IsHex(strHex)) - throw runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); + throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); return ParseHex(strHex); } diff --git a/src/core_write.cpp b/src/core_write.cpp index 574008de2c46..0669457a4263 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -6,7 +6,7 @@ #include "base58.h" #include "primitives/transaction.h" -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "script/script.h" #include "script/standard.h" #include "serialize.h" @@ -16,18 +16,17 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" -#include -using namespace std; -string FormatScript(const CScript& script) + +std::string FormatScript(const CScript& script) { - string ret; + std::string ret; CScript::const_iterator it = script.begin(); opcodetype op; while (it != script.end()) { CScript::const_iterator it2 = it; - vector vch; + std::vector vch; if (script.GetOp2(it, op, &vch)) { if (op == OP_0) { ret += "0 "; @@ -36,9 +35,9 @@ string FormatScript(const CScript& script) ret += strprintf("%i ", op - OP_1NEGATE - 1); continue; } else if (op >= OP_NOP && op <= OP_CHECKMULTISIGVERIFY) { - string str(GetOpName(op)); - if (str.substr(0, 3) == string("OP_")) { - ret += str.substr(3, string::npos) + " "; + std::string str(GetOpName(op)); + if (str.substr(0, 3) == std::string("OP_")) { + ret += str.substr(3, std::string::npos) + " "; continue; } } @@ -67,7 +66,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, bool fIncludeHex) { txnouttype type; - vector addresses; + std::vector addresses; int nRequired; out.pushKV("asm", scriptPubKey.ToString()); @@ -83,7 +82,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); - BOOST_FOREACH (const CTxDestination& addr, addresses) + for (const CTxDestination& addr : addresses) a.push_back(EncodeDestination(addr)); out.pushKV("addresses", a); } @@ -95,7 +94,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin(UniValue::VARR); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); diff --git a/src/crypto/sph_blake.h b/src/crypto/sph_blake.h index d8d794399d00..bad7a5aa4bec 100644 --- a/src/crypto/sph_blake.h +++ b/src/crypto/sph_blake.h @@ -80,11 +80,11 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 H[8]; - sph_u32 S[4]; - sph_u32 T0, T1; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[8]; + sph_u32 S[4]; + sph_u32 T0, T1; #endif } sph_blake_small_context; @@ -114,11 +114,11 @@ typedef sph_blake_small_context sph_blake256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u64 H[8]; - sph_u64 S[4]; - sph_u64 T0, T1; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[8]; + sph_u64 S[4]; + sph_u64 T0, T1; #endif } sph_blake_big_context; @@ -179,7 +179,7 @@ void sph_blake224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BLAKE-256 context. This process performs no memory allocation. @@ -224,7 +224,7 @@ void sph_blake256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #if SPH_64 @@ -271,7 +271,7 @@ void sph_blake384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BLAKE-512 context. This process performs no memory allocation. @@ -316,7 +316,7 @@ void sph_blake512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #endif diff --git a/src/crypto/sph_bmw.h b/src/crypto/sph_bmw.h index d386b0c14053..aeae2fb4fddc 100644 --- a/src/crypto/sph_bmw.h +++ b/src/crypto/sph_bmw.h @@ -79,13 +79,13 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 H[16]; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[16]; #if SPH_64 - sph_u64 bit_count; + sph_u64 bit_count; #else - sph_u32 bit_count_high, bit_count_low; + sph_u32 bit_count_high, bit_count_low; #endif #endif } sph_bmw_small_context; @@ -116,10 +116,10 @@ typedef sph_bmw_small_context sph_bmw256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u64 H[16]; - sph_u64 bit_count; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[16]; + sph_u64 bit_count; #endif } sph_bmw_big_context; @@ -180,7 +180,7 @@ void sph_bmw224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BMW-256 context. This process performs no memory allocation. @@ -225,7 +225,7 @@ void sph_bmw256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #if SPH_64 @@ -272,7 +272,7 @@ void sph_bmw384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BMW-512 context. This process performs no memory allocation. @@ -317,7 +317,7 @@ void sph_bmw512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #endif diff --git a/src/crypto/sph_cubehash.h b/src/crypto/sph_cubehash.h index 487a1946ad40..f4f502cb5096 100644 --- a/src/crypto/sph_cubehash.h +++ b/src/crypto/sph_cubehash.h @@ -76,9 +76,9 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 state[32]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[32]; #endif } sph_cubehash_context; @@ -146,7 +146,7 @@ void sph_cubehash224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a CubeHash-256 context. This process performs no memory @@ -192,7 +192,7 @@ void sph_cubehash256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a CubeHash-384 context. This process performs no memory @@ -238,7 +238,7 @@ void sph_cubehash384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a CubeHash-512 context. This process performs no memory @@ -284,7 +284,7 @@ void sph_cubehash512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } #endif diff --git a/src/crypto/sph_echo.h b/src/crypto/sph_echo.h index 1ae1e3dd6243..aed0a1ae2428 100644 --- a/src/crypto/sph_echo.h +++ b/src/crypto/sph_echo.h @@ -76,15 +76,15 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[192]; /* first field, for alignment */ - size_t ptr; - union { - sph_u32 Vs[4][4]; + unsigned char buf[192]; /* first field, for alignment */ + size_t ptr; + union { + sph_u32 Vs[4][4]; #if SPH_64 - sph_u64 Vb[4][2]; + sph_u64 Vb[4][2]; #endif - } u; - sph_u32 C0, C1, C2, C3; + } u; + sph_u32 C0, C1, C2, C3; #endif } sph_echo_small_context; @@ -101,15 +101,15 @@ typedef struct { */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - union { - sph_u32 Vs[8][4]; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { + sph_u32 Vs[8][4]; #if SPH_64 - sph_u64 Vb[8][2]; + sph_u64 Vb[8][2]; #endif - } u; - sph_u32 C0, C1, C2, C3; + } u; + sph_u32 C0, C1, C2, C3; #endif } sph_echo_big_context; @@ -176,7 +176,7 @@ void sph_echo224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an ECHO-256 context. This process performs no memory allocation. @@ -221,7 +221,7 @@ void sph_echo256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an ECHO-384 context. This process performs no memory allocation. @@ -266,7 +266,7 @@ void sph_echo384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an ECHO-512 context. This process performs no memory allocation. @@ -311,8 +311,8 @@ void sph_echo512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - + void *cc, unsigned ub, unsigned n, void *dst); + #ifdef __cplusplus } #endif diff --git a/src/crypto/sph_groestl.h b/src/crypto/sph_groestl.h index 495f05e21174..bb638e9bdb38 100644 --- a/src/crypto/sph_groestl.h +++ b/src/crypto/sph_groestl.h @@ -74,18 +74,18 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - union { + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { #if SPH_64 - sph_u64 wide[8]; + sph_u64 wide[8]; #endif - sph_u32 narrow[16]; - } state; + sph_u32 narrow[16]; + } state; #if SPH_64 - sph_u64 count; + sph_u64 count; #else - sph_u32 count_high, count_low; + sph_u32 count_high, count_low; #endif #endif } sph_groestl_small_context; @@ -114,18 +114,18 @@ typedef sph_groestl_small_context sph_groestl256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - union { + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { #if SPH_64 - sph_u64 wide[16]; + sph_u64 wide[16]; #endif - sph_u32 narrow[32]; - } state; + sph_u32 narrow[32]; + } state; #if SPH_64 - sph_u64 count; + sph_u64 count; #else - sph_u32 count_high, count_low; + sph_u32 count_high, count_low; #endif #endif } sph_groestl_big_context; @@ -185,7 +185,7 @@ void sph_groestl224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Groestl-256 context. This process performs no memory allocation. @@ -230,7 +230,7 @@ void sph_groestl256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Groestl-384 context. This process performs no memory allocation. @@ -275,7 +275,7 @@ void sph_groestl384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Groestl-512 context. This process performs no memory allocation. @@ -320,7 +320,7 @@ void sph_groestl512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } diff --git a/src/crypto/sph_jh.h b/src/crypto/sph_jh.h index 82fae58df8cc..c8a9fabc05b5 100644 --- a/src/crypto/sph_jh.h +++ b/src/crypto/sph_jh.h @@ -75,18 +75,18 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - union { + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { #if SPH_64 - sph_u64 wide[16]; + sph_u64 wide[16]; #endif - sph_u32 narrow[32]; - } H; + sph_u32 narrow[32]; + } H; #if SPH_64 - sph_u64 block_count; + sph_u64 block_count; #else - sph_u32 block_count_high, block_count_low; + sph_u32 block_count_high, block_count_low; #endif #endif } sph_jh_context; @@ -154,7 +154,7 @@ void sph_jh224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a JH-256 context. This process performs no memory allocation. @@ -199,7 +199,7 @@ void sph_jh256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a JH-384 context. This process performs no memory allocation. @@ -244,7 +244,7 @@ void sph_jh384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a JH-512 context. This process performs no memory allocation. @@ -289,7 +289,7 @@ void sph_jh512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } diff --git a/src/crypto/sph_keccak.h b/src/crypto/sph_keccak.h index bdafdb88db02..233154209b9c 100644 --- a/src/crypto/sph_keccak.h +++ b/src/crypto/sph_keccak.h @@ -75,14 +75,14 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[144]; /* first field, for alignment */ - size_t ptr, lim; - union { + unsigned char buf[144]; /* first field, for alignment */ + size_t ptr, lim; + union { #if SPH_64 - sph_u64 wide[25]; + sph_u64 wide[25]; #endif - sph_u32 narrow[50]; - } u; + sph_u32 narrow[50]; + } u; #endif } sph_keccak_context; @@ -149,7 +149,7 @@ void sph_keccak224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Keccak-256 context. This process performs no memory allocation. @@ -194,7 +194,7 @@ void sph_keccak256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Keccak-384 context. This process performs no memory allocation. @@ -239,7 +239,7 @@ void sph_keccak384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Keccak-512 context. This process performs no memory allocation. @@ -284,7 +284,7 @@ void sph_keccak512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } diff --git a/src/crypto/sph_luffa.h b/src/crypto/sph_luffa.h index a32fd7b16be6..31182933d311 100644 --- a/src/crypto/sph_luffa.h +++ b/src/crypto/sph_luffa.h @@ -75,9 +75,9 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 V[3][8]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[3][8]; #endif } sph_luffa224_context; @@ -92,9 +92,9 @@ typedef sph_luffa224_context sph_luffa256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 V[4][8]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[4][8]; #endif } sph_luffa384_context; @@ -103,9 +103,9 @@ typedef struct { */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 V[5][8]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[5][8]; #endif } sph_luffa512_context; @@ -152,7 +152,7 @@ void sph_luffa224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Luffa-256 context. This process performs no memory allocation. @@ -197,7 +197,7 @@ void sph_luffa256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Luffa-384 context. This process performs no memory allocation. @@ -242,7 +242,7 @@ void sph_luffa384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Luffa-512 context. This process performs no memory allocation. @@ -287,10 +287,10 @@ void sph_luffa512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - + void *cc, unsigned ub, unsigned n, void *dst); + #ifdef __cplusplus } #endif - + #endif diff --git a/src/crypto/sph_shavite.h b/src/crypto/sph_shavite.h index 0957e42a9f0e..ed13b753b0cb 100644 --- a/src/crypto/sph_shavite.h +++ b/src/crypto/sph_shavite.h @@ -77,10 +77,10 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 h[8]; - sph_u32 count0, count1; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 h[8]; + sph_u32 count0, count1; #endif } sph_shavite_small_context; @@ -108,10 +108,10 @@ typedef sph_shavite_small_context sph_shavite256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u32 h[16]; - sph_u32 count0, count1, count2, count3; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u32 h[16]; + sph_u32 count0, count1, count2, count3; #endif } sph_shavite_big_context; @@ -170,7 +170,7 @@ void sph_shavite224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a SHAvite-256 context. This process performs no memory allocation. @@ -215,7 +215,7 @@ void sph_shavite256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a SHAvite-384 context. This process performs no memory allocation. @@ -260,7 +260,7 @@ void sph_shavite384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a SHAvite-512 context. This process performs no memory allocation. @@ -305,10 +305,10 @@ void sph_shavite512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - + void *cc, unsigned ub, unsigned n, void *dst); + #ifdef __cplusplus } -#endif - +#endif + #endif diff --git a/src/crypto/sph_simd.h b/src/crypto/sph_simd.h index 92ee1e7275c4..c674db2ce8ae 100644 --- a/src/crypto/sph_simd.h +++ b/src/crypto/sph_simd.h @@ -76,10 +76,10 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 state[16]; - sph_u32 count_low, count_high; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[16]; + sph_u32 count_low, count_high; #endif } sph_simd_small_context; @@ -96,10 +96,10 @@ typedef struct { */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u32 state[32]; - sph_u32 count_low, count_high; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[32]; + sph_u32 count_low, count_high; #endif } sph_simd_big_context; @@ -166,7 +166,7 @@ void sph_simd224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an SIMD-256 context. This process performs no memory allocation. @@ -211,7 +211,7 @@ void sph_simd256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an SIMD-384 context. This process performs no memory allocation. @@ -256,7 +256,7 @@ void sph_simd384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an SIMD-512 context. This process performs no memory allocation. @@ -301,7 +301,7 @@ void sph_simd512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } #endif diff --git a/src/crypto/sph_skein.h b/src/crypto/sph_skein.h index bddbc86fa5aa..924ba7413c3e 100644 --- a/src/crypto/sph_skein.h +++ b/src/crypto/sph_skein.h @@ -82,10 +82,10 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u64 h0, h1, h2, h3, h4, h5, h6, h7; - sph_u64 bcount; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u64 h0, h1, h2, h3, h4, h5, h6, h7; + sph_u64 bcount; #endif } sph_skein_big_context; @@ -152,7 +152,7 @@ void sph_skein224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Skein-256 context. This process performs no memory allocation. @@ -197,7 +197,7 @@ void sph_skein256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Skein-384 context. This process performs no memory allocation. @@ -242,7 +242,7 @@ void sph_skein384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Skein-512 context. This process performs no memory allocation. @@ -287,7 +287,7 @@ void sph_skein512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #endif diff --git a/src/crypto/sph_types.h b/src/crypto/sph_types.h index 7295b0b37097..cef79bde12d5 100644 --- a/src/crypto/sph_types.h +++ b/src/crypto/sph_types.h @@ -1028,7 +1028,7 @@ typedef long long sph_s64; * 64-bit Sparc architecture (implies v9). */ #elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ - || defined __sparcv9 + || defined __sparcv9 #define SPH_DETECT_BIG_ENDIAN 1 #define SPH_DETECT_UPTR sph_u64 @@ -1041,7 +1041,7 @@ typedef long long sph_s64; * 32-bit Sparc. */ #elif (defined __sparc__ || defined __sparc) \ - && !(defined __sparcv9 || defined __arch64__) + && !(defined __sparcv9 || defined __arch64__) #define SPH_DETECT_BIG_ENDIAN 1 #define SPH_DETECT_UPTR sph_u32 @@ -1075,7 +1075,7 @@ typedef long long sph_s64; * PowerPC. */ #elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ - || defined _ARCH_PPC + || defined _ARCH_PPC /* * Note: we do not declare cross-endian access to be "fast": even if @@ -1101,7 +1101,7 @@ typedef long long sph_s64; * Itanium, 64-bit. */ #elif defined __ia64 || defined __ia64__ \ - || defined __itanium__ || defined _M_IA64 + || defined __itanium__ || defined _M_IA64 #if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN #define SPH_DETECT_BIG_ENDIAN 1 @@ -1187,8 +1187,8 @@ typedef long long sph_s64; static SPH_INLINE sph_u32 sph_bswap32(sph_u32 x) { - __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); - return x; + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; } #if SPH_64 @@ -1196,8 +1196,8 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - return ((sph_u64)sph_bswap32((sph_u32)x) << 32) - | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); } #endif @@ -1212,8 +1212,8 @@ sph_bswap64(sph_u64 x) static SPH_INLINE sph_u32 sph_bswap32(sph_u32 x) { - __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); - return x; + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; } #if SPH_64 @@ -1221,8 +1221,8 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); - return x; + __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); + return x; } #endif @@ -1238,11 +1238,11 @@ sph_bswap64(sph_u64 x) static __inline sph_u32 __declspec(naked) __fastcall sph_bswap32(sph_u32 x) { - __asm { - bswap ecx - mov eax,ecx - ret - } + __asm { + bswap ecx + mov eax,ecx + ret + } } #if SPH_64 @@ -1250,8 +1250,8 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - return ((sph_u64)sph_bswap32((sph_u32)x) << 32) - | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); } #endif @@ -1265,10 +1265,10 @@ sph_bswap64(sph_u64 x) static SPH_INLINE sph_u32 sph_bswap32(sph_u32 x) { - x = SPH_T32((x << 16) | (x >> 16)); - x = ((x & SPH_C32(0xFF00FF00)) >> 8) - | ((x & SPH_C32(0x00FF00FF)) << 8); - return x; + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; } #if SPH_64 @@ -1282,12 +1282,12 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - x = SPH_T64((x << 32) | (x >> 32)); - x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) - | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); - x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) - | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); - return x; + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; } #endif @@ -1313,48 +1313,48 @@ sph_bswap64(sph_u64 x) */ #define SPH_SPARCV9_SET_ASI \ - sph_u32 sph_sparcv9_asi; \ - __asm__ __volatile__ ( \ - "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); + sph_u32 sph_sparcv9_asi; \ + __asm__ __volatile__ ( \ + "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); #define SPH_SPARCV9_RESET_ASI \ - __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); + __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); #define SPH_SPARCV9_DEC32LE(base, idx) ({ \ - sph_u32 sph_sparcv9_tmp; \ - __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ - : "=r" (sph_sparcv9_tmp) : "r" (base)); \ - sph_sparcv9_tmp; \ - }) + sph_u32 sph_sparcv9_tmp; \ + __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ + : "=r" (sph_sparcv9_tmp) : "r" (base)); \ + sph_sparcv9_tmp; \ + }) #endif static SPH_INLINE void sph_enc16be(void *dst, unsigned val) { - ((unsigned char *)dst)[0] = (val >> 8); - ((unsigned char *)dst)[1] = val; + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; } static SPH_INLINE unsigned sph_dec16be(const void *src) { - return ((unsigned)(((const unsigned char *)src)[0]) << 8) - | (unsigned)(((const unsigned char *)src)[1]); + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); } static SPH_INLINE void sph_enc16le(void *dst, unsigned val) { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = val >> 8; + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; } static SPH_INLINE unsigned sph_dec16le(const void *src) { - return (unsigned)(((const unsigned char *)src)[0]) - | ((unsigned)(((const unsigned char *)src)[1]) << 8); + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); } /** @@ -1369,27 +1369,27 @@ sph_enc32be(void *dst, sph_u32 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #else - if (((SPH_UPTR)dst & 3) == 0) { + if (((SPH_UPTR)dst & 3) == 0) { #if SPH_LITTLE_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; - } else { - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; - } + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; + } #endif #else - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; #endif } @@ -1404,14 +1404,14 @@ static SPH_INLINE void sph_enc32be_aligned(void *dst, sph_u32 val) { #if SPH_LITTLE_ENDIAN - *(sph_u32 *)dst = sph_bswap32(val); + *(sph_u32 *)dst = sph_bswap32(val); #elif SPH_BIG_ENDIAN - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #else - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; #endif } @@ -1427,29 +1427,29 @@ sph_dec32be(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif #else - if (((SPH_UPTR)src & 3) == 0) { + if (((SPH_UPTR)src & 3) == 0) { #if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif - } else { - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); - } + } else { + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); + } #endif #else - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); #endif } @@ -1464,14 +1464,14 @@ static SPH_INLINE sph_u32 sph_dec32be_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #elif SPH_BIG_ENDIAN - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #else - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); #endif } @@ -1487,27 +1487,27 @@ sph_enc32le(void *dst, sph_u32 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #else - if (((SPH_UPTR)dst & 3) == 0) { + if (((SPH_UPTR)dst & 3) == 0) { #if SPH_BIG_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; - } else { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - } + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + } #endif #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); #endif } @@ -1522,14 +1522,14 @@ static SPH_INLINE void sph_enc32le_aligned(void *dst, sph_u32 val) { #if SPH_LITTLE_ENDIAN - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #elif SPH_BIG_ENDIAN - *(sph_u32 *)dst = sph_bswap32(val); + *(sph_u32 *)dst = sph_bswap32(val); #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); #endif } @@ -1545,25 +1545,25 @@ sph_dec32le(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif #else - if (((SPH_UPTR)src & 3) == 0) { + if (((SPH_UPTR)src & 3) == 0) { #if SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC && !SPH_NO_ASM - sph_u32 tmp; - - /* - * "__volatile__" is needed here because without it, - * gcc-3.4.3 miscompiles the code and performs the - * access before the test on the address, thus triggering - * a bus error... - */ - __asm__ __volatile__ ( - "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + sph_u32 tmp; + + /* + * "__volatile__" is needed here because without it, + * gcc-3.4.3 miscompiles the code and performs the + * access before the test on the address, thus triggering + * a bus error... + */ + __asm__ __volatile__ ( + "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * On PowerPC, this turns out not to be worth the effort: the inline * assembly makes GCC optimizer uncomfortable, which tends to nullify @@ -1577,30 +1577,30 @@ sph_dec32le(const void *src) * functions, the generic code appears to be efficient enough already. * #elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM - sph_u32 tmp; + sph_u32 tmp; - __asm__ __volatile__ ( - "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ( + "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #endif #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif - } else { - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); - } + } else { + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + } #endif #else - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); #endif } @@ -1615,30 +1615,30 @@ static SPH_INLINE sph_u32 sph_dec32le_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #elif SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC && !SPH_NO_ASM - sph_u32 tmp; + sph_u32 tmp; - __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * Not worth it generally. * #elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM - sph_u32 tmp; + sph_u32 tmp; - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #endif #else - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); #endif } @@ -1656,35 +1656,35 @@ sph_enc64be(void *dst, sph_u64 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - val = sph_bswap64(val); + val = sph_bswap64(val); #endif - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #else - if (((SPH_UPTR)dst & 7) == 0) { + if (((SPH_UPTR)dst & 7) == 0) { #if SPH_LITTLE_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; - } else { - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; - } + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; + } #endif #else - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; #endif } @@ -1699,18 +1699,18 @@ static SPH_INLINE void sph_enc64be_aligned(void *dst, sph_u64 val) { #if SPH_LITTLE_ENDIAN - *(sph_u64 *)dst = sph_bswap64(val); + *(sph_u64 *)dst = sph_bswap64(val); #elif SPH_BIG_ENDIAN - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #else - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; #endif } @@ -1726,37 +1726,37 @@ sph_dec64be(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #else - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #endif #else - if (((SPH_UPTR)src & 7) == 0) { + if (((SPH_UPTR)src & 7) == 0) { #if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #else - return *(const sph_u64 *)src; -#endif - } else { - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); - } + return *(const sph_u64 *)src; +#endif + } else { + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); + } #endif #else - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); #endif } @@ -1771,18 +1771,18 @@ static SPH_INLINE sph_u64 sph_dec64be_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #elif SPH_BIG_ENDIAN - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #else - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); #endif } @@ -1798,35 +1798,35 @@ sph_enc64le(void *dst, sph_u64 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - val = sph_bswap64(val); + val = sph_bswap64(val); #endif - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #else - if (((SPH_UPTR)dst & 7) == 0) { + if (((SPH_UPTR)dst & 7) == 0) { #if SPH_BIG_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; - } else { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); - } + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); + } #endif #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); #endif } @@ -1841,18 +1841,18 @@ static SPH_INLINE void sph_enc64le_aligned(void *dst, sph_u64 val) { #if SPH_LITTLE_ENDIAN - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #elif SPH_BIG_ENDIAN - *(sph_u64 *)dst = sph_bswap64(val); + *(sph_u64 *)dst = sph_bswap64(val); #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); #endif } @@ -1868,59 +1868,59 @@ sph_dec64le(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #else - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #endif #else - if (((SPH_UPTR)src & 7) == 0) { + if (((SPH_UPTR)src & 7) == 0) { #if SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ( - "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ( + "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * Not worth it generally. * #elif SPH_PPC32_GCC && !SPH_NO_ASM - return (sph_u64)sph_dec32le_aligned(src) - | ((sph_u64)sph_dec32le_aligned( - (const char *)src + 4) << 32); + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned( + (const char *)src + 4) << 32); #elif SPH_PPC64_GCC && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ( - "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ( + "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #endif #else - return *(const sph_u64 *)src; -#endif - } else { - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); - } + return *(const sph_u64 *)src; +#endif + } else { + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + } #endif #else - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); #endif } @@ -1935,37 +1935,37 @@ static SPH_INLINE sph_u64 sph_dec64le_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #elif SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * Not worth it generally. * #elif SPH_PPC32_GCC && !SPH_NO_ASM - return (sph_u64)sph_dec32le_aligned(src) - | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); #elif SPH_PPC64_GCC && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #endif #else - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); #endif } diff --git a/src/denomination_functions.cpp b/src/denomination_functions.cpp index 5c88b348439f..d6ec569fc8e3 100644 --- a/src/denomination_functions.cpp +++ b/src/denomination_functions.cpp @@ -10,29 +10,28 @@ #include "denomination_functions.h" -using namespace libzerocoin; // ------------------------------------------------------------------------------------------------------- // Number of coins used for either change or a spend given a map of coins used // ------------------------------------------------------------------------------------------------------- int getNumberOfCoinsUsed( - const std::map& mapChange) + const std::map& mapChange) { int nChangeCount = 0; - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { nChangeCount += mapChange.at(denom); } return nChangeCount; } // ------------------------------------------------------------------------------------------------------- -// Find the max CoinDenomination amongst held coins +// Find the maxlibzerocoin::CoinDenomination amongst held coins // ------------------------------------------------------------------------------------------------------- -CoinDenomination getMaxDenomHeld( - const std::map& mapCoinsHeld) +libzerocoin::CoinDenomination getMaxDenomHeld( + const std::map& mapCoinsHeld) { - CoinDenomination maxDenom = ZQ_ERROR; - for (auto& coin : reverse_iterate(zerocoinDenomList)) { + libzerocoin::CoinDenomination maxDenom = libzerocoin::ZQ_ERROR; + for (auto& coin : reverse_iterate(libzerocoin::zerocoinDenomList)) { if (mapCoinsHeld.at(coin)) { maxDenom = coin; break; @@ -43,19 +42,19 @@ CoinDenomination getMaxDenomHeld( // ------------------------------------------------------------------------------------------------------- // Get Exact Amount with CoinsHeld // ------------------------------------------------------------------------------------------------------- -std::map getSpendCoins(const CAmount nValueTarget, - const std::map mapOfDenomsHeld) +std::map getSpendCoins(const CAmount nValueTarget, + const std::map mapOfDenomsHeld) { - std::map mapUsed; + std::map mapUsed; CAmount nRemainingValue = nValueTarget; // Initialize - for (const auto& denom : zerocoinDenomList) - mapUsed.insert(std::pair(denom, 0)); + for (const auto& denom : libzerocoin::zerocoinDenomList) + mapUsed.insert(std::pair(denom, 0)); // Start with the Highest Denomination coin and grab coins as long as the remaining amount is greater than the // current denomination value and we have the denom - for (auto& coin : reverse_iterate(zerocoinDenomList)) { + for (auto& coin : reverse_iterate(libzerocoin::zerocoinDenomList)) { CAmount nValue = ZerocoinDenominationToAmount(coin); do { if ((nRemainingValue >= nValue) && (mapUsed.at(coin) < mapOfDenomsHeld.at(coin))) { @@ -70,17 +69,17 @@ std::map getSpendCoins(const CAmount nValueTarget, // ------------------------------------------------------------------------------------------------------- // Get change (no limits) // ------------------------------------------------------------------------------------------------------- -std::map getChange(const CAmount nValueTarget) +std::map getChange(const CAmount nValueTarget) { - std::map mapChange; + std::map mapChange; CAmount nRemainingValue = nValueTarget; // Initialize - for (const auto& denom : zerocoinDenomList) - mapChange.insert(std::pair(denom, 0)); + for (const auto& denom : libzerocoin::zerocoinDenomList) + mapChange.insert(std::pair(denom, 0)); // Start with the Highest Denomination coin and grab coins as long as the remaining amount is greater than the // current denomination value - for (auto& coin : reverse_iterate(zerocoinDenomList)) { + for (auto& coin : reverse_iterate(libzerocoin::zerocoinDenomList)) { CAmount nValue = ZerocoinDenominationToAmount(coin); do { if (nRemainingValue >= nValue) { @@ -99,17 +98,17 @@ std::map getChange(const CAmount nValueTarget) bool getIdealSpends( const CAmount nValueTarget, const std::list& listMints, - const std::map mapOfDenomsHeld, - std::map& mapOfDenomsUsed) + const std::map mapOfDenomsHeld, + std::map& mapOfDenomsUsed) { CAmount nRemainingValue = nValueTarget; // Initialize - for (const auto& denom : zerocoinDenomList) - mapOfDenomsUsed.insert(std::pair(denom, 0)); + for (const auto& denom : libzerocoin::zerocoinDenomList) + mapOfDenomsUsed.insert(std::pair(denom, 0)); // Start with the Highest Denomination coin and grab coins as long as the remaining amount is greater than the // current denomination value - for (auto& coin : reverse_iterate(zerocoinDenomList)) { + for (auto& coin : reverse_iterate(libzerocoin::zerocoinDenomList)) { for (const CMintMeta& mint : listMints) { if (mint.isUsed) continue; if (nRemainingValue >= ZerocoinDenominationToAmount(coin) && coin == mint.denom) { @@ -127,12 +126,12 @@ bool getIdealSpends( // ------------------------------------------------------------------------------------------------------- std::vector getSpends( const std::list& listMints, - std::map& mapOfDenomsUsed, + std::map& mapOfDenomsUsed, CAmount& nCoinsSpentValue) { std::vector vSelectedMints; nCoinsSpentValue = 0; - for (auto& coin : reverse_iterate(zerocoinDenomList)) { + for (auto& coin : reverse_iterate(libzerocoin::zerocoinDenomList)) { do { for (const CMintMeta& mint : listMints) { if (mint.isUsed) continue; @@ -169,14 +168,14 @@ void listSpends(const std::vector& vSelectedMints) } // ------------------------------------------------------------------------------------------------------- -// Find the CoinDenomination with the most number for a given amount +// Find thelibzerocoin::CoinDenomination with the most number for a given amount // ------------------------------------------------------------------------------------------------------- -CoinDenomination getDenomWithMostCoins( - const std::map& mapOfDenomsUsed) +libzerocoin::CoinDenomination getDenomWithMostCoins( + const std::map& mapOfDenomsUsed) { - CoinDenomination maxCoins = ZQ_ERROR; + libzerocoin::CoinDenomination maxCoins = libzerocoin::ZQ_ERROR; CAmount nMaxNumber = 0; - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { CAmount amount = mapOfDenomsUsed.at(denom); if (amount > nMaxNumber) { nMaxNumber = amount; @@ -186,12 +185,12 @@ CoinDenomination getDenomWithMostCoins( return maxCoins; } // ------------------------------------------------------------------------------------------------------- -// Get the next denomination above the current one. Return ZQ_ERROR if already at the highest +// Get the next denomination above the current one. Return libzerocoin::ZQ_ERROR if already at the highest // ------------------------------------------------------------------------------------------------------- -CoinDenomination getNextHighestDenom(const CoinDenomination& this_denom) +libzerocoin::CoinDenomination getNextHighestDenom(const libzerocoin::CoinDenomination& this_denom) { - CoinDenomination nextValue = ZQ_ERROR; - for (const auto& denom : zerocoinDenomList) { + libzerocoin::CoinDenomination nextValue = libzerocoin::ZQ_ERROR; + for (const auto& denom : libzerocoin::zerocoinDenomList) { if (ZerocoinDenominationToAmount(denom) > ZerocoinDenominationToAmount(this_denom)) { nextValue = denom; break; @@ -201,13 +200,13 @@ CoinDenomination getNextHighestDenom(const CoinDenomination& this_denom) } // ------------------------------------------------------------------------------------------------------- // Get the next denomination below the current one that is also amongst those held. -// Return ZQ_ERROR if none found +// Return libzerocoin::ZQ_ERROR if none found // ------------------------------------------------------------------------------------------------------- -CoinDenomination getNextLowerDenomHeld(const CoinDenomination& this_denom, - const std::map& mapCoinsHeld) +libzerocoin::CoinDenomination getNextLowerDenomHeld(const libzerocoin::CoinDenomination& this_denom, + const std::map& mapCoinsHeld) { - CoinDenomination nextValue = ZQ_ERROR; - for (auto& denom : reverse_iterate(zerocoinDenomList)) { + libzerocoin::CoinDenomination nextValue = libzerocoin::ZQ_ERROR; + for (auto& denom : reverse_iterate(libzerocoin::zerocoinDenomList)) { if ((denom < this_denom) && (mapCoinsHeld.at(denom) != 0)) { nextValue = denom; break; @@ -219,10 +218,10 @@ CoinDenomination getNextLowerDenomHeld(const CoinDenomination& this_denom, int minimizeChange( int nMaxNumberOfSpends, int nChangeCount, - const CoinDenomination nextToMaxDenom, + const libzerocoin::CoinDenomination nextToMaxDenom, const CAmount nValueTarget, - const std::map& mapOfDenomsHeld, - std::map& mapOfDenomsUsed) + const std::map& mapOfDenomsHeld, + std::map& mapOfDenomsUsed) { // Now find out if possible without using 1 coin such that we have more spends but less change // First get set of coins close to value but still less than value (since not exact) @@ -231,13 +230,13 @@ int minimizeChange( int nCoinCount = 0; // Re-clear this - std::map savedMapOfDenomsUsed = mapOfDenomsUsed; - for (const auto& denom : zerocoinDenomList) + std::map savedMapOfDenomsUsed = mapOfDenomsUsed; + for (const auto& denom : libzerocoin::zerocoinDenomList) mapOfDenomsUsed.at(denom) = 0; // Find the amount this is less than total but uses up higher denoms first, // starting at the denom that is not greater than the overall total - for (const auto& denom : reverse_iterate(zerocoinDenomList)) { + for (const auto& denom : reverse_iterate(libzerocoin::zerocoinDenomList)) { if (denom <= nextToMaxDenom) { CAmount nValue = ZerocoinDenominationToAmount(denom); do { @@ -254,7 +253,7 @@ int minimizeChange( // Now work way back up from the bottom filling in with the denom that we have that is just // bigger than the remaining amount // Shouldn't need more than one coin here? - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { CAmount nValue = ZerocoinDenominationToAmount(denom); if ((nValue > nRemainingValue) && (mapOfDenomsUsed.at(denom) < mapOfDenomsHeld.at(denom))) { mapOfDenomsUsed.at(denom)++; @@ -272,11 +271,11 @@ int minimizeChange( // So 5 is no longer needed and will become change also CAmount nAltChangeAmount = AmountUsed - nValueTarget; - std::map mapAltChange = getChange(nAltChangeAmount); + std::map mapAltChange = getChange(nAltChangeAmount); // Check if there is overlap between change and spend denominations // And if so, remove those that overlap - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { do { if (mapAltChange.at(denom) && mapOfDenomsUsed.at(denom)) { mapOfDenomsUsed.at(denom)--; @@ -317,32 +316,32 @@ int calculateChange( int nMaxNumberOfSpends, bool fMinimizeChange, const CAmount nValueTarget, - const std::map& mapOfDenomsHeld, - std::map& mapOfDenomsUsed) + const std::map& mapOfDenomsHeld, + std::map& mapOfDenomsUsed) { - CoinDenomination minDenomOverTarget = ZQ_ERROR; + libzerocoin::CoinDenomination minDenomOverTarget = libzerocoin::ZQ_ERROR; // Initialize mapOfDenomsUsed.clear(); - for (const auto& denom : zerocoinDenomList) - mapOfDenomsUsed.insert(std::pair(denom, 0)); + for (const auto& denom : libzerocoin::zerocoinDenomList) + mapOfDenomsUsed.insert(std::pair(denom, 0)); - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { if (nValueTarget < ZerocoinDenominationToAmount(denom) && mapOfDenomsHeld.at(denom)) { minDenomOverTarget = denom; break; } } - // OK so if != ZQ_ERROR we have a solution using 1 coin - if (minDenomOverTarget != ZQ_ERROR) { + // OK so if != libzerocoin::ZQ_ERROR we have a solution using 1 coin + if (minDenomOverTarget != libzerocoin::ZQ_ERROR) { mapOfDenomsUsed.at(minDenomOverTarget) = 1; // Now find out # of coins in change CAmount nChangeAmount = ZerocoinDenominationToAmount(minDenomOverTarget) - nValueTarget; - std::map mapChange = getChange(nChangeAmount); + std::map mapChange = getChange(nChangeAmount); int nChangeCount = getNumberOfCoinsUsed(mapChange); if (fMinimizeChange) { - CoinDenomination nextToMaxDenom = getNextLowerDenomHeld(minDenomOverTarget, mapOfDenomsHeld); + libzerocoin::CoinDenomination nextToMaxDenom = getNextLowerDenomHeld(minDenomOverTarget, mapOfDenomsHeld); int newChangeCount = minimizeChange(nMaxNumberOfSpends, nChangeCount, nextToMaxDenom, nValueTarget, mapOfDenomsHeld, mapOfDenomsUsed); @@ -351,7 +350,7 @@ int calculateChange( if (newChangeCount < nChangeCount) return newChangeCount; // Reclear - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) mapOfDenomsUsed.at(denom) = 0; // Then reset as before previous clearing mapOfDenomsUsed.at(minDenomOverTarget) = 1; @@ -361,12 +360,12 @@ int calculateChange( } else { // Try to meet a different way - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) mapOfDenomsUsed.at(denom) = 0; CAmount nRemainingValue = nValueTarget; int nCoinCount = 0; CAmount AmountUsed = 0; - for (const auto& denom : reverse_iterate(zerocoinDenomList)) { + for (const auto& denom : reverse_iterate(libzerocoin::zerocoinDenomList)) { CAmount nValue = ZerocoinDenominationToAmount(denom); do { if (mapOfDenomsHeld.at(denom) && nRemainingValue > 0) { @@ -380,14 +379,14 @@ int calculateChange( } CAmount nChangeAmount = AmountUsed - nValueTarget; - std::map mapChange = getChange(nChangeAmount); + std::map mapChange = getChange(nChangeAmount); int nMaxChangeCount = getNumberOfCoinsUsed(mapChange); // Instead get max Denom held - CoinDenomination maxDenomHeld = getMaxDenomHeld(mapOfDenomsHeld); + libzerocoin::CoinDenomination maxDenomHeld = getMaxDenomHeld(mapOfDenomsHeld); // Assign for size (only) - std::map mapOfMinDenomsUsed = mapOfDenomsUsed; + std::map mapOfMinDenomsUsed = mapOfDenomsUsed; int nChangeCount = minimizeChange(nMaxNumberOfSpends, nMaxChangeCount, maxDenomHeld, nValueTarget, @@ -410,10 +409,10 @@ int calculateChange( // ------------------------------------------------------------------------------------------------------- std::vector SelectMintsFromList(const CAmount nValueTarget, CAmount& nSelectedValue, int nMaxNumberOfSpends, bool fMinimizeChange, int& nCoinsReturned, const std::list& listMints, - const std::map mapOfDenomsHeld, int& nNeededSpends) + const std::map mapOfDenomsHeld, int& nNeededSpends) { std::vector vSelectedMints; - std::map mapOfDenomsUsed; + std::map mapOfDenomsUsed; nNeededSpends = 0; bool fCanMeetExactly = getIdealSpends(nValueTarget, listMints, mapOfDenomsHeld, mapOfDenomsUsed); diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp index 4c7306e48aad..6e6ef19ee863 100644 --- a/src/ecwrapper.cpp +++ b/src/ecwrapper.cpp @@ -240,11 +240,11 @@ bool CECKey::Recover(const uint256& hash, const unsigned char* p64, int rec) BIGNUM *sig_s = NULL; if (!(sig_r = BN_bin2bn(&p64[0], 32, nullptr)) || !(sig_s = BN_bin2bn(&p64[32], 32, nullptr)) || - !ECDSA_SIG_set0(sig, sig_r, sig_s)) { - BN_free(sig_r); - BN_free(sig_s); - return false; - } + !ECDSA_SIG_set0(sig, sig_r, sig_s)) { + BN_free(sig_r); + BN_free(sig_s); + return false; + } #else BN_bin2bn(&p64[0], 32, sig->r); BN_bin2bn(&p64[32], 32, sig->s); diff --git a/src/hash.cpp b/src/hash.cpp index 95070558bca9..f7efa958698a 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -69,14 +69,14 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector> 24) & 0xFF; num[1] = (nChild >> 16) & 0xFF; num[2] = (nChild >> 8) & 0xFF; num[3] = (nChild >> 0) & 0xFF; - CHMAC_SHA512(chainCode, 32).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output); + CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output); } void scrypt_hash(const char* pass, unsigned int pLen, const char* salt, unsigned int sLen, char* output, unsigned int N, unsigned int r, unsigned int p, unsigned int dkLen) diff --git a/src/hash.h b/src/hash.h index 2d7305246e5a..c11acf9aacb4 100644 --- a/src/hash.h +++ b/src/hash.h @@ -6,8 +6,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_HASH_H -#define BITCOIN_HASH_H +#ifndef PHORE_HASH_H +#define PHORE_HASH_H #include "crypto/ripemd160.h" #include "crypto/sha256.h" @@ -28,7 +28,7 @@ #include #include -using namespace std; +typedef uint256 ChainCode; /** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */ class CHash256 @@ -156,9 +156,9 @@ inline std::string Hash(std::string input) SHA256_Init(&sha256); SHA256_Update(&sha256, input.c_str(), input.size()); SHA256_Final(hash, &sha256); - stringstream ss; + std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { - ss << hex << setw(2) << setfill('0') << (int)hash[i]; + ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i]; } return ss.str(); } @@ -321,7 +321,7 @@ uint256 SerializeHash(const T& obj, int nType = SER_GETHASH, int nVersion = PROT unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash); -void BIP32Hash(const unsigned char chainCode[32], unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); +void BIP32Hash(const ChainCode chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); //int HMAC_SHA512_Init(HMAC_SHA512_CTX *pctx, const void *pkey, size_t len); //int HMAC_SHA512_Update(HMAC_SHA512_CTX *pctx, const void *pdata, size_t len); @@ -415,4 +415,4 @@ inline uint256 HashQuark(const T1 pbegin, const T1 pend) void scrypt_hash(const char* pass, unsigned int pLen, const char* salt, unsigned int sLen, char* output, unsigned int N, unsigned int r, unsigned int p, unsigned int dkLen); -#endif // BITCOIN_HASH_H +#endif // PHORE_HASH_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 98ac750bb193..6194613ffe21 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -3,8 +3,8 @@ #include "base58.h" #include "chainparams.h" #include "httpserver.h" -#include "rpcprotocol.h" -#include "rpcserver.h" +#include "rpc/protocol.h" +#include "rpc/server.h" #include "random.h" #include "sync.h" #include "util.h" @@ -172,7 +172,7 @@ bool StartHTTPRPC() assert(EventBase()); httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase()); - RPCRegisterTimerInterface(httpRPCTimerInterface); + RPCSetTimerInterface(httpRPCTimerInterface); return true; } @@ -186,7 +186,7 @@ void StopHTTPRPC() LogPrint("rpc", "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); if (httpRPCTimerInterface) { - RPCUnregisterTimerInterface(httpRPCTimerInterface); + RPCUnsetTimerInterface(httpRPCTimerInterface); delete httpRPCTimerInterface; httpRPCTimerInterface = 0; } diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 6baaeff02835..1bb38592b678 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -8,7 +8,7 @@ #include "compat.h" #include "util.h" #include "netbase.h" -#include "rpcprotocol.h" // For HTTP status codes +#include "rpc/protocol.h" // For HTTP status codes #include "sync.h" #include "ui_interface.h" @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -34,10 +35,6 @@ #endif #endif -#include // for to_lower() -#include -#include - /** Maximum size of http request (request line + headers) */ static const size_t MAX_HEADERS_SIZE = 8192; @@ -54,7 +51,7 @@ class HTTPWorkItem : public HTTPClosure func(req.get(), path); } - boost::scoped_ptr req; + std::unique_ptr req; private: std::string path; @@ -69,8 +66,8 @@ class WorkQueue { private: /** Mutex protects entire object */ - CWaitableCriticalSection cs; - CConditionVariable cond; + std::mutex cs; + std::condition_variable cond; /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */ std::deque queue; bool running; @@ -84,12 +81,12 @@ class WorkQueue WorkQueue &wq; ThreadCounter(WorkQueue &w): wq(w) { - boost::lock_guard lock(wq.cs); + std::lock_guard lock(wq.cs); wq.numThreads += 1; } ~ThreadCounter() { - boost::lock_guard lock(wq.cs); + std::lock_guard lock(wq.cs); wq.numThreads -= 1; wq.cond.notify_all(); } @@ -114,7 +111,7 @@ class WorkQueue /** Enqueue a work item */ bool Enqueue(WorkItem* item) { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); if (queue.size() >= maxDepth) { return false; } @@ -129,7 +126,7 @@ class WorkQueue while (running) { WorkItem* i = 0; { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); while (running && queue.empty()) cond.wait(lock); if (!running) @@ -144,14 +141,14 @@ class WorkQueue /** Interrupt and exit loops */ void Interrupt() { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); running = false; cond.notify_all(); } /** Wait for worker threads to exit */ void WaitExit() { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); while (numThreads > 0) cond.wait(lock); } @@ -159,7 +156,7 @@ class WorkQueue /** Return current depth of queue */ size_t Depth() { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); return queue.size(); } }; @@ -195,7 +192,7 @@ static bool ClientAllowed(const CNetAddr& netaddr) { if (!netaddr.IsValid()) return false; - BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets) + for (const CSubNet& subnet : rpc_allow_subnets) if (subnet.Match(netaddr)) return true; return false; @@ -209,7 +206,7 @@ static bool InitHTTPAllowList() rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost if (mapMultiArgs.count("-rpcallowip")) { const std::vector& vAllow = mapMultiArgs["-rpcallowip"]; - BOOST_FOREACH (std::string strAllow, vAllow) { + for (std::string strAllow : vAllow) { CSubNet subnet(strAllow); if (!subnet.IsValid()) { uiInterface.ThreadSafeMessageBox( @@ -221,7 +218,7 @@ static bool InitHTTPAllowList() } } std::string strAllowed; - BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets) + for (const CSubNet& subnet : rpc_allow_subnets) strAllowed += subnet.ToString() + " "; LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed); return true; @@ -305,13 +302,14 @@ static void http_reject_request_cb(struct evhttp_request* req, void*) evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); } /** Event dispatcher thread */ -static void ThreadHTTP(struct event_base* base, struct evhttp* http) +static bool ThreadHTTP(struct event_base* base, struct evhttp* http) { RenameThread("bitcoin-http"); LogPrint("http", "Entering http event loop\n"); event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() LogPrint("http", "Exited http event loop\n"); + return event_base_got_break(base) == 0; } /** Bind HTTP server to specified addresses */ @@ -440,17 +438,22 @@ bool InitHTTPServer() return true; } -boost::thread threadHTTP; +std::thread threadHTTP; +std::future threadResult; bool StartHTTPServer() { LogPrint("http", "Starting HTTP server\n"); int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L); LogPrintf("HTTP: starting %d worker threads\n", rpcThreads); - threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); + std::packaged_task task(ThreadHTTP); + threadResult = task.get_future(); + threadHTTP = std::thread(std::move(task), eventBase, eventHTTP); - for (int i = 0; i < rpcThreads; i++) - boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + for (int i = 0; i < rpcThreads; i++) { + std::thread rpc_worker(HTTPWorkQueueRun, workQueue); + rpc_worker.detach(); + } return true; } @@ -458,7 +461,7 @@ void InterruptHTTPServer() { LogPrint("http", "Interrupting HTTP server\n"); if (eventHTTP) { - BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) { + for (evhttp_bound_socket *socket : boundSockets) { evhttp_del_accept_socket(eventHTTP, socket); } evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL); @@ -484,15 +487,12 @@ void StopHTTPServer() // master that appears to be solved, so in the future that solution // could be used again (if desirable). // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990) -#if BOOST_VERSION >= 105000 - if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) { -#else - if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) { -#endif + if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) { LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n"); event_base_loopbreak(eventBase); - threadHTTP.join(); + } + threadHTTP.join(); } if (eventHTTP) { evhttp_free(eventHTTP); @@ -519,7 +519,7 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data) delete self; } -HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function& handler): +HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function& handler): deleteWhenTriggered(deleteWhenTriggered), handler(handler) { ev = event_new(base, -1, 0, httpevent_callback_fn, this); @@ -601,7 +601,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); HTTPEvent* ev = new HTTPEvent(eventBase, true, - boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); + std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); ev->trigger(0); replySent = true; req = 0; // transferred back to main thread diff --git a/src/httpserver.h b/src/httpserver.h index ff4f7c43666d..53c387e19f28 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -7,9 +7,7 @@ #include #include -#include -#include -#include +#include static const int DEFAULT_RPC_SERIALIZE_VERSION = 1; static const int DEFAULT_HTTP_THREADS=4; @@ -36,7 +34,7 @@ void InterruptHTTPServer(); void StopHTTPServer(); /** Handler for requests to a certain HTTP path */ -typedef boost::function HTTPRequestHandler; +typedef std::function HTTPRequestHandler; /** Register handler for prefix. * If multiple handlers match a prefix, the first-registered one will * be invoked. @@ -133,7 +131,7 @@ class HTTPEvent * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called) * handler is the handler to call when the event is triggered. */ - HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function& handler); + HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function& handler); ~HTTPEvent(); /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after @@ -142,7 +140,7 @@ class HTTPEvent void trigger(struct timeval* tv); bool deleteWhenTriggered; - boost::function handler; + std::function handler; private: struct event* ev; }; diff --git a/src/init.cpp b/src/init.cpp index 183b948ae3e5..5ee8fd4ff12b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -29,7 +29,7 @@ #include "masternodeman.h" #include "miner.h" #include "net.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "script/standard.h" #include "scheduler.h" #include "spork.h" @@ -61,14 +61,13 @@ #include #include #include +#include #include #if ENABLE_ZMQ #include "zmq/zmqnotificationinterface.h" #endif -using namespace boost; -using namespace std; #ifdef ENABLE_WALLET CWallet* pwalletMain = NULL; @@ -166,15 +165,17 @@ class CCoinsViewErrorCatcher : public CCoinsViewBacked static CCoinsViewDB* pcoinsdbview = NULL; static CCoinsViewErrorCatcher* pcoinscatcher = NULL; +static boost::scoped_ptr globalVerifyHandle; -void Interrupt(boost::thread_group& threadGroup) +static boost::thread_group threadGroup; +static CScheduler scheduler; +void Interrupt() { InterruptHTTPServer(); InterruptHTTPRPC(); InterruptRPC(); InterruptREST(); InterruptTorControl(); - threadGroup.interrupt_all(); } /** Preparing steps before shutting down or restarting the wallet */ @@ -209,6 +210,11 @@ void PrepareShutdown() DumpMasternodePayments(); UnregisterNodeSignals(GetNodeSignals()); + // After everything has been shut down, but before things get flushed, stop the + // CScheduler/checkqueue threadGroup + threadGroup.interrupt_all(); + threadGroup.join_all(); + if (fFeeEstimatesInitialized) { boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_fileout(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION); @@ -286,6 +292,8 @@ void Shutdown() delete zwalletMain; zwalletMain = NULL; #endif + globalVerifyHandle.reset(); + ECC_Stop(); LogPrintf("%s: done\n", __func__); } @@ -330,10 +338,10 @@ void OnRPCPreCommand(const CRPCCommand& cmd) #endif // Observe safe mode - string strWarning = GetWarnings("rpc"); + std::string strWarning = GetWarnings("rpc"); if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && !cmd.okSafeMode) - throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); + throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning); } std::string HelpMessage(HelpMessageMode mode) @@ -342,7 +350,7 @@ std::string HelpMessage(HelpMessageMode mode) // When adding new options to the categories, please keep and ensure alphabetical ordering. // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators. - string strUsage = HelpMessageGroup(_("Options:")); + std::string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); strUsage += HelpMessageOpt("-version", _("Print version and exit")); strUsage += HelpMessageOpt("-alertnotify=", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); @@ -463,6 +471,7 @@ std::string HelpMessage(HelpMessageMode mode) #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); + strUsage += HelpMessageOpt("-uacomment=", _("Append comment to the user agent string")); if (GetBoolArg("-help-debug", false)) { strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkmempool=", strprintf("Run checks every transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); @@ -477,7 +486,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0)); strUsage += HelpMessageOpt("-sporkkey=", _("Enable spork administration functionality with the appropriate private key.")); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, tor, mempool, net, proxy, http, libevent, phore, (obfuscation, swiftx, masternode, mnpayments, mnbudget, zero, precompute, staking)"; // Don't translate these and qt below + std::string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, tor, mempool, net, proxy, http, libevent, phore, (obfuscation, swiftx, masternode, mnpayments, mnbudget, zero, precompute, staking)"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + @@ -496,6 +505,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-relaypriority", strprintf(_("Require high priority for relaying free or low-fee transactions (default:%u)"), 1)); strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf(_("Limit size of signature cache to entries (default: %u)"), 50000)); } + strUsage += HelpMessageOpt("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in PHR/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK()))); strUsage += HelpMessageOpt("-printtoconsole", strprintf(_("Send trace/debug info to console instead of debug.log file (default: %u)"), 0)); if (GetBoolArg("-help-debug", false)) { @@ -534,8 +544,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-backupzphr=", strprintf(_("Enable automatic wallet backups triggered after each zPhr minting (0-1, default: %u)"), 1)); strUsage += HelpMessageOpt("-zphrbackuppath=", _("Specify custom backup path to add a copy of any automatic zPHR backup. If set as dir, every backup generates a timestamped file. If set as file, will rewrite to that file every backup. If backuppath is set as well, 4 backups will happen")); #endif -// strUsage += " -anonymizephoreamount= " + strprintf(_("Keep N PHR anonymized (default: %u)"), 0) + "\n"; -// strUsage += " -liquidityprovider= " + strprintf(_("Provide liquidity to Obfuscation by infrequently mixing coins on a continual basis (0-100, default: %u, 1=very frequent, high fees, 100=very infrequent, low fees)"), 0) + "\n"; strUsage += HelpMessageOpt("-reindexzerocoin=", strprintf(_("Delete all zerocoin spends and mints that have been recorded to the blockchain database and reindex them (0-1, default: %u)"), 0)); strUsage += HelpMessageGroup(_("SwiftX options:")); strUsage += HelpMessageOpt("-enableswifttx=", strprintf(_("Enable SwiftX, show confirmations for locked transactions (bool, default: %s)"), "true")); @@ -656,12 +664,12 @@ void ThreadImport(std::vector vImportFiles) } // hardcoded $DATADIR/bootstrap.dat - filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; - if (filesystem::exists(pathBootstrap)) { + boost::filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; + if (boost::filesystem::exists(pathBootstrap)) { FILE* file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { CImportingNow imp; - filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; + boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); LoadExternalBlockFile(file); RenameOver(pathBootstrap, pathBootstrapOld); @@ -671,7 +679,7 @@ void ThreadImport(std::vector vImportFiles) } // -loadblock= - BOOST_FOREACH (boost::filesystem::path& path, vImportFiles) { + for (boost::filesystem::path& path : vImportFiles) { FILE* file = fopen(path.string().c_str(), "rb"); if (file) { CImportingNow imp; @@ -695,8 +703,7 @@ void ThreadImport(std::vector vImportFiles) bool InitSanityCheck(void) { if (!ECC_InitSanityCheck()) { - InitError("OpenSSL appears to lack support for elliptic curve cryptography. For more " - "information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries"); + InitError("Elliptic curve cryptography sanity check failure. Aborting."); return false; } if (!glibc_sanity_test() || !glibcxx_sanity_test()) @@ -705,7 +712,7 @@ bool InitSanityCheck(void) return true; } -bool AppInitServers(boost::thread_group& threadGroup) +bool AppInitServers() { RPCServer::OnStopped(&OnRPCStopped); RPCServer::OnPreCommand(&OnRPCPreCommand); @@ -725,7 +732,7 @@ bool AppInitServers(boost::thread_group& threadGroup) /** Initialize phore. * @pre Parameters should be parsed and config file should be read. */ -bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std::vector& words) +bool AppInit2(const std::vector& words) { // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -876,8 +883,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std fDebug = !mapMultiArgs["-debug"].empty(); // Special-case: if -debug=0/-nodebug is set, turn off debugging messages - const vector& categories = mapMultiArgs["-debug"]; - if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), string("0")) != categories.end()) + const std::vector& categories = mapMultiArgs["-debug"]; + if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), std::string("0")) != categories.end()) fDebug = false; // Check for -debugnet @@ -997,8 +1004,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices |= NODE_BLOOM; + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + // Initialize elliptic curve code + ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); + // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. Phore Core is shutting down.")); @@ -1061,7 +1074,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std */ if (fServer) { uiInterface.InitMessage.connect(SetRPCWarmupStatus); - if (!AppInitServers(threadGroup)) + if (!AppInitServers()) return InitError(_("Unable to start HTTP server. See debug log for details.")); } @@ -1070,15 +1083,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std // ********************************************************* Step 5: Backup wallet and verify wallet database integrity #ifdef ENABLE_WALLET if (!fDisableWallet) { - filesystem::path backupDir = GetDataDir() / "backups"; - if (!filesystem::exists(backupDir)) { + boost::filesystem::path backupDir = GetDataDir() / "backups"; + if (!boost::filesystem::exists(backupDir)) { // Always create backup folder to not confuse the operating system's file browser - filesystem::create_directories(backupDir); + boost::filesystem::create_directories(backupDir); } nWalletBackups = GetArg("-createwalletbackups", 10); nWalletBackups = std::max(0, std::min(10, nWalletBackups)); if (nWalletBackups > 0) { - if (filesystem::exists(backupDir)) { + if (boost::filesystem::exists(backupDir)) { // Create backup of the wallet std::string dateTimeStr = DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime()); std::string backupPathStr = backupDir.string(); @@ -1141,30 +1154,30 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std if (GetBoolArg("-resync", false)) { uiInterface.InitMessage(_("Preparing for resync...")); // Delete the local blockchain folders to force a resync from scratch to get a consitent blockchain-state - filesystem::path blocksDir = GetDataDir() / "blocks"; - filesystem::path chainstateDir = GetDataDir() / "chainstate"; - filesystem::path sporksDir = GetDataDir() / "sporks"; - filesystem::path zerocoinDir = GetDataDir() / "zerocoin"; + boost::filesystem::path blocksDir = GetDataDir() / "blocks"; + boost::filesystem::path chainstateDir = GetDataDir() / "chainstate"; + boost::filesystem::path sporksDir = GetDataDir() / "sporks"; + boost::filesystem::path zerocoinDir = GetDataDir() / "zerocoin"; LogPrintf("Deleting blockchain folders blocks, chainstate, sporks and zerocoin\n"); // We delete in 4 individual steps in case one of the folder is missing already try { - if (filesystem::exists(blocksDir)){ + if (boost::filesystem::exists(blocksDir)){ boost::filesystem::remove_all(blocksDir); LogPrintf("-resync: folder deleted: %s\n", blocksDir.string().c_str()); } - if (filesystem::exists(chainstateDir)){ + if (boost::filesystem::exists(chainstateDir)){ boost::filesystem::remove_all(chainstateDir); LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); } - if (filesystem::exists(sporksDir)){ + if (boost::filesystem::exists(sporksDir)){ boost::filesystem::remove_all(sporksDir); LogPrintf("-resync: folder deleted: %s\n", sporksDir.string().c_str()); } - if (filesystem::exists(zerocoinDir)){ + if (boost::filesystem::exists(zerocoinDir)){ boost::filesystem::remove_all(zerocoinDir); LogPrintf("-resync: folder deleted: %s\n", zerocoinDir.string().c_str()); } @@ -1190,7 +1203,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std // try again if (!bitdb.Open(GetDataDir())) { // if it still fails, it probably means we can't even create the database env - string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir); + std::string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir); return InitError(msg); } } @@ -1201,10 +1214,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std return false; } - if (filesystem::exists(GetDataDir() / strWalletFile)) { + if (boost::filesystem::exists(GetDataDir() / strWalletFile)) { CDBEnv::VerifyResult r = bitdb.Verify(strWalletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { - string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!" + std::string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!" " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if" " your balance or transactions are incorrect you should" " restore from a backup."), @@ -1218,7 +1231,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std // parse masternode.conf std::string strErr; if (!masternodeConfig.read(strErr)) { - string msg = strprintf("Error reading masternode configuration file: %s\n", strErr.c_str()); + std::string msg = strprintf("Error reading masternode configuration file: %s\n", strErr.c_str()); return InitError(msg); } } // (!fDisableWallet) @@ -1227,9 +1240,24 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std RegisterNodeSignals(GetNodeSignals()); + // sanitize comments per BIP-0014, format user agent and check total size + std::vector uacomments; + for (const std::string& cmt : mapMultiArgs["-uacomment"]) { + if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); + uacomments.push_back(cmt); + } + + // format user agent, check total size + strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); + if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { + return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), + strSubVersion.size(), MAX_SUBVERSION_LENGTH)); + } + if (mapArgs.count("-onlynet")) { std::set nets; - BOOST_FOREACH (std::string snet, mapMultiArgs["-onlynet"]) { + for (std::string snet : mapMultiArgs["-onlynet"]) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1243,7 +1271,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std } if (mapArgs.count("-whitelist")) { - BOOST_FOREACH (const std::string& net, mapMultiArgs["-whitelist"]) { + for (const std::string& net : mapMultiArgs["-whitelist"]) { CSubNet subnet(net); if (!subnet.IsValid()) return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); @@ -1303,13 +1331,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std bool fBound = false; if (fListen) { if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { - BOOST_FOREACH (std::string strBind, mapMultiArgs["-bind"]) { + for (std::string strBind : mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } - BOOST_FOREACH (std::string strBind, mapMultiArgs["-whitebind"]) { + for (std::string strBind : mapMultiArgs["-whitebind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); @@ -1320,7 +1348,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std } else { struct in_addr inaddr_any; inaddr_any.s_addr = INADDR_ANY; - fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE); + fBound |= Bind(CService((in6_addr)IN6ADDR_ANY_INIT, GetListenPort()), BF_NONE); fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE); } if (!fBound) @@ -1328,7 +1356,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std } if (mapArgs.count("-externalip")) { - BOOST_FOREACH (string strAddr, mapMultiArgs["-externalip"]) { + for (std::string strAddr : mapMultiArgs["-externalip"]) { CService addrLocal(strAddr, GetListenPort()); if (!addrLocal.IsValid()) return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); @@ -1336,7 +1364,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std } } - BOOST_FOREACH (string strDest, mapMultiArgs["-seednode"]) + for (std::string strDest : mapMultiArgs["-seednode"]) AddOneShot(strDest); #if ENABLE_ZMQ @@ -1353,30 +1381,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std fReindex = GetBoolArg("-reindex", false); - // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/ - filesystem::path blocksDir = GetDataDir() / "blocks"; - if (!filesystem::exists(blocksDir)) { - filesystem::create_directories(blocksDir); - bool linked = false; - for (unsigned int i = 1; i < 10000; i++) { - filesystem::path source = GetDataDir() / strprintf("blk%04u.dat", i); - if (!filesystem::exists(source)) break; - filesystem::path dest = blocksDir / strprintf("blk%05u.dat", i - 1); - try { - filesystem::create_hard_link(source, dest); - LogPrintf("Hardlinked %s -> %s\n", source.string(), dest.string()); - linked = true; - } catch (filesystem::filesystem_error& e) { - // Note: hardlink creation failing is not a disaster, it just means - // blocks will get re-downloaded from peers. - LogPrintf("Error hardlinking blk%04u.dat : %s\n", i, e.what()); - break; - } - } - if (linked) { - fReindex = true; - } - } + // Create blocks directory if it doesn't already exist + boost::filesystem::create_directories(GetDataDir() / "blocks"); // cache size calculations size_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20); @@ -1411,7 +1417,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std delete pSporkDB; //Phore specific: zerocoin and spork DB's - zerocoinDB = new CZerocoinDB(0, false, false); + zerocoinDB = new CZerocoinDB(0, false, fReindex); pSporkDB = new CSporkDB(0, false, false); pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); @@ -1427,7 +1433,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std LoadSporksFromDB(); uiInterface.InitMessage(_("Loading block index...")); - string strBlockIndexError = ""; + std::string strBlockIndexError = ""; if (!LoadBlockIndex(strBlockIndexError)) { strLoadError = _("Error loading block database"); strLoadError = strprintf("%s : %s", strLoadError, strBlockIndexError); @@ -1535,7 +1541,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std uiInterface.InitMessage(_("Calculating missing accumulators...")); LogPrintf("%s : finding missing checkpoints\n", __func__); - string strError; + std::string strError; if (!ReindexAccumulators(listAccCheckpointsNoDB, strError)) return InitError(strError); } @@ -1640,7 +1646,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std if (nLoadWalletRet == DB_CORRUPT) strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) { - string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" + std::string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" " or address book entries might be missing or incorrect.")); InitWarning(msg); } else if (nLoadWalletRet == DB_TOO_NEW) @@ -1731,7 +1737,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std // Restore wallet transaction metadata after -zapwallettxes=1 if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") { - BOOST_FOREACH (const CWalletTx& wtxOld, vWtx) { + for (const CWalletTx& wtxOld : vWtx) { uint256 hash = wtxOld.GetHash(); std::map::iterator mi = pwalletMain->mapWallet.find(hash); if (mi != pwalletMain->mapWallet.end()) { @@ -1802,7 +1808,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std std::vector vImportFiles; if (mapArgs.count("-loadblock")) { - BOOST_FOREACH (string strFile, mapMultiArgs["-loadblock"]) + for (std::string strFile : mapMultiArgs["-loadblock"]) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); @@ -1908,10 +1914,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std LOCK(pwalletMain->cs_wallet); LogPrintf("Locking Masternodes:\n"); uint256 mnTxHash; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { LogPrintf(" %s %s\n", mne.getTxHash(), mne.getOutputIndex()); mnTxHash.SetHex(mne.getTxHash()); - COutPoint outpoint = COutPoint(mnTxHash, boost::lexical_cast(mne.getOutputIndex())); + COutPoint outpoint = COutPoint(mnTxHash, (unsigned int) std::stoul(mne.getOutputIndex().c_str())); pwalletMain->LockCoin(outpoint); } } @@ -1929,20 +1935,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std nPreferredDenom = 0; } -// XX42 Remove/refactor code below. Until then provide safe defaults - nAnonymizePhoreAmount = 2; - -// nLiquidityProvider = GetArg("-liquidityprovider", 0); //0-100 -// if (nLiquidityProvider != 0) { -// obfuScationPool.SetMinBlockSpacing(std::min(nLiquidityProvider, 100) * 15); -// fEnableZeromint = true; -// nZeromintPercentage = 99999; -// } -// -// nAnonymizePhoreAmount = GetArg("-anonymizephoreamount", 0); -// if (nAnonymizePhoreAmount > 999999) nAnonymizePhoreAmount = 999999; -// if (nAnonymizePhoreAmount < 2) nAnonymizePhoreAmount = 2; - fEnableSwiftTX = GetBoolArg("-enableswifttx", fEnableSwiftTX); nSwiftTXDepth = GetArg("-swifttxdepth", nSwiftTXDepth); nSwiftTXDepth = std::min(std::max(nSwiftTXDepth, 0), 60); @@ -1955,7 +1947,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std LogPrintf("fLiteMode %d\n", fLiteMode); LogPrintf("nSwiftTXDepth %d\n", nSwiftTXDepth); - LogPrintf("Anonymize Phore Amount %d\n", nAnonymizePhoreAmount); LogPrintf("Budget Mode %s\n", strBudgetMode.c_str()); /* Denominations @@ -1973,10 +1964,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std obfuScationDenominations.push_back((10 * COIN) + 10000); obfuScationDenominations.push_back((1 * COIN) + 1000); obfuScationDenominations.push_back((.1 * COIN) + 100); - /* Disabled till we need them - obfuScationDenominations.push_back( (.01 * COIN)+10 ); - obfuScationDenominations.push_back( (.001 * COIN)+1 ); - */ obfuScationPool.InitCollateralAddress(); diff --git a/src/init.h b/src/init.h index eb39d1ae44d0..671b4810d4fb 100644 --- a/src/init.h +++ b/src/init.h @@ -24,10 +24,10 @@ extern CzPHRWallet* zwalletMain; void StartShutdown(); bool ShutdownRequested(); /** Interrupt threads */ -void Interrupt(boost::thread_group& threadGroup); +void Interrupt(); void Shutdown(); void PrepareShutdown(); -bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler, const std::vector& words); +bool AppInit2(const std::vector& words); /** The help message mode determines what help message to show */ enum HelpMessageMode { diff --git a/src/kernel.cpp b/src/kernel.cpp index 276eaa51fa8a..b8e894ae3668 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -13,7 +13,6 @@ #include "timedata.h" #include "util.h" -using namespace std; bool fTestNet = false; //Params().NetworkID() == CBaseChainParams::TESTNET; @@ -75,8 +74,8 @@ static int64_t GetStakeModifierSelectionInterval() // already selected blocks in vSelectedBlocks, and with timestamp up to // nSelectionIntervalStop. static bool SelectBlockFromCandidates( - vector >& vSortedByTimestamp, - map& mapSelectedBlocks, + std::vector >& vSortedByTimestamp, + std::map& mapSelectedBlocks, int64_t nSelectionIntervalStop, uint64_t nStakeModifierPrev, const CBlockIndex** pindexSelected) @@ -86,7 +85,7 @@ static bool SelectBlockFromCandidates( bool fSelected = false; uint256 hashBest = 0; *pindexSelected = (const CBlockIndex*)0; - BOOST_FOREACH (const PAIRTYPE(int64_t, uint256) & item, vSortedByTimestamp) { + for (const PAIRTYPE(int64_t, uint256) & item : vSortedByTimestamp) { if (!mapBlockIndex.count(item.second)) return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString().c_str()); @@ -175,26 +174,26 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod return true; // Sort candidate blocks by timestamp - vector > vSortedByTimestamp; + std::vector > vSortedByTimestamp; vSortedByTimestamp.reserve(64 * getIntervalVersion(fTestNet) / nStakeTargetSpacing); int64_t nSelectionInterval = GetStakeModifierSelectionInterval(); int64_t nSelectionIntervalStart = (pindexPrev->GetBlockTime() / getIntervalVersion(fTestNet)) * getIntervalVersion(fTestNet) - nSelectionInterval; const CBlockIndex* pindex = pindexPrev; while (pindex && pindex->GetBlockTime() >= nSelectionIntervalStart) { - vSortedByTimestamp.push_back(make_pair(pindex->GetBlockTime(), pindex->GetBlockHash())); + vSortedByTimestamp.push_back(std::make_pair(pindex->GetBlockTime(), pindex->GetBlockHash())); pindex = pindex->pprev; } int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0; - reverse(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); + std::reverse(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); // Select 64 blocks from candidate blocks to generate stake modifier uint64_t nStakeModifierNew = 0; int64_t nSelectionIntervalStop = nSelectionIntervalStart; - map mapSelectedBlocks; - for (int nRound = 0; nRound < min(64, (int)vSortedByTimestamp.size()); nRound++) { + std::map mapSelectedBlocks; + for (int nRound = 0; nRound < std::min(64, (int)vSortedByTimestamp.size()); nRound++) { // add an interval section to the current selection round nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound); @@ -206,7 +205,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod nStakeModifierNew |= (((uint64_t)pindex->GetStakeEntropyBit()) << nRound); // add the selected block from candidates to selected list - mapSelectedBlocks.insert(make_pair(pindex->GetBlockHash(), pindex)); + mapSelectedBlocks.insert(std::make_pair(pindex->GetBlockHash(), pindex)); if (fDebug || GetBoolArg("-printstakemodifier", false)) LogPrintf("ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n", nRound, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nSelectionIntervalStop).c_str(), pindex->nHeight, pindex->GetStakeEntropyBit()); @@ -214,7 +213,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod // Print selection map for visualization of the selected blocks if (fDebug || GetBoolArg("-printstakemodifier", false)) { - string strSelectionMap = ""; + std::string strSelectionMap = ""; // '-' indicates proof-of-work blocks not selected strSelectionMap.insert(0, pindexPrev->nHeight - nHeightFirstCandidate + 1, '-'); pindex = pindexPrev; @@ -224,14 +223,14 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "="); pindex = pindex->pprev; } - BOOST_FOREACH (const PAIRTYPE(uint256, const CBlockIndex*) & item, mapSelectedBlocks) { + for (const PAIRTYPE(uint256, const CBlockIndex*) & item : mapSelectedBlocks) { // 'S' indicates selected proof-of-stake blocks // 'W' indicates selected proof-of-work blocks strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake() ? "S" : "W"); } LogPrintf("ComputeNextStakeModifier: selection height [%d, %d] map %s\n", nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap.c_str()); } - if (fDebug || GetBoolArg("-printstakemodifier", false)) { + if (GetBoolArg("-printstakemodifier", false)) { LogPrintf("ComputeNextStakeModifier: new modifier=%s time=%s\n", std::to_string(nStakeModifierNew).c_str(), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexPrev->GetBlockTime()).c_str()); } diff --git a/src/key.cpp b/src/key.cpp index f0856977caa1..6aefada0c18f 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,54 +1,172 @@ -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" +#include "uint256.h" +#include "crypto/common.h" #include "crypto/hmac_sha512.h" -#include "crypto/rfc6979_hmac_sha256.h" -#include "eccryptoverify.h" -#include "pubkey.h" #include "random.h" -#include "ecwrapper.h" #include +#include -//! anonymous namespace -namespace -{ - class CSecp256k1Init - { - public: - CSecp256k1Init() - { - secp256k1_start(SECP256K1_START_SIGN); - } - ~CSecp256k1Init() - { - secp256k1_stop(); - } - }; - static CSecp256k1Init instance_of_csecp256k1; - -} // anon namespace +static secp256k1_context* secp256k1_context_sign = nullptr; + +/** These functions are taken from the libsecp256k1 distribution and are very ugly. */ + +/** + * This parses a format loosely based on a DER encoding of the ECPrivateKey type from + * section C.4 of SEC 1 , with the following caveats: + * + * * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not + * required to be encoded as one octet if it is less than 256, as DER would require. + * * The octet-length of the SEQUENCE must not be greater than the remaining + * length of the key encoding, but need not match it (i.e. the encoding may contain + * junk after the encoded SEQUENCE). + * * The privateKey OCTET STRING is zero-filled on the left to 32 octets. + * * Anything after the encoding of the privateKey OCTET STRING is ignored, whether + * or not it is validly encoded DER. + * + * out32 must point to an output buffer of length at least 32 bytes. + */ +static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + memset(out32, 0, 32); + /* sequence header */ + if (end - privkey < 1 || *privkey != 0x30u) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end - privkey < 1 || !(*privkey & 0x80u)) { + return 0; + } + ptrdiff_t lenb = *privkey & ~0x80u; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end - privkey < lenb) { + return 0; + } + /* sequence length */ + ptrdiff_t len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0u); + privkey += lenb; + if (end - privkey < len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || privkey[2] != 0x01u) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end - privkey < 2 || privkey[0] != 0x04u) { + return 0; + } + ptrdiff_t oslen = privkey[1]; + privkey += 2; + if (oslen > 32 || end - privkey < oslen) { + return 0; + } + memcpy(out32 + (32 - oslen), privkey, oslen); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +/** + * This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1 + * . The optional parameters and publicKey fields are + * included. + * + * privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes. + * privkeylen must initially be set to the size of the privkey buffer. Upon return it + * will be set to the number of bytes used in the buffer. + * key32 must point to a 32-byte raw private key. + */ +static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE); + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE); + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = CPubKey::PUBLIC_KEY_SIZE; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + assert(*privkeylen == CKey::PRIVATE_KEY_SIZE); + } + return 1; +} bool CKey::Check(const unsigned char* vch) { - return eccrypto::Check(vch); + return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); } void CKey::MakeNewKey(bool fCompressedIn) { do { - GetStrongRandBytes(vch, sizeof(vch)); - } while (!Check(vch)); + GetRandBytes(keydata.data(), keydata.size()); + } while (!Check(keydata.data())); fValid = true; fCompressed = fCompressedIn; } bool CKey::SetPrivKey(const CPrivKey& privkey, bool fCompressedIn) { - if (!secp256k1_ec_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size())) + if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size())) return false; fCompressed = fCompressedIn; fValid = true; @@ -57,7 +175,7 @@ bool CKey::SetPrivKey(const CPrivKey& privkey, bool fCompressedIn) uint256 CKey::GetPrivKey_256() { - void* key = &vch; + void* key = keydata.data(); uint256* key_256 = (uint256*)key; return *key_256; @@ -67,10 +185,10 @@ CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; - int privkeylen, ret; - privkey.resize(279); - privkeylen = 279; - ret = secp256k1_ec_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); + size_t privkeylen; + privkey.resize(PRIVATE_KEY_SIZE); + privkeylen = PRIVATE_KEY_SIZE; + int ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); assert(ret); privkey.resize(privkeylen); return privkey; @@ -79,11 +197,13 @@ CPrivKey CKey::GetPrivKey() const CPubKey CKey::GetPubKey() const { assert(fValid); + secp256k1_pubkey pubkey; CPubKey result; - int clen = 65; - int ret = secp256k1_ec_pubkey_create((unsigned char*)result.begin(), &clen, begin(), fCompressed); - assert((int)result.size() == clen); + size_t clen = 65; + int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); assert(ret); + secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + assert(result.size() == clen); assert(result.IsValid()); return result; } @@ -92,20 +212,16 @@ bool CKey::Sign(const uint256& hash, std::vector& vchSig, uint32_ { if (!fValid) return false; - vchSig.resize(72); - RFC6979_HMAC_SHA256 prng(begin(), 32, (unsigned char*)&hash, 32); - do { - uint256 nonce; - prng.Generate((unsigned char*)&nonce, 32); - nonce += test_case; - int nSigLen = 72; - int ret = secp256k1_ecdsa_sign((const unsigned char*)&hash, 32, (unsigned char*)&vchSig[0], &nSigLen, begin(), (unsigned char*)&nonce); - nonce = 0; - if (ret) { - vchSig.resize(nSigLen); - return true; - } - } while (true); + vchSig.resize(CPubKey::SIGNATURE_SIZE); + size_t nSigLen = CPubKey::SIGNATURE_SIZE; + unsigned char extra_entropy[32] = {0}; + WriteLE32(extra_entropy, test_case); + secp256k1_ecdsa_signature sig; + int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr); + assert(ret); + secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)vchSig.data(), &nSigLen, &sig); + vchSig.resize(nSigLen); + return true; } bool CKey::VerifyPubKey(const CPubKey& pubkey) const @@ -117,7 +233,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const std::string str = "Bitcoin key verification\n"; GetRandBytes(rnd, sizeof(rnd)); uint256 hash; - CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize((unsigned char*)&hash); + CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin()); std::vector vchSig; Sign(hash, vchSig); return pubkey.Verify(hash, vchSig); @@ -127,25 +243,21 @@ bool CKey::SignCompact(const uint256& hash, std::vector& vchSig) { if (!fValid) return false; - vchSig.resize(65); + vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE); int rec = -1; - RFC6979_HMAC_SHA256 prng(begin(), 32, (unsigned char*)&hash, 32); - do { - uint256 nonce; - prng.Generate((unsigned char*)&nonce, 32); - int ret = secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, 32, &vchSig[1], begin(), (unsigned char*)&nonce, &rec); - nonce = 0; - if (ret) - break; - } while (true); + secp256k1_ecdsa_recoverable_signature sig; + int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr); + assert(ret); + secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig); + assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); return true; } -bool CKey::Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck = false) +bool CKey::Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck = false) { - if (!secp256k1_ec_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size())) + if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), privkey.data(), privkey.size())) return false; fCompressed = vchPubKey.IsCompressed(); fValid = true; @@ -156,24 +268,22 @@ bool CKey::Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck = false) return VerifyPubKey(vchPubKey); } -bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const +bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const { assert(IsValid()); assert(IsCompressed()); - unsigned char out[64]; - LockObject(out); + std::vector> vout(64); if ((nChild >> 31) == 0) { CPubKey pubkey = GetPubKey(); - assert(pubkey.begin() + 33 == pubkey.end()); - BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin() + 1, out); + assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); + BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data()); } else { - assert(begin() + 32 == end()); - BIP32Hash(cc, nChild, 0, begin(), out); + assert(size() == 32); + BIP32Hash(cc, nChild, 0, begin(), vout.data()); } - memcpy(ccChild, out + 32, 32); + memcpy(ccChild.begin(), vout.data()+32, 32); memcpy((unsigned char*)keyChild.begin(), begin(), 32); - bool ret = secp256k1_ec_privkey_tweak_add((unsigned char*)keyChild.begin(), out); - UnlockObject(out); + bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data()); keyChild.fCompressed = true; keyChild.fValid = ret; return ret; @@ -185,18 +295,17 @@ bool CExtKey::Derive(CExtKey& out, unsigned int nChild) const CKeyID id = key.GetPubKey().GetID(); memcpy(&out.vchFingerprint[0], &id, 4); out.nChild = nChild; - return key.Derive(out.key, out.vchChainCode, nChild, vchChainCode); + return key.Derive(out.key, out.chaincode, nChild, chaincode); } void CExtKey::SetMaster(const unsigned char* seed, unsigned int nSeedLen) { static const unsigned char hashkey[] = {'B', 'i', 't', 'c', 'o', 'i', 'n', ' ', 's', 'e', 'e', 'd'}; - unsigned char out[64]; - LockObject(out); - CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out); - key.Set(&out[0], &out[32], true); - memcpy(vchChainCode, &out[32], 32); - UnlockObject(out); + std::vector> vout(64); + CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(vout.data()); + key.Set(vout.data(), vout.data() + 32, true); + memcpy(chaincode.begin(), vout.data() + 32, 32); + nDepth = 0; nChild = 0; memset(vchFingerprint, 0, sizeof(vchFingerprint)); @@ -209,7 +318,7 @@ CExtPubKey CExtKey::Neuter() const memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4); ret.nChild = nChild; ret.pubkey = key.GetPubKey(); - memcpy(&ret.vchChainCode[0], &vchChainCode[0], 32); + ret.chaincode = chaincode; return ret; } @@ -221,7 +330,7 @@ void CExtKey::Encode(unsigned char code[74]) const code[6] = (nChild >> 16) & 0xFF; code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; - memcpy(code + 9, vchChainCode, 32); + memcpy(code + 9, chaincode.begin(), 32); code[41] = 0; assert(key.size() == 32); memcpy(code + 42, key.begin(), 32); @@ -232,19 +341,40 @@ void CExtKey::Decode(const unsigned char code[74]) nDepth = code[0]; memcpy(vchFingerprint, code + 1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; - memcpy(vchChainCode, code + 9, 32); + memcpy(chaincode.begin(), code + 9, 32); key.Set(code + 42, code + 74, true); } bool ECC_InitSanityCheck() { -#if !defined(USE_SECP256K1) - if (!CECKey::SanityCheck()) { - return false; - } -#endif CKey key; key.MakeNewKey(true); CPubKey pubkey = key.GetPubKey(); return key.VerifyPubKey(pubkey); +} + +void ECC_Start() { + assert(secp256k1_context_sign == nullptr); + + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + assert(ctx != nullptr); + + { + // Pass in a random blinding seed to the secp256k1 context. + std::vector> vseed(32); + GetRandBytes(vseed.data(), 32); + bool ret = secp256k1_context_randomize(ctx, vseed.data()); + assert(ret); + } + + secp256k1_context_sign = ctx; +} + +void ECC_Stop() { + secp256k1_context *ctx = secp256k1_context_sign; + secp256k1_context_sign = nullptr; + + if (ctx) { + secp256k1_context_destroy(ctx); + } } \ No newline at end of file diff --git a/src/key.h b/src/key.h index 6f6c0ab8d517..057fdfab595c 100644 --- a/src/key.h +++ b/src/key.h @@ -1,16 +1,17 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Copyright (c) 2015-2017 The PIVX developers +// Copyright (c) 2015-2018 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_KEY_H -#define BITCOIN_KEY_H +#ifndef PHORE_KEY_H +#define PHORE_KEY_H #include "pubkey.h" #include "allocators.h" #include "serialize.h" #include "uint256.h" +#include "pubkey.h" #include #include @@ -19,25 +20,30 @@ class CPubKey; struct CExtPubKey; -/** - * secp256k1: - * const unsigned int PRIVATE_KEY_SIZE = 279; - * const unsigned int PUBLIC_KEY_SIZE = 65; - * const unsigned int SIGNATURE_SIZE = 72; - * - * see www.keylength.com - * script supports up to 75 for single byte push - */ - /** * secure_allocator is defined in allocators.h - * CPrivKey is a serialized private key, with all parameters included (279 bytes) + * CPrivKey is a serialized private key, with all parameters included + * (PRIVATE_KEY_SIZE bytes) */ typedef std::vector > CPrivKey; /** An encapsulated private key. */ class CKey { +public: + /** + * secp256k1: + */ + static const unsigned int PRIVATE_KEY_SIZE = 279; + static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, + "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); + private: //! Whether this private key is valid. We check for correctness when modifying the key //! data, so fValid should always correspond to the actual state. @@ -47,7 +53,7 @@ class CKey bool fCompressed; //! The actual byte data - unsigned char vch[32]; + std::vector > keydata; //! Check whether the 32-byte array pointed to be vch is valid keydata. bool static Check(const unsigned char* vch); @@ -56,49 +62,36 @@ class CKey //! Construct an invalid private key. CKey() : fValid(false), fCompressed(false) { - LockObject(vch); - } - - //! Copy constructor. This is necessary because of memlocking. - CKey(const CKey& secret) : fValid(secret.fValid), fCompressed(secret.fCompressed) - { - LockObject(vch); - memcpy(vch, secret.vch, sizeof(vch)); - } - - //! Destructor (again necessary because of memlocking). - ~CKey() - { - UnlockObject(vch); + // Important: vch must be 32 bytes in length to not break serialization + keydata.resize(32); } friend bool operator==(const CKey& a, const CKey& b) { - return a.fCompressed == b.fCompressed && a.size() == b.size() && - memcmp(&a.vch[0], &b.vch[0], a.size()) == 0; + return a.fCompressed == b.fCompressed && + a.size() == b.size() && + memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0; } //! Initialize using begin and end iterators to byte data. template void Set(const T pbegin, const T pend, bool fCompressedIn) { - if (pend - pbegin != 32) { + if (size_t(pend - pbegin) != keydata.size()) { fValid = false; - return; - } - if (Check(&pbegin[0])) { - memcpy(vch, (unsigned char*)&pbegin[0], 32); + } else if (Check(&pbegin[0])) { + memcpy(keydata.data(), (unsigned char*)&pbegin[0], keydata.size()); fValid = true; fCompressed = fCompressedIn; } else { fValid = false; } - } +} //! Simple read-only vector-like interface. - unsigned int size() const { return (fValid ? 32 : 0); } - const unsigned char* begin() const { return vch; } - const unsigned char* end() const { return vch + size(); } + unsigned int size() const { return (fValid ? keydata.size() : 0); } + const unsigned char* begin() const { return keydata.data(); } + const unsigned char* end() const { return keydata.data() + size(); } //! Check whether this private key is valid. bool IsValid() const { return fValid; } @@ -128,8 +121,7 @@ class CKey /** * Create a DER-serialized signature. - * The test_case parameter tweaks the deterministic nonce, and is only for - * testing. It should be zero for normal use. + * The test_case parameter tweaks the deterministic nonce. */ bool Sign(const uint256& hash, std::vector& vchSig, uint32_t test_case = 0) const; @@ -143,7 +135,7 @@ class CKey bool SignCompact(const uint256& hash, std::vector& vchSig) const; //! Derive BIP32 child key. - bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const; + bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; /** * Verify thoroughly whether a private key and a public key match. @@ -152,7 +144,7 @@ class CKey bool VerifyPubKey(const CPubKey& vchPubKey) const; //! Load private key and check that public key matches. - bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck); + bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck); //! Check whether an element of a signature (r or s) is valid. static bool CheckSignatureElement(const unsigned char* vch, int len, bool half); @@ -162,17 +154,20 @@ struct CExtKey { unsigned char nDepth; unsigned char vchFingerprint[4]; unsigned int nChild; - unsigned char vchChainCode[32]; + ChainCode chaincode; CKey key; friend bool operator==(const CExtKey& a, const CExtKey& b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - memcmp(&a.vchChainCode[0], &b.vchChainCode[0], 32) == 0 && a.key == b.key; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.key == b.key; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetMaster(const unsigned char* seed, unsigned int nSeedLen); @@ -195,7 +190,13 @@ struct CExtKey { } }; -/** Check that required EC support is available at runtime */ +/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ +void ECC_Start(void); + +/** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called first. */ +void ECC_Stop(void); + +/** Check that required EC support is available at runtime. */ bool ECC_InitSanityCheck(void); -#endif // BITCOIN_KEY_H \ No newline at end of file +#endif // PHORE_KEY_H \ No newline at end of file diff --git a/src/keystore.cpp b/src/keystore.cpp index 7f54e6c4f0ae..1a317eb7cf94 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -11,7 +11,7 @@ #include "script/standard.h" #include "util.h" -#include + static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut) { @@ -200,3 +200,39 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest) } return CKeyID(); } + +bool CBasicKeyStore::HaveKey(const CKeyID& address) const +{ + bool result; + { + LOCK(cs_KeyStore); + result = (mapKeys.count(address) > 0); + } + return result; +} + +void CBasicKeyStore::GetKeys(std::set& setAddress) const +{ + setAddress.clear(); + { + LOCK(cs_KeyStore); + KeyMap::const_iterator mi = mapKeys.begin(); + while (mi != mapKeys.end()) { + setAddress.insert((*mi).first); + mi++; + } + } +} + +bool CBasicKeyStore::GetKey(const CKeyID& address, CKey& keyOut) const +{ + { + LOCK(cs_KeyStore); + KeyMap::const_iterator mi = mapKeys.find(address); + if (mi != mapKeys.end()) { + keyOut = mi->second; + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/keystore.h b/src/keystore.h index cdfe760a77fe..8175178da488 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -14,7 +14,6 @@ #include "script/standard.h" #include -#include class CScript; class CScriptID; @@ -78,39 +77,10 @@ class CBasicKeyStore : public CKeyStore public: bool AddKeyPubKey(const CKey& key, const CPubKey& pubkey) override; bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override; - bool HaveKey(const CKeyID& address) const override - { - bool result; - { - LOCK(cs_KeyStore); - result = (mapKeys.count(address) > 0); - } - return result; - } - void GetKeys(std::set& setAddress) const override - { - setAddress.clear(); - { - LOCK(cs_KeyStore); - KeyMap::const_iterator mi = mapKeys.begin(); - while (mi != mapKeys.end()) { - setAddress.insert((*mi).first); - mi++; - } - } - } - bool GetKey(const CKeyID& address, CKey& keyOut) const override - { - { - LOCK(cs_KeyStore); - KeyMap::const_iterator mi = mapKeys.find(address); - if (mi != mapKeys.end()) { - keyOut = mi->second; - return true; - } - } - return false; - } + bool HaveKey(const CKeyID& address) const override; + void GetKeys(std::set& setAddress) const override; + bool GetKey(const CKeyID& address, CKey& keyOut) const override; + virtual bool AddCScript(const CScript& redeemScript) override; virtual bool HaveCScript(const CScriptID& hash) const override; virtual bool GetCScript(const CScriptID& hash, CScript& redeemScriptOut) const override; diff --git a/src/leveldb/.gitignore b/src/leveldb/.gitignore new file mode 100644 index 000000000000..71d87a4eeb60 --- /dev/null +++ b/src/leveldb/.gitignore @@ -0,0 +1,13 @@ +build_config.mk +*.a +*.o +*.dylib* +*.so +*.so.* +*_test +db_bench +leveldbutil +Release +Debug +Benchmark +vs2010.* diff --git a/src/leveldb/.travis.yml b/src/leveldb/.travis.yml new file mode 100644 index 000000000000..f5bd74c45412 --- /dev/null +++ b/src/leveldb/.travis.yml @@ -0,0 +1,13 @@ +language: cpp +compiler: +- clang +- gcc +os: +- linux +- osx +sudo: false +before_install: +- echo $LANG +- echo $LC_ALL +script: +- make -j 4 check diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile index 2bd2cadcddeb..f7cc7d736c4f 100644 --- a/src/leveldb/Makefile +++ b/src/leveldb/Makefile @@ -20,208 +20,405 @@ $(shell CC="$(CC)" CXX="$(CXX)" TARGET_OS="$(TARGET_OS)" \ # this file is generated by the previous line to set build flags and sources include build_config.mk +TESTS = \ + db/autocompact_test \ + db/c_test \ + db/corruption_test \ + db/db_test \ + db/dbformat_test \ + db/fault_injection_test \ + db/filename_test \ + db/log_test \ + db/recovery_test \ + db/skiplist_test \ + db/version_edit_test \ + db/version_set_test \ + db/write_batch_test \ + helpers/memenv/memenv_test \ + issues/issue178_test \ + issues/issue200_test \ + table/filter_block_test \ + table/table_test \ + util/arena_test \ + util/bloom_test \ + util/cache_test \ + util/coding_test \ + util/crc32c_test \ + util/env_posix_test \ + util/env_test \ + util/hash_test + +UTILS = \ + db/db_bench \ + db/leveldbutil + +# Put the object files in a subdirectory, but the application at the top of the object dir. +PROGNAMES := $(notdir $(TESTS) $(UTILS)) + +# On Linux may need libkyotocabinet-dev for dependency. +BENCHMARKS = \ + doc/bench/db_bench_sqlite3 \ + doc/bench/db_bench_tree_db + CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) LDFLAGS += $(PLATFORM_LDFLAGS) LIBS += $(PLATFORM_LIBS) -LIBOBJECTS = $(SOURCES:.cc=.o) -MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o) - -TESTUTIL = ./util/testutil.o -TESTHARNESS = ./util/testharness.o $(TESTUTIL) +SIMULATOR_OUTDIR=out-ios-x86 +DEVICE_OUTDIR=out-ios-arm -# Note: iOS should probably be using libtool, not ar. ifeq ($(PLATFORM), IOS) +# Note: iOS should probably be using libtool, not ar. AR=xcrun ar +SIMULATORSDK=$(shell xcrun -sdk iphonesimulator --show-sdk-path) +DEVICESDK=$(shell xcrun -sdk iphoneos --show-sdk-path) +DEVICE_CFLAGS = -isysroot "$(DEVICESDK)" -arch armv6 -arch armv7 -arch armv7s -arch arm64 +SIMULATOR_CFLAGS = -isysroot "$(SIMULATORSDK)" -arch i686 -arch x86_64 +STATIC_OUTDIR=out-ios-universal +else +STATIC_OUTDIR=out-static +SHARED_OUTDIR=out-shared +STATIC_PROGRAMS := $(addprefix $(STATIC_OUTDIR)/, $(PROGNAMES)) +SHARED_PROGRAMS := $(addprefix $(SHARED_OUTDIR)/, db_bench) endif -TESTS = \ - arena_test \ - autocompact_test \ - bloom_test \ - c_test \ - cache_test \ - coding_test \ - corruption_test \ - crc32c_test \ - db_test \ - dbformat_test \ - env_test \ - filename_test \ - filter_block_test \ - hash_test \ - issue178_test \ - issue200_test \ - log_test \ - memenv_test \ - skiplist_test \ - table_test \ - version_edit_test \ - version_set_test \ - write_batch_test - -PROGRAMS = db_bench leveldbutil $(TESTS) -BENCHMARKS = db_bench_sqlite3 db_bench_tree_db - -LIBRARY = libleveldb.a -MEMENVLIBRARY = libmemenv.a +STATIC_LIBOBJECTS := $(addprefix $(STATIC_OUTDIR)/, $(SOURCES:.cc=.o)) +STATIC_MEMENVOBJECTS := $(addprefix $(STATIC_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +DEVICE_LIBOBJECTS := $(addprefix $(DEVICE_OUTDIR)/, $(SOURCES:.cc=.o)) +DEVICE_MEMENVOBJECTS := $(addprefix $(DEVICE_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +SIMULATOR_LIBOBJECTS := $(addprefix $(SIMULATOR_OUTDIR)/, $(SOURCES:.cc=.o)) +SIMULATOR_MEMENVOBJECTS := $(addprefix $(SIMULATOR_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +SHARED_LIBOBJECTS := $(addprefix $(SHARED_OUTDIR)/, $(SOURCES:.cc=.o)) +SHARED_MEMENVOBJECTS := $(addprefix $(SHARED_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +TESTUTIL := $(STATIC_OUTDIR)/util/testutil.o +TESTHARNESS := $(STATIC_OUTDIR)/util/testharness.o $(TESTUTIL) + +STATIC_TESTOBJS := $(addprefix $(STATIC_OUTDIR)/, $(addsuffix .o, $(TESTS))) +STATIC_UTILOBJS := $(addprefix $(STATIC_OUTDIR)/, $(addsuffix .o, $(UTILS))) +STATIC_ALLOBJS := $(STATIC_LIBOBJECTS) $(STATIC_MEMENVOBJECTS) $(STATIC_TESTOBJS) $(STATIC_UTILOBJS) $(TESTHARNESS) +DEVICE_ALLOBJS := $(DEVICE_LIBOBJECTS) $(DEVICE_MEMENVOBJECTS) +SIMULATOR_ALLOBJS := $(SIMULATOR_LIBOBJECTS) $(SIMULATOR_MEMENVOBJECTS) default: all # Should we build shared libraries? ifneq ($(PLATFORM_SHARED_EXT),) +# Many leveldb test apps use non-exported API's. Only build a subset for testing. +SHARED_ALLOBJS := $(SHARED_LIBOBJECTS) $(SHARED_MEMENVOBJECTS) $(TESTHARNESS) + ifneq ($(PLATFORM_SHARED_VERSIONED),true) -SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) -SHARED2 = $(SHARED1) -SHARED3 = $(SHARED1) -SHARED = $(SHARED1) +SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT) +SHARED_LIB2 = $(SHARED_LIB1) +SHARED_LIB3 = $(SHARED_LIB1) +SHARED_LIBS = $(SHARED_LIB1) +SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a else # Update db.h if you change these. -SHARED_MAJOR = 1 -SHARED_MINOR = 18 -SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) -SHARED2 = $(SHARED1).$(SHARED_MAJOR) -SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) -SHARED = $(SHARED1) $(SHARED2) $(SHARED3) -$(SHARED1): $(SHARED3) - ln -fs $(SHARED3) $(SHARED1) -$(SHARED2): $(SHARED3) - ln -fs $(SHARED3) $(SHARED2) +SHARED_VERSION_MAJOR = 1 +SHARED_VERSION_MINOR = 20 +SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT) +SHARED_LIB2 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR) +SHARED_LIB3 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR).$(SHARED_VERSION_MINOR) +SHARED_LIBS = $(SHARED_OUTDIR)/$(SHARED_LIB1) $(SHARED_OUTDIR)/$(SHARED_LIB2) $(SHARED_OUTDIR)/$(SHARED_LIB3) +$(SHARED_OUTDIR)/$(SHARED_LIB1): $(SHARED_OUTDIR)/$(SHARED_LIB3) + ln -fs $(SHARED_LIB3) $(SHARED_OUTDIR)/$(SHARED_LIB1) +$(SHARED_OUTDIR)/$(SHARED_LIB2): $(SHARED_OUTDIR)/$(SHARED_LIB3) + ln -fs $(SHARED_LIB3) $(SHARED_OUTDIR)/$(SHARED_LIB2) +SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a endif -$(SHARED3): - $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) $(LIBS) +$(SHARED_OUTDIR)/$(SHARED_LIB3): $(SHARED_LIBOBJECTS) + $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED_LIB2) $(SHARED_LIBOBJECTS) -o $(SHARED_OUTDIR)/$(SHARED_LIB3) $(LIBS) endif # PLATFORM_SHARED_EXT -all: $(SHARED) $(LIBRARY) +all: $(SHARED_LIBS) $(SHARED_PROGRAMS) $(STATIC_OUTDIR)/libleveldb.a $(STATIC_OUTDIR)/libmemenv.a $(STATIC_PROGRAMS) -check: all $(PROGRAMS) $(TESTS) - for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done +check: $(STATIC_PROGRAMS) + for t in $(notdir $(TESTS)); do echo "***** Running $$t"; $(STATIC_OUTDIR)/$$t || exit 1; done clean: - -rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) */*.o */*/*.o ios-x86/*/*.o ios-arm/*/*.o build_config.mk - -rm -rf ios-x86/* ios-arm/* + -rm -rf out-static out-shared out-ios-x86 out-ios-arm out-ios-universal + -rm -f build_config.mk + -rm -rf ios-x86 ios-arm -$(LIBRARY): $(LIBOBJECTS) - rm -f $@ - $(AR) -rs $@ $(LIBOBJECTS) +$(STATIC_OUTDIR): + mkdir $@ -db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) +$(STATIC_OUTDIR)/db: | $(STATIC_OUTDIR) + mkdir $@ -db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS) +$(STATIC_OUTDIR)/helpers/memenv: | $(STATIC_OUTDIR) + mkdir -p $@ -db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS) +$(STATIC_OUTDIR)/port: | $(STATIC_OUTDIR) + mkdir $@ -leveldbutil: db/leveldb_main.o $(LIBOBJECTS) - $(CXX) $(LDFLAGS) db/leveldb_main.o $(LIBOBJECTS) -o $@ $(LIBS) +$(STATIC_OUTDIR)/table: | $(STATIC_OUTDIR) + mkdir $@ -arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(STATIC_OUTDIR)/util: | $(STATIC_OUTDIR) + mkdir $@ -autocompact_test: db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +.PHONY: STATIC_OBJDIRS +STATIC_OBJDIRS: \ + $(STATIC_OUTDIR)/db \ + $(STATIC_OUTDIR)/port \ + $(STATIC_OUTDIR)/table \ + $(STATIC_OUTDIR)/util \ + $(STATIC_OUTDIR)/helpers/memenv -bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SHARED_OUTDIR): + mkdir $@ -c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SHARED_OUTDIR)/db: | $(SHARED_OUTDIR) + mkdir $@ -cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SHARED_OUTDIR)/helpers/memenv: | $(SHARED_OUTDIR) + mkdir -p $@ -coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SHARED_OUTDIR)/port: | $(SHARED_OUTDIR) + mkdir $@ -corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SHARED_OUTDIR)/table: | $(SHARED_OUTDIR) + mkdir $@ -crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SHARED_OUTDIR)/util: | $(SHARED_OUTDIR) + mkdir $@ -db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +.PHONY: SHARED_OBJDIRS +SHARED_OBJDIRS: \ + $(SHARED_OUTDIR)/db \ + $(SHARED_OUTDIR)/port \ + $(SHARED_OUTDIR)/table \ + $(SHARED_OUTDIR)/util \ + $(SHARED_OUTDIR)/helpers/memenv -dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(DEVICE_OUTDIR): + mkdir $@ -env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(DEVICE_OUTDIR)/db: | $(DEVICE_OUTDIR) + mkdir $@ -filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(DEVICE_OUTDIR)/helpers/memenv: | $(DEVICE_OUTDIR) + mkdir -p $@ -filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(DEVICE_OUTDIR)/port: | $(DEVICE_OUTDIR) + mkdir $@ -hash_test: util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(DEVICE_OUTDIR)/table: | $(DEVICE_OUTDIR) + mkdir $@ -issue178_test: issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(DEVICE_OUTDIR)/util: | $(DEVICE_OUTDIR) + mkdir $@ -issue200_test: issues/issue200_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) issues/issue200_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +.PHONY: DEVICE_OBJDIRS +DEVICE_OBJDIRS: \ + $(DEVICE_OUTDIR)/db \ + $(DEVICE_OUTDIR)/port \ + $(DEVICE_OUTDIR)/table \ + $(DEVICE_OUTDIR)/util \ + $(DEVICE_OUTDIR)/helpers/memenv -log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SIMULATOR_OUTDIR): + mkdir $@ -table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SIMULATOR_OUTDIR)/db: | $(SIMULATOR_OUTDIR) + mkdir $@ -skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SIMULATOR_OUTDIR)/helpers/memenv: | $(SIMULATOR_OUTDIR) + mkdir -p $@ -version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SIMULATOR_OUTDIR)/port: | $(SIMULATOR_OUTDIR) + mkdir $@ -version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SIMULATOR_OUTDIR)/table: | $(SIMULATOR_OUTDIR) + mkdir $@ -write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +$(SIMULATOR_OUTDIR)/util: | $(SIMULATOR_OUTDIR) + mkdir $@ -$(MEMENVLIBRARY) : $(MEMENVOBJECTS) - rm -f $@ - $(AR) -rs $@ $(MEMENVOBJECTS) +.PHONY: SIMULATOR_OBJDIRS +SIMULATOR_OBJDIRS: \ + $(SIMULATOR_OUTDIR)/db \ + $(SIMULATOR_OUTDIR)/port \ + $(SIMULATOR_OUTDIR)/table \ + $(SIMULATOR_OUTDIR)/util \ + $(SIMULATOR_OUTDIR)/helpers/memenv -memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) - $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS) +$(STATIC_ALLOBJS): | STATIC_OBJDIRS +$(DEVICE_ALLOBJS): | DEVICE_OBJDIRS +$(SIMULATOR_ALLOBJS): | SIMULATOR_OBJDIRS +$(SHARED_ALLOBJS): | SHARED_OBJDIRS ifeq ($(PLATFORM), IOS) -# For iOS, create universal object files to be used on both the simulator and +$(DEVICE_OUTDIR)/libleveldb.a: $(DEVICE_LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(DEVICE_LIBOBJECTS) + +$(SIMULATOR_OUTDIR)/libleveldb.a: $(SIMULATOR_LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(SIMULATOR_LIBOBJECTS) + +$(DEVICE_OUTDIR)/libmemenv.a: $(DEVICE_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(DEVICE_MEMENVOBJECTS) + +$(SIMULATOR_OUTDIR)/libmemenv.a: $(SIMULATOR_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(SIMULATOR_MEMENVOBJECTS) + +# For iOS, create universal object libraries to be used on both the simulator and # a device. -PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms -SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer -DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer -IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString) -IOSARCH=-arch armv6 -arch armv7 -arch armv7s -arch arm64 - -.cc.o: - mkdir -p ios-x86/$(dir $@) - xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@ - mkdir -p ios-arm/$(dir $@) - xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@ - xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@ - -.c.o: - mkdir -p ios-x86/$(dir $@) - xcrun -sdk iphonesimulator $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@ - mkdir -p ios-arm/$(dir $@) - xcrun -sdk iphoneos $(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@ - xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@ +$(STATIC_OUTDIR)/libleveldb.a: $(STATIC_OUTDIR) $(DEVICE_OUTDIR)/libleveldb.a $(SIMULATOR_OUTDIR)/libleveldb.a + lipo -create $(DEVICE_OUTDIR)/libleveldb.a $(SIMULATOR_OUTDIR)/libleveldb.a -output $@ +$(STATIC_OUTDIR)/libmemenv.a: $(STATIC_OUTDIR) $(DEVICE_OUTDIR)/libmemenv.a $(SIMULATOR_OUTDIR)/libmemenv.a + lipo -create $(DEVICE_OUTDIR)/libmemenv.a $(SIMULATOR_OUTDIR)/libmemenv.a -output $@ else -.cc.o: +$(STATIC_OUTDIR)/libleveldb.a:$(STATIC_LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(STATIC_LIBOBJECTS) + +$(STATIC_OUTDIR)/libmemenv.a:$(STATIC_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(STATIC_MEMENVOBJECTS) +endif + +$(SHARED_MEMENVLIB):$(SHARED_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(SHARED_MEMENVOBJECTS) + +$(STATIC_OUTDIR)/db_bench:db/db_bench.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/db_bench.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/db_bench_sqlite3:doc/bench/db_bench_sqlite3.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) $(CXXFLAGS) doc/bench/db_bench_sqlite3.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS) + +$(STATIC_OUTDIR)/db_bench_tree_db:doc/bench/db_bench_tree_db.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) $(CXXFLAGS) doc/bench/db_bench_tree_db.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS) + +$(STATIC_OUTDIR)/leveldbutil:db/leveldbutil.cc $(STATIC_LIBOBJECTS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/leveldbutil.cc $(STATIC_LIBOBJECTS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/arena_test:util/arena_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/arena_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/autocompact_test:db/autocompact_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/autocompact_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/bloom_test:util/bloom_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/bloom_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/c_test:$(STATIC_OUTDIR)/db/c_test.o $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(STATIC_OUTDIR)/db/c_test.o $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/cache_test:util/cache_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/cache_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/coding_test:util/coding_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/coding_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/corruption_test:db/corruption_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/corruption_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/crc32c_test:util/crc32c_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/crc32c_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/db_test:db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/dbformat_test:db/dbformat_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/dbformat_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/env_posix_test:util/env_posix_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_posix_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/env_test:util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/fault_injection_test:db/fault_injection_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/fault_injection_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/filename_test:db/filename_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/filename_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/filter_block_test:table/filter_block_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) table/filter_block_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/hash_test:util/hash_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/hash_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/issue178_test:issues/issue178_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) issues/issue178_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/issue200_test:issues/issue200_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) issues/issue200_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/log_test:db/log_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/log_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/recovery_test:db/recovery_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/recovery_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/table_test:table/table_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) table/table_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/skiplist_test:db/skiplist_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/skiplist_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/version_edit_test:db/version_edit_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/version_edit_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/version_set_test:db/version_set_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/version_set_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/write_batch_test:db/write_batch_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/write_batch_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/memenv_test:$(STATIC_OUTDIR)/helpers/memenv/memenv_test.o $(STATIC_OUTDIR)/libmemenv.a $(STATIC_OUTDIR)/libleveldb.a $(TESTHARNESS) + $(XCRUN) $(CXX) $(LDFLAGS) $(STATIC_OUTDIR)/helpers/memenv/memenv_test.o $(STATIC_OUTDIR)/libmemenv.a $(STATIC_OUTDIR)/libleveldb.a $(TESTHARNESS) -o $@ $(LIBS) + +$(SHARED_OUTDIR)/db_bench:$(SHARED_OUTDIR)/db/db_bench.o $(SHARED_LIBS) $(TESTUTIL) + $(XCRUN) $(CXX) $(LDFLAGS) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SHARED_OUTDIR)/db/db_bench.o $(TESTUTIL) $(SHARED_OUTDIR)/$(SHARED_LIB3) -o $@ $(LIBS) + +.PHONY: run-shared +run-shared: $(SHARED_OUTDIR)/db_bench + LD_LIBRARY_PATH=$(SHARED_OUTDIR) $(SHARED_OUTDIR)/db_bench + +$(SIMULATOR_OUTDIR)/%.o: %.cc + xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) $(SIMULATOR_CFLAGS) -c $< -o $@ + +$(DEVICE_OUTDIR)/%.o: %.cc + xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) $(DEVICE_CFLAGS) -c $< -o $@ + +$(SIMULATOR_OUTDIR)/%.o: %.c + xcrun -sdk iphonesimulator $(CC) $(CFLAGS) $(SIMULATOR_CFLAGS) -c $< -o $@ + +$(DEVICE_OUTDIR)/%.o: %.c + xcrun -sdk iphoneos $(CC) $(CFLAGS) $(DEVICE_CFLAGS) -c $< -o $@ + +$(STATIC_OUTDIR)/%.o: %.cc $(CXX) $(CXXFLAGS) -c $< -o $@ -.c.o: +$(STATIC_OUTDIR)/%.o: %.c $(CC) $(CFLAGS) -c $< -o $@ -endif + +$(SHARED_OUTDIR)/%.o: %.cc + $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@ + +$(SHARED_OUTDIR)/%.o: %.c + $(CC) $(CFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@ + +$(STATIC_OUTDIR)/port/port_posix_sse.o: port/port_posix_sse.cc + $(CXX) $(CXXFLAGS) $(PLATFORM_SSEFLAGS) -c $< -o $@ + +$(SHARED_OUTDIR)/port/port_posix_sse.o: port/port_posix_sse.cc + $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(PLATFORM_SSEFLAGS) -c $< -o $@ diff --git a/src/leveldb/README b/src/leveldb/README deleted file mode 100644 index 3618adeeedbe..000000000000 --- a/src/leveldb/README +++ /dev/null @@ -1,51 +0,0 @@ -leveldb: A key-value store -Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) - -The code under this directory implements a system for maintaining a -persistent key/value store. - -See doc/index.html for more explanation. -See doc/impl.html for a brief overview of the implementation. - -The public interface is in include/*.h. Callers should not include or -rely on the details of any other header files in this package. Those -internal APIs may be changed without warning. - -Guide to header files: - -include/db.h - Main interface to the DB: Start here - -include/options.h - Control over the behavior of an entire database, and also - control over the behavior of individual reads and writes. - -include/comparator.h - Abstraction for user-specified comparison function. If you want - just bytewise comparison of keys, you can use the default comparator, - but clients can write their own comparator implementations if they - want custom ordering (e.g. to handle different character - encodings, etc.) - -include/iterator.h - Interface for iterating over data. You can get an iterator - from a DB object. - -include/write_batch.h - Interface for atomically applying multiple updates to a database. - -include/slice.h - A simple module for maintaining a pointer and a length into some - other byte array. - -include/status.h - Status is returned from many of the public interfaces and is used - to report success and various kinds of errors. - -include/env.h - Abstraction of the OS environment. A posix implementation of - this interface is in util/env_posix.cc - -include/table.h -include/table_builder.h - Lower-level modules that most clients probably won't use directly diff --git a/src/leveldb/README.md b/src/leveldb/README.md index 480affb5ca1d..a010c508585e 100644 --- a/src/leveldb/README.md +++ b/src/leveldb/README.md @@ -1,5 +1,7 @@ **LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.** +[![Build Status](https://travis-ci.org/google/leveldb.svg?branch=master)](https://travis-ci.org/google/leveldb) + Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) # Features @@ -10,9 +12,11 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) * Multiple changes can be made in one atomic batch. * Users can create a transient snapshot to get a consistent view of data. * Forward and backward iteration is supported over the data. - * Data is automatically compressed using the [Snappy compression library](http://code.google.com/p/snappy). + * Data is automatically compressed using the [Snappy compression library](http://google.github.io/snappy/). * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions. - * [Detailed documentation](http://htmlpreview.github.io/?https://github.com/google/leveldb/blob/master/doc/index.html) about how to use the library is included with the source code. + +# Documentation + [LevelDB library documentation](https://github.com/google/leveldb/blob/master/doc/index.md) is online and bundled with the source code. # Limitations @@ -20,6 +24,37 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) * Only a single process (possibly multi-threaded) can access a particular database at a time. * There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library. +# Contributing to the leveldb Project +The leveldb project welcomes contributions. leveldb's primary goal is to be +a reliable and fast key/value store. Changes that are in line with the +features/limitations outlined above, and meet the requirements below, +will be considered. + +Contribution requirements: + +1. **POSIX only**. We _generally_ will only accept changes that are both + compiled, and tested on a POSIX platform - usually Linux. Very small + changes will sometimes be accepted, but consider that more of an + exception than the rule. + +2. **Stable API**. We strive very hard to maintain a stable API. Changes that + require changes for projects using leveldb _might_ be rejected without + sufficient benefit to the project. + +3. **Tests**: All changes must be accompanied by a new (or changed) test, or + a sufficient explanation as to why a new (or changed) test is not required. + +## Submitting a Pull Request +Before any pull request will be accepted the author must first sign a +Contributor License Agreement (CLA) at https://cla.developers.google.com/. + +In order to keep the commit timeline linear +[squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits) +your changes down to a single commit and [rebase](https://git-scm.com/docs/git-rebase) +on google/leveldb/master. This keeps the commit timeline linear and more easily sync'ed +with the internal repository at Google. More information at GitHub's +[About Git rebase](https://help.github.com/articles/about-git-rebase/) page. + # Performance Here is a performance report (with explanations) from the run of the @@ -78,29 +113,30 @@ by the one or two disk seeks needed to fetch the data from disk. Write performance will be mostly unaffected by whether or not the working set fits in memory. - readrandom : 16.677 micros/op; (approximately 60,000 reads per second) - readseq : 0.476 micros/op; 232.3 MB/s - readreverse : 0.724 micros/op; 152.9 MB/s + readrandom : 16.677 micros/op; (approximately 60,000 reads per second) + readseq : 0.476 micros/op; 232.3 MB/s + readreverse : 0.724 micros/op; 152.9 MB/s LevelDB compacts its underlying storage data in the background to improve read performance. The results listed above were done immediately after a lot of random writes. The results after compactions (which are usually triggered automatically) are better. - readrandom : 11.602 micros/op; (approximately 85,000 reads per second) - readseq : 0.423 micros/op; 261.8 MB/s - readreverse : 0.663 micros/op; 166.9 MB/s + readrandom : 11.602 micros/op; (approximately 85,000 reads per second) + readseq : 0.423 micros/op; 261.8 MB/s + readreverse : 0.663 micros/op; 166.9 MB/s Some of the high cost of reads comes from repeated decompression of blocks read from disk. If we supply enough cache to the leveldb so it can hold the uncompressed blocks in memory, the read performance improves again: - readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction) - readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction) + readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction) + readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction) ## Repository contents -See doc/index.html for more explanation. See doc/impl.html for a brief overview of the implementation. +See [doc/index.md](doc/index.md) for more explanation. See +[doc/impl.md](doc/impl.md) for a brief overview of the implementation. The public interface is in include/*.h. Callers should not include or rely on the details of any other header files in this package. Those @@ -113,7 +149,7 @@ Guide to header files: * **include/options.h**: Control over the behavior of an entire database, and also control over the behavior of individual reads and writes. -* **include/comparator.h**: Abstraction for user-specified comparison function. +* **include/comparator.h**: Abstraction for user-specified comparison function. If you want just bytewise comparison of keys, you can use the default comparator, but clients can write their own comparator implementations if they want custom ordering (e.g. to handle different character encodings, etc.) @@ -130,7 +166,7 @@ length into some other byte array. * **include/status.h**: Status is returned from many of the public interfaces and is used to report success and various kinds of errors. -* **include/env.h**: +* **include/env.h**: Abstraction of the OS environment. A posix implementation of this interface is in util/env_posix.cc diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index a1101c1bdad8..4a9471590096 100755 --- a/src/leveldb/build_detect_platform +++ b/src/leveldb/build_detect_platform @@ -63,6 +63,7 @@ PLATFORM_SHARED_EXT="so" PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," PLATFORM_SHARED_CFLAGS="-fPIC" PLATFORM_SHARED_VERSIONED=true +PLATFORM_SSEFLAGS= MEMCMP_FLAG= if [ "$CXX" = "g++" ]; then @@ -77,6 +78,7 @@ case "$TARGET_OS" in COMMON_FLAGS="$MEMCMP_FLAG -lpthread -DOS_LINUX -DCYGWIN" PLATFORM_LDFLAGS="-lpthread" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; Darwin) PLATFORM=OS_MACOSX @@ -85,24 +87,28 @@ case "$TARGET_OS" in [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; Linux) PLATFORM=OS_LINUX COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX" PLATFORM_LDFLAGS="-pthread" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; SunOS) PLATFORM=OS_SOLARIS COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS" PLATFORM_LIBS="-lpthread -lrt" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; FreeBSD) PLATFORM=OS_FREEBSD COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD" PLATFORM_LIBS="-lpthread" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; GNU/kFreeBSD) PLATFORM=OS_KFREEBSD @@ -115,24 +121,28 @@ case "$TARGET_OS" in COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" PLATFORM_LIBS="-lpthread -lgcc_s" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; OpenBSD) PLATFORM=OS_OPENBSD COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD" PLATFORM_LDFLAGS="-pthread" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; DragonFly) PLATFORM=OS_DRAGONFLYBSD COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD" PLATFORM_LIBS="-lpthread" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc ;; OS_ANDROID_CROSSCOMPILE) PLATFORM=OS_ANDROID COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" PLATFORM_LDFLAGS="" # All pthread features are in the Android C library PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc CROSS_COMPILE=true ;; HP-UX) @@ -140,6 +150,7 @@ case "$TARGET_OS" in COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX" PLATFORM_LDFLAGS="-pthread" PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc # man ld: +h internal_name PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl," ;; @@ -148,6 +159,7 @@ case "$TARGET_OS" in COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc PLATFORM_SHARED_EXT= PLATFORM_SHARED_LDFLAGS= PLATFORM_SHARED_CFLAGS= @@ -175,14 +187,14 @@ DIRS="$PREFIX/db $PREFIX/util $PREFIX/table" set -f # temporarily disable globbing so that our patterns aren't expanded PRUNE_TEST="-name *test*.cc -prune" PRUNE_BENCH="-name *_bench.cc -prune" -PRUNE_TOOL="-name leveldb_main.cc -prune" +PRUNE_TOOL="-name leveldbutil.cc -prune" PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "` set +f # re-enable globbing # The sources consist of the portable files, plus the platform-specific port # file. -echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT +echo "SOURCES=$PORTABLE_FILES $PORT_FILE $PORT_SSE_FILE" >> $OUTPUT echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT if [ "$CROSS_COMPILE" = "true" ]; then @@ -213,6 +225,21 @@ EOF fi rm -f $CXXOUTPUT 2>/dev/null + + # Test if gcc SSE 4.2 is supported + $CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -msse4.2 2>/dev/null </dev/null +fi + +# Use the SSE 4.2 CRC32C intrinsics iff runtime checks indicate compiler supports them. +if [ -n "$PLATFORM_SSEFLAGS" ]; then + PLATFORM_SSEFLAGS="$PLATFORM_SSEFLAGS -DLEVELDB_PLATFORM_POSIX_SSE" fi PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS" @@ -225,6 +252,7 @@ echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT +echo "PLATFORM_SSEFLAGS=$PLATFORM_SSEFLAGS" >> $OUTPUT echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc index 96afc68913ce..37a484d25fea 100644 --- a/src/leveldb/db/corruption_test.cc +++ b/src/leveldb/db/corruption_test.cc @@ -36,7 +36,7 @@ class CorruptionTest { tiny_cache_ = NewLRUCache(100); options_.env = &env_; options_.block_cache = tiny_cache_; - dbname_ = test::TmpDir() + "/db_test"; + dbname_ = test::TmpDir() + "/corruption_test"; DestroyDB(dbname_, options_); db_ = NULL; diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc index 705a170aae47..3ad19a512b56 100644 --- a/src/leveldb/db/db_bench.cc +++ b/src/leveldb/db/db_bench.cc @@ -33,6 +33,7 @@ // readmissing -- read N missing keys in random order // readhot -- read N times in random order from 1% section of DB // seekrandom -- N random seeks +// open -- cost of opening a DB // crc32c -- repeated crc32c of 4K of data // acquireload -- load N*1000 times // Meta operations: @@ -83,6 +84,14 @@ static bool FLAGS_histogram = false; // (initialized to default value by "main") static int FLAGS_write_buffer_size = 0; +// Number of bytes written to each file. +// (initialized to default value by "main") +static int FLAGS_max_file_size = 0; + +// Approximate size of user data packed per block (before compression. +// (initialized to default value by "main") +static int FLAGS_block_size = 0; + // Number of bytes to use as a cache of uncompressed data. // Negative means use default settings. static int FLAGS_cache_size = -1; @@ -99,12 +108,16 @@ static int FLAGS_bloom_bits = -1; // benchmark will fail. static bool FLAGS_use_existing_db = false; +// If true, reuse existing log/MANIFEST files when re-opening a database. +static bool FLAGS_reuse_logs = false; + // Use the db with the following name. static const char* FLAGS_db = NULL; namespace leveldb { namespace { +leveldb::Env* g_env = NULL; // Helper for quickly generating random data. class RandomGenerator { @@ -138,6 +151,7 @@ class RandomGenerator { } }; +#if defined(__linux) static Slice TrimSpace(Slice s) { size_t start = 0; while (start < s.size() && isspace(s[start])) { @@ -149,6 +163,7 @@ static Slice TrimSpace(Slice s) { } return Slice(s.data() + start, limit - start); } +#endif static void AppendWithSpace(std::string* str, Slice msg) { if (msg.empty()) return; @@ -180,7 +195,7 @@ class Stats { done_ = 0; bytes_ = 0; seconds_ = 0; - start_ = Env::Default()->NowMicros(); + start_ = g_env->NowMicros(); finish_ = start_; message_.clear(); } @@ -198,7 +213,7 @@ class Stats { } void Stop() { - finish_ = Env::Default()->NowMicros(); + finish_ = g_env->NowMicros(); seconds_ = (finish_ - start_) * 1e-6; } @@ -208,7 +223,7 @@ class Stats { void FinishedSingleOp() { if (FLAGS_histogram) { - double now = Env::Default()->NowMicros(); + double now = g_env->NowMicros(); double micros = now - last_op_finish_; hist_.Add(micros); if (micros > 20000) { @@ -398,10 +413,10 @@ class Benchmark { reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), heap_counter_(0) { std::vector files; - Env::Default()->GetChildren(FLAGS_db, &files); + g_env->GetChildren(FLAGS_db, &files); for (size_t i = 0; i < files.size(); i++) { if (Slice(files[i]).starts_with("heap-")) { - Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); + g_env->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); } } if (!FLAGS_use_existing_db) { @@ -442,7 +457,11 @@ class Benchmark { bool fresh_db = false; int num_threads = FLAGS_threads; - if (name == Slice("fillseq")) { + if (name == Slice("open")) { + method = &Benchmark::OpenBench; + num_ /= 10000; + if (num_ < 1) num_ = 1; + } else if (name == Slice("fillseq")) { fresh_db = true; method = &Benchmark::WriteSeq; } else if (name == Slice("fillbatch")) { @@ -579,7 +598,7 @@ class Benchmark { arg[i].shared = &shared; arg[i].thread = new ThreadState(i); arg[i].thread->shared = &shared; - Env::Default()->StartThread(ThreadBody, &arg[i]); + g_env->StartThread(ThreadBody, &arg[i]); } shared.mu.Lock(); @@ -690,11 +709,15 @@ class Benchmark { void Open() { assert(db_ == NULL); Options options; + options.env = g_env; options.create_if_missing = !FLAGS_use_existing_db; options.block_cache = cache_; options.write_buffer_size = FLAGS_write_buffer_size; + options.max_file_size = FLAGS_max_file_size; + options.block_size = FLAGS_block_size; options.max_open_files = FLAGS_open_files; options.filter_policy = filter_policy_; + options.reuse_logs = FLAGS_reuse_logs; Status s = DB::Open(options, FLAGS_db, &db_); if (!s.ok()) { fprintf(stderr, "open error: %s\n", s.ToString().c_str()); @@ -702,6 +725,14 @@ class Benchmark { } } + void OpenBench(ThreadState* thread) { + for (int i = 0; i < num_; i++) { + delete db_; + Open(); + thread->stats.FinishedSingleOp(); + } + } + void WriteSeq(ThreadState* thread) { DoWrite(thread, true); } @@ -906,7 +937,7 @@ class Benchmark { char fname[100]; snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); WritableFile* file; - Status s = Env::Default()->NewWritableFile(fname, &file); + Status s = g_env->NewWritableFile(fname, &file); if (!s.ok()) { fprintf(stderr, "%s\n", s.ToString().c_str()); return; @@ -915,7 +946,7 @@ class Benchmark { delete file; if (!ok) { fprintf(stderr, "heap profiling not supported\n"); - Env::Default()->DeleteFile(fname); + g_env->DeleteFile(fname); } } }; @@ -924,6 +955,8 @@ class Benchmark { int main(int argc, char** argv) { FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; + FLAGS_max_file_size = leveldb::Options().max_file_size; + FLAGS_block_size = leveldb::Options().block_size; FLAGS_open_files = leveldb::Options().max_open_files; std::string default_db_path; @@ -941,6 +974,9 @@ int main(int argc, char** argv) { } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && (n == 0 || n == 1)) { FLAGS_use_existing_db = n; + } else if (sscanf(argv[i], "--reuse_logs=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_reuse_logs = n; } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { FLAGS_num = n; } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { @@ -951,6 +987,10 @@ int main(int argc, char** argv) { FLAGS_value_size = n; } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { FLAGS_write_buffer_size = n; + } else if (sscanf(argv[i], "--max_file_size=%d%c", &n, &junk) == 1) { + FLAGS_max_file_size = n; + } else if (sscanf(argv[i], "--block_size=%d%c", &n, &junk) == 1) { + FLAGS_block_size = n; } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { FLAGS_cache_size = n; } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { @@ -965,9 +1005,11 @@ int main(int argc, char** argv) { } } + leveldb::g_env = leveldb::Env::Default(); + // Choose a location for the test database if none given with --db= if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); + leveldb::g_env->GetTestDirectory(&default_db_path); default_db_path += "/dbbench"; FLAGS_db = default_db_path.c_str(); } diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc index 49b95953b4e9..3bb58e560aa7 100644 --- a/src/leveldb/db/db_impl.cc +++ b/src/leveldb/db/db_impl.cc @@ -96,6 +96,7 @@ Options SanitizeOptions(const std::string& dbname, result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.max_file_size, 1<<20, 1<<30); ClipToRange(&result.block_size, 1<<10, 4<<20); if (result.info_log == NULL) { // Open a log file in the same directory as the db @@ -125,7 +126,7 @@ DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) db_lock_(NULL), shutting_down_(NULL), bg_cv_(&mutex_), - mem_(new MemTable(internal_comparator_)), + mem_(NULL), imm_(NULL), logfile_(NULL), logfile_number_(0), @@ -134,7 +135,6 @@ DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) tmp_batch_(new WriteBatch), bg_compaction_scheduled_(false), manual_compaction_(NULL) { - mem_->Ref(); has_imm_.Release_Store(NULL); // Reserve ten files or so for other uses and give the rest to TableCache. @@ -271,7 +271,7 @@ void DBImpl::DeleteObsoleteFiles() { } } -Status DBImpl::Recover(VersionEdit* edit) { +Status DBImpl::Recover(VersionEdit* edit, bool *save_manifest) { mutex_.AssertHeld(); // Ignore error from CreateDir since the creation of the DB is @@ -301,66 +301,69 @@ Status DBImpl::Recover(VersionEdit* edit) { } } - s = versions_->Recover(); - if (s.ok()) { - SequenceNumber max_sequence(0); - - // Recover from all newer log files than the ones named in the - // descriptor (new log files may have been added by the previous - // incarnation without registering them in the descriptor). - // - // Note that PrevLogNumber() is no longer used, but we pay - // attention to it in case we are recovering a database - // produced by an older version of leveldb. - const uint64_t min_log = versions_->LogNumber(); - const uint64_t prev_log = versions_->PrevLogNumber(); - std::vector filenames; - s = env_->GetChildren(dbname_, &filenames); + s = versions_->Recover(save_manifest); + if (!s.ok()) { + return s; + } + SequenceNumber max_sequence(0); + + // Recover from all newer log files than the ones named in the + // descriptor (new log files may have been added by the previous + // incarnation without registering them in the descriptor). + // + // Note that PrevLogNumber() is no longer used, but we pay + // attention to it in case we are recovering a database + // produced by an older version of leveldb. + const uint64_t min_log = versions_->LogNumber(); + const uint64_t prev_log = versions_->PrevLogNumber(); + std::vector filenames; + s = env_->GetChildren(dbname_, &filenames); + if (!s.ok()) { + return s; + } + std::set expected; + versions_->AddLiveFiles(&expected); + uint64_t number; + FileType type; + std::vector logs; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + expected.erase(number); + if (type == kLogFile && ((number >= min_log) || (number == prev_log))) + logs.push_back(number); + } + } + if (!expected.empty()) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d missing files; e.g.", + static_cast(expected.size())); + return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); + } + + // Recover in the order in which the logs were generated + std::sort(logs.begin(), logs.end()); + for (size_t i = 0; i < logs.size(); i++) { + s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit, + &max_sequence); if (!s.ok()) { return s; } - std::set expected; - versions_->AddLiveFiles(&expected); - uint64_t number; - FileType type; - std::vector logs; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type)) { - expected.erase(number); - if (type == kLogFile && ((number >= min_log) || (number == prev_log))) - logs.push_back(number); - } - } - if (!expected.empty()) { - char buf[50]; - snprintf(buf, sizeof(buf), "%d missing files; e.g.", - static_cast(expected.size())); - return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); - } - - // Recover in the order in which the logs were generated - std::sort(logs.begin(), logs.end()); - for (size_t i = 0; i < logs.size(); i++) { - s = RecoverLogFile(logs[i], edit, &max_sequence); - // The previous incarnation may not have written any MANIFEST - // records after allocating this log number. So we manually - // update the file number allocation counter in VersionSet. - versions_->MarkFileNumberUsed(logs[i]); - } + // The previous incarnation may not have written any MANIFEST + // records after allocating this log number. So we manually + // update the file number allocation counter in VersionSet. + versions_->MarkFileNumberUsed(logs[i]); + } - if (s.ok()) { - if (versions_->LastSequence() < max_sequence) { - versions_->SetLastSequence(max_sequence); - } - } + if (versions_->LastSequence() < max_sequence) { + versions_->SetLastSequence(max_sequence); } - return s; + return Status::OK(); } -Status DBImpl::RecoverLogFile(uint64_t log_number, - VersionEdit* edit, +Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log, + bool* save_manifest, VersionEdit* edit, SequenceNumber* max_sequence) { struct LogReporter : public log::Reader::Reporter { Env* env; @@ -405,12 +408,13 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, std::string scratch; Slice record; WriteBatch batch; + int compactions = 0; MemTable* mem = NULL; while (reader.ReadRecord(&record, &scratch) && status.ok()) { if (record.size() < 12) { reporter.Corruption( - record.size(), Status::Corruption("log record too small")); + record.size(), Status::Corruption("log record too small", fname)); continue; } WriteBatchInternal::SetContents(&batch, record); @@ -432,25 +436,52 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, } if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { + compactions++; + *save_manifest = true; status = WriteLevel0Table(mem, edit, NULL); + mem->Unref(); + mem = NULL; if (!status.ok()) { // Reflect errors immediately so that conditions like full // file-systems cause the DB::Open() to fail. break; } - mem->Unref(); - mem = NULL; } } - if (status.ok() && mem != NULL) { - status = WriteLevel0Table(mem, edit, NULL); - // Reflect errors immediately so that conditions like full - // file-systems cause the DB::Open() to fail. + delete file; + + // See if we should keep reusing the last log file. + if (status.ok() && options_.reuse_logs && last_log && compactions == 0) { + assert(logfile_ == NULL); + assert(log_ == NULL); + assert(mem_ == NULL); + uint64_t lfile_size; + if (env_->GetFileSize(fname, &lfile_size).ok() && + env_->NewAppendableFile(fname, &logfile_).ok()) { + Log(options_.info_log, "Reusing old log %s \n", fname.c_str()); + log_ = new log::Writer(logfile_, lfile_size); + logfile_number_ = log_number; + if (mem != NULL) { + mem_ = mem; + mem = NULL; + } else { + // mem can be NULL if lognum exists but was empty. + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + } + } + } + + if (mem != NULL) { + // mem did not get reused; compact it. + if (status.ok()) { + *save_manifest = true; + status = WriteLevel0Table(mem, edit, NULL); + } + mem->Unref(); } - if (mem != NULL) mem->Unref(); - delete file; return status; } @@ -821,8 +852,9 @@ Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, delete iter; if (s.ok()) { Log(options_.info_log, - "Generated table #%llu: %lld keys, %lld bytes", + "Generated table #%llu@%d: %lld keys, %lld bytes", (unsigned long long) output_number, + compact->compaction->level(), (unsigned long long) current_entries, (unsigned long long) current_bytes); } @@ -1395,6 +1427,19 @@ bool DBImpl::GetProperty(const Slice& property, std::string* value) { } else if (in == "sstables") { *value = versions_->current()->DebugString(); return true; + } else if (in == "approximate-memory-usage") { + size_t total_usage = options_.block_cache->TotalCharge(); + if (mem_) { + total_usage += mem_->ApproximateMemoryUsage(); + } + if (imm_) { + total_usage += imm_->ApproximateMemoryUsage(); + } + char buf[50]; + snprintf(buf, sizeof(buf), "%llu", + static_cast(total_usage)); + value->append(buf); + return true; } return false; @@ -1449,8 +1494,11 @@ Status DB::Open(const Options& options, const std::string& dbname, DBImpl* impl = new DBImpl(options, dbname); impl->mutex_.Lock(); VersionEdit edit; - Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists - if (s.ok()) { + // Recover handles create_if_missing, error_if_exists + bool save_manifest = false; + Status s = impl->Recover(&edit, &save_manifest); + if (s.ok() && impl->mem_ == NULL) { + // Create new log and a corresponding memtable. uint64_t new_log_number = impl->versions_->NewFileNumber(); WritableFile* lfile; s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), @@ -1460,15 +1508,22 @@ Status DB::Open(const Options& options, const std::string& dbname, impl->logfile_ = lfile; impl->logfile_number_ = new_log_number; impl->log_ = new log::Writer(lfile); - s = impl->versions_->LogAndApply(&edit, &impl->mutex_); - } - if (s.ok()) { - impl->DeleteObsoleteFiles(); - impl->MaybeScheduleCompaction(); + impl->mem_ = new MemTable(impl->internal_comparator_); + impl->mem_->Ref(); } } + if (s.ok() && save_manifest) { + edit.SetPrevLogNumber(0); // No older logs needed after recovery. + edit.SetLogNumber(impl->logfile_number_); + s = impl->versions_->LogAndApply(&edit, &impl->mutex_); + } + if (s.ok()) { + impl->DeleteObsoleteFiles(); + impl->MaybeScheduleCompaction(); + } impl->mutex_.Unlock(); if (s.ok()) { + assert(impl->mem_ != NULL); *dbptr = impl; } else { delete impl; diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h index cfc998164af6..8ff323e72879 100644 --- a/src/leveldb/db/db_impl.h +++ b/src/leveldb/db/db_impl.h @@ -78,7 +78,8 @@ class DBImpl : public DB { // Recover the descriptor from persistent storage. May do a significant // amount of work to recover recently logged updates. Any changes to // be made to the descriptor are added to *edit. - Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Status Recover(VersionEdit* edit, bool* save_manifest) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); void MaybeIgnoreError(Status* s) const; @@ -90,9 +91,8 @@ class DBImpl : public DB { // Errors are recorded in bg_error_. void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_); - Status RecoverLogFile(uint64_t log_number, - VersionEdit* edit, - SequenceNumber* max_sequence) + Status RecoverLogFile(uint64_t log_number, bool last_log, bool* save_manifest, + VersionEdit* edit, SequenceNumber* max_sequence) EXCLUSIVE_LOCKS_REQUIRED(mutex_); Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc index 0fed9137d5ff..a0b08bc19c65 100644 --- a/src/leveldb/db/db_test.cc +++ b/src/leveldb/db/db_test.cc @@ -193,6 +193,7 @@ class DBTest { // Sequence of option configurations to try enum OptionConfig { kDefault, + kReuse, kFilter, kUncompressed, kEnd @@ -237,7 +238,11 @@ class DBTest { // Return the current option configuration. Options CurrentOptions() { Options options; + options.reuse_logs = false; switch (option_config_) { + case kReuse: + options.reuse_logs = true; + break; case kFilter: options.filter_policy = filter_policy_; break; @@ -558,6 +563,17 @@ TEST(DBTest, GetFromVersions) { } while (ChangeOptions()); } +TEST(DBTest, GetMemUsage) { + do { + ASSERT_OK(Put("foo", "v1")); + std::string val; + ASSERT_TRUE(db_->GetProperty("leveldb.approximate-memory-usage", &val)); + int mem_usage = atoi(val.c_str()); + ASSERT_GT(mem_usage, 0); + ASSERT_LT(mem_usage, 5*1024*1024); + } while (ChangeOptions()); +} + TEST(DBTest, GetSnapshot) { do { // Try with both a short key and a long key @@ -1080,6 +1096,14 @@ TEST(DBTest, ApproximateSizes) { // 0 because GetApproximateSizes() does not account for memtable space ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + if (options.reuse_logs) { + // Recovery will reuse memtable, and GetApproximateSizes() does not + // account for memtable usage; + Reopen(&options); + ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + continue; + } + // Check sizes across recovery by reopening a few times for (int run = 0; run < 3; run++) { Reopen(&options); @@ -1123,6 +1147,11 @@ TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); + if (options.reuse_logs) { + // Need to force a memtable compaction since recovery does not do so. + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + } + // Check sizes across recovery by reopening a few times for (int run = 0; run < 3; run++) { Reopen(&options); @@ -2084,7 +2113,8 @@ void BM_LogAndApply(int iters, int num_base_files) { InternalKeyComparator cmp(BytewiseComparator()); Options options; VersionSet vset(dbname, &options, NULL, &cmp); - ASSERT_OK(vset.Recover()); + bool save_manifest; + ASSERT_OK(vset.Recover(&save_manifest)); VersionEdit vbase; uint64_t fnum = 1; for (int i = 0; i < num_base_files; i++) { diff --git a/src/leveldb/db/fault_injection_test.cc b/src/leveldb/db/fault_injection_test.cc new file mode 100644 index 000000000000..875dfe81eeab --- /dev/null +++ b/src/leveldb/db/fault_injection_test.cc @@ -0,0 +1,554 @@ +// Copyright 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// This test uses a custom Env to keep track of the state of a filesystem as of +// the last "sync". It then checks for data loss errors by purposely dropping +// file data (or entire files) not protected by a "sync". + +#include "leveldb/db.h" + +#include +#include +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/log_format.h" +#include "db/version_set.h" +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kValueSize = 1000; +static const int kMaxNumValues = 2000; +static const size_t kNumIterations = 3; + +class FaultInjectionTestEnv; + +namespace { + +// Assume a filename, and not a directory name like "/foo/bar/" +static std::string GetDirName(const std::string filename) { + size_t found = filename.find_last_of("/\\"); + if (found == std::string::npos) { + return ""; + } else { + return filename.substr(0, found); + } +} + +Status SyncDir(const std::string& dir) { + // As this is a test it isn't required to *actually* sync this directory. + return Status::OK(); +} + +// A basic file truncation function suitable for this test. +Status Truncate(const std::string& filename, uint64_t length) { + leveldb::Env* env = leveldb::Env::Default(); + + SequentialFile* orig_file; + Status s = env->NewSequentialFile(filename, &orig_file); + if (!s.ok()) + return s; + + char* scratch = new char[length]; + leveldb::Slice result; + s = orig_file->Read(length, &result, scratch); + delete orig_file; + if (s.ok()) { + std::string tmp_name = GetDirName(filename) + "/truncate.tmp"; + WritableFile* tmp_file; + s = env->NewWritableFile(tmp_name, &tmp_file); + if (s.ok()) { + s = tmp_file->Append(result); + delete tmp_file; + if (s.ok()) { + s = env->RenameFile(tmp_name, filename); + } else { + env->DeleteFile(tmp_name); + } + } + } + + delete[] scratch; + + return s; +} + +struct FileState { + std::string filename_; + ssize_t pos_; + ssize_t pos_at_last_sync_; + ssize_t pos_at_last_flush_; + + FileState(const std::string& filename) + : filename_(filename), + pos_(-1), + pos_at_last_sync_(-1), + pos_at_last_flush_(-1) { } + + FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {} + + bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; } + + Status DropUnsyncedData() const; +}; + +} // anonymous namespace + +// A wrapper around WritableFile which informs another Env whenever this file +// is written to or sync'ed. +class TestWritableFile : public WritableFile { + public: + TestWritableFile(const FileState& state, + WritableFile* f, + FaultInjectionTestEnv* env); + virtual ~TestWritableFile(); + virtual Status Append(const Slice& data); + virtual Status Close(); + virtual Status Flush(); + virtual Status Sync(); + + private: + FileState state_; + WritableFile* target_; + bool writable_file_opened_; + FaultInjectionTestEnv* env_; + + Status SyncParent(); +}; + +class FaultInjectionTestEnv : public EnvWrapper { + public: + FaultInjectionTestEnv() : EnvWrapper(Env::Default()), filesystem_active_(true) {} + virtual ~FaultInjectionTestEnv() { } + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result); + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); + virtual Status DeleteFile(const std::string& f); + virtual Status RenameFile(const std::string& s, const std::string& t); + + void WritableFileClosed(const FileState& state); + Status DropUnsyncedFileData(); + Status DeleteFilesCreatedAfterLastDirSync(); + void DirWasSynced(); + bool IsFileCreatedSinceLastDirSync(const std::string& filename); + void ResetState(); + void UntrackFile(const std::string& f); + // Setting the filesystem to inactive is the test equivalent to simulating a + // system reset. Setting to inactive will freeze our saved filesystem state so + // that it will stop being recorded. It can then be reset back to the state at + // the time of the reset. + bool IsFilesystemActive() const { return filesystem_active_; } + void SetFilesystemActive(bool active) { filesystem_active_ = active; } + + private: + port::Mutex mutex_; + std::map db_file_state_; + std::set new_files_since_last_dir_sync_; + bool filesystem_active_; // Record flushes, syncs, writes +}; + +TestWritableFile::TestWritableFile(const FileState& state, + WritableFile* f, + FaultInjectionTestEnv* env) + : state_(state), + target_(f), + writable_file_opened_(true), + env_(env) { + assert(f != NULL); +} + +TestWritableFile::~TestWritableFile() { + if (writable_file_opened_) { + Close(); + } + delete target_; +} + +Status TestWritableFile::Append(const Slice& data) { + Status s = target_->Append(data); + if (s.ok() && env_->IsFilesystemActive()) { + state_.pos_ += data.size(); + } + return s; +} + +Status TestWritableFile::Close() { + writable_file_opened_ = false; + Status s = target_->Close(); + if (s.ok()) { + env_->WritableFileClosed(state_); + } + return s; +} + +Status TestWritableFile::Flush() { + Status s = target_->Flush(); + if (s.ok() && env_->IsFilesystemActive()) { + state_.pos_at_last_flush_ = state_.pos_; + } + return s; +} + +Status TestWritableFile::SyncParent() { + Status s = SyncDir(GetDirName(state_.filename_)); + if (s.ok()) { + env_->DirWasSynced(); + } + return s; +} + +Status TestWritableFile::Sync() { + if (!env_->IsFilesystemActive()) { + return Status::OK(); + } + // Ensure new files referred to by the manifest are in the filesystem. + Status s = target_->Sync(); + if (s.ok()) { + state_.pos_at_last_sync_ = state_.pos_; + } + if (env_->IsFileCreatedSinceLastDirSync(state_.filename_)) { + Status ps = SyncParent(); + if (s.ok() && !ps.ok()) { + s = ps; + } + } + return s; +} + +Status FaultInjectionTestEnv::NewWritableFile(const std::string& fname, + WritableFile** result) { + WritableFile* actual_writable_file; + Status s = target()->NewWritableFile(fname, &actual_writable_file); + if (s.ok()) { + FileState state(fname); + state.pos_ = 0; + *result = new TestWritableFile(state, actual_writable_file, this); + // NewWritableFile doesn't append to files, so if the same file is + // opened again then it will be truncated - so forget our saved + // state. + UntrackFile(fname); + MutexLock l(&mutex_); + new_files_since_last_dir_sync_.insert(fname); + } + return s; +} + +Status FaultInjectionTestEnv::NewAppendableFile(const std::string& fname, + WritableFile** result) { + WritableFile* actual_writable_file; + Status s = target()->NewAppendableFile(fname, &actual_writable_file); + if (s.ok()) { + FileState state(fname); + state.pos_ = 0; + { + MutexLock l(&mutex_); + if (db_file_state_.count(fname) == 0) { + new_files_since_last_dir_sync_.insert(fname); + } else { + state = db_file_state_[fname]; + } + } + *result = new TestWritableFile(state, actual_writable_file, this); + } + return s; +} + +Status FaultInjectionTestEnv::DropUnsyncedFileData() { + Status s; + MutexLock l(&mutex_); + for (std::map::const_iterator it = + db_file_state_.begin(); + s.ok() && it != db_file_state_.end(); ++it) { + const FileState& state = it->second; + if (!state.IsFullySynced()) { + s = state.DropUnsyncedData(); + } + } + return s; +} + +void FaultInjectionTestEnv::DirWasSynced() { + MutexLock l(&mutex_); + new_files_since_last_dir_sync_.clear(); +} + +bool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync( + const std::string& filename) { + MutexLock l(&mutex_); + return new_files_since_last_dir_sync_.find(filename) != + new_files_since_last_dir_sync_.end(); +} + +void FaultInjectionTestEnv::UntrackFile(const std::string& f) { + MutexLock l(&mutex_); + db_file_state_.erase(f); + new_files_since_last_dir_sync_.erase(f); +} + +Status FaultInjectionTestEnv::DeleteFile(const std::string& f) { + Status s = EnvWrapper::DeleteFile(f); + ASSERT_OK(s); + if (s.ok()) { + UntrackFile(f); + } + return s; +} + +Status FaultInjectionTestEnv::RenameFile(const std::string& s, + const std::string& t) { + Status ret = EnvWrapper::RenameFile(s, t); + + if (ret.ok()) { + MutexLock l(&mutex_); + if (db_file_state_.find(s) != db_file_state_.end()) { + db_file_state_[t] = db_file_state_[s]; + db_file_state_.erase(s); + } + + if (new_files_since_last_dir_sync_.erase(s) != 0) { + assert(new_files_since_last_dir_sync_.find(t) == + new_files_since_last_dir_sync_.end()); + new_files_since_last_dir_sync_.insert(t); + } + } + + return ret; +} + +void FaultInjectionTestEnv::ResetState() { + // Since we are not destroying the database, the existing files + // should keep their recorded synced/flushed state. Therefore + // we do not reset db_file_state_ and new_files_since_last_dir_sync_. + MutexLock l(&mutex_); + SetFilesystemActive(true); +} + +Status FaultInjectionTestEnv::DeleteFilesCreatedAfterLastDirSync() { + // Because DeleteFile access this container make a copy to avoid deadlock + mutex_.Lock(); + std::set new_files(new_files_since_last_dir_sync_.begin(), + new_files_since_last_dir_sync_.end()); + mutex_.Unlock(); + Status s; + std::set::const_iterator it; + for (it = new_files.begin(); s.ok() && it != new_files.end(); ++it) { + s = DeleteFile(*it); + } + return s; +} + +void FaultInjectionTestEnv::WritableFileClosed(const FileState& state) { + MutexLock l(&mutex_); + db_file_state_[state.filename_] = state; +} + +Status FileState::DropUnsyncedData() const { + ssize_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_; + return Truncate(filename_, sync_pos); +} + +class FaultInjectionTest { + public: + enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR }; + enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES }; + + FaultInjectionTestEnv* env_; + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + FaultInjectionTest() + : env_(new FaultInjectionTestEnv), + tiny_cache_(NewLRUCache(100)), + db_(NULL) { + dbname_ = test::TmpDir() + "/fault_test"; + DestroyDB(dbname_, Options()); // Destroy any db from earlier run + options_.reuse_logs = true; + options_.env = env_; + options_.paranoid_checks = true; + options_.block_cache = tiny_cache_; + options_.create_if_missing = true; + } + + ~FaultInjectionTest() { + CloseDB(); + DestroyDB(dbname_, Options()); + delete tiny_cache_; + delete env_; + } + + void ReuseLogs(bool reuse) { + options_.reuse_logs = reuse; + } + + void Build(int start_idx, int num_vals) { + std::string key_space, value_space; + WriteBatch batch; + for (int i = start_idx; i < start_idx + num_vals; i++) { + Slice key = Key(i, &key_space); + batch.Clear(); + batch.Put(key, Value(i, &value_space)); + WriteOptions options; + ASSERT_OK(db_->Write(options, &batch)); + } + } + + Status ReadValue(int i, std::string* val) const { + std::string key_space, value_space; + Slice key = Key(i, &key_space); + Value(i, &value_space); + ReadOptions options; + return db_->Get(options, key, val); + } + + Status Verify(int start_idx, int num_vals, + ExpectedVerifResult expected) const { + std::string val; + std::string value_space; + Status s; + for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) { + Value(i, &value_space); + s = ReadValue(i, &val); + if (expected == VAL_EXPECT_NO_ERROR) { + if (s.ok()) { + ASSERT_EQ(value_space, val); + } + } else if (s.ok()) { + fprintf(stderr, "Expected an error at %d, but was OK\n", i); + s = Status::IOError(dbname_, "Expected value error:"); + } else { + s = Status::OK(); // An expected error + } + } + return s; + } + + // Return the ith key + Slice Key(int i, std::string* storage) const { + char buf[100]; + snprintf(buf, sizeof(buf), "%016d", i); + storage->assign(buf, strlen(buf)); + return Slice(*storage); + } + + // Return the value to associate with the specified key + Slice Value(int k, std::string* storage) const { + Random r(k); + return test::RandomString(&r, kValueSize, storage); + } + + Status OpenDB() { + delete db_; + db_ = NULL; + env_->ResetState(); + return DB::Open(options_, dbname_, &db_); + } + + void CloseDB() { + delete db_; + db_ = NULL; + } + + void DeleteAllData() { + Iterator* iter = db_->NewIterator(ReadOptions()); + WriteOptions options; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ASSERT_OK(db_->Delete(WriteOptions(), iter->key())); + } + + delete iter; + } + + void ResetDBState(ResetMethod reset_method) { + switch (reset_method) { + case RESET_DROP_UNSYNCED_DATA: + ASSERT_OK(env_->DropUnsyncedFileData()); + break; + case RESET_DELETE_UNSYNCED_FILES: + ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync()); + break; + default: + assert(false); + } + } + + void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) { + DeleteAllData(); + Build(0, num_pre_sync); + db_->CompactRange(NULL, NULL); + Build(num_pre_sync, num_post_sync); + } + + void PartialCompactTestReopenWithFault(ResetMethod reset_method, + int num_pre_sync, + int num_post_sync) { + env_->SetFilesystemActive(false); + CloseDB(); + ResetDBState(reset_method); + ASSERT_OK(OpenDB()); + ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::VAL_EXPECT_NO_ERROR)); + ASSERT_OK(Verify(num_pre_sync, num_post_sync, FaultInjectionTest::VAL_EXPECT_ERROR)); + } + + void NoWriteTestPreFault() { + } + + void NoWriteTestReopenWithFault(ResetMethod reset_method) { + CloseDB(); + ResetDBState(reset_method); + ASSERT_OK(OpenDB()); + } + + void DoTest() { + Random rnd(0); + ASSERT_OK(OpenDB()); + for (size_t idx = 0; idx < kNumIterations; idx++) { + int num_pre_sync = rnd.Uniform(kMaxNumValues); + int num_post_sync = rnd.Uniform(kMaxNumValues); + + PartialCompactTestPreFault(num_pre_sync, num_post_sync); + PartialCompactTestReopenWithFault(RESET_DROP_UNSYNCED_DATA, + num_pre_sync, + num_post_sync); + + NoWriteTestPreFault(); + NoWriteTestReopenWithFault(RESET_DROP_UNSYNCED_DATA); + + PartialCompactTestPreFault(num_pre_sync, num_post_sync); + // No new files created so we expect all values since no files will be + // dropped. + PartialCompactTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES, + num_pre_sync + num_post_sync, + 0); + + NoWriteTestPreFault(); + NoWriteTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES); + } + } +}; + +TEST(FaultInjectionTest, FaultTestNoLogReuse) { + ReuseLogs(false); + DoTest(); +} + +TEST(FaultInjectionTest, FaultTestWithLogReuse) { + ReuseLogs(true); + DoTest(); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/leveldb_main.cc b/src/leveldb/db/leveldbutil.cc similarity index 96% rename from src/leveldb/db/leveldb_main.cc rename to src/leveldb/db/leveldbutil.cc index 9f4b7dd70c24..d06d64d640b1 100644 --- a/src/leveldb/db/leveldb_main.cc +++ b/src/leveldb/db/leveldbutil.cc @@ -19,6 +19,7 @@ class StdoutPrinter : public WritableFile { virtual Status Close() { return Status::OK(); } virtual Status Flush() { return Status::OK(); } virtual Status Sync() { return Status::OK(); } + virtual std::string GetName() const { return "[stdout]"; } }; bool HandleDumpCommand(Env* env, char** files, int num) { diff --git a/src/leveldb/db/log_format.h b/src/leveldb/db/log_format.h index a8c06efe185a..356e69fca231 100644 --- a/src/leveldb/db/log_format.h +++ b/src/leveldb/db/log_format.h @@ -3,7 +3,7 @@ // found in the LICENSE file. See the AUTHORS file for names of contributors. // // Log format information shared by reader and writer. -// See ../doc/log_format.txt for more detail. +// See ../doc/log_format.md for more detail. #ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ #define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc index e44b66c85bf7..8b6ad136d7da 100644 --- a/src/leveldb/db/log_reader.cc +++ b/src/leveldb/db/log_reader.cc @@ -25,7 +25,8 @@ Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, eof_(false), last_record_offset_(0), end_of_buffer_offset_(0), - initial_offset_(initial_offset) { + initial_offset_(initial_offset), + resyncing_(initial_offset > 0) { } Reader::~Reader() { @@ -72,8 +73,25 @@ bool Reader::ReadRecord(Slice* record, std::string* scratch) { Slice fragment; while (true) { - uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size(); const unsigned int record_type = ReadPhysicalRecord(&fragment); + + // ReadPhysicalRecord may have only had an empty trailer remaining in its + // internal buffer. Calculate the offset of the next physical record now + // that it has returned, properly accounting for its header size. + uint64_t physical_record_offset = + end_of_buffer_offset_ - buffer_.size() - kHeaderSize - fragment.size(); + + if (resyncing_) { + if (record_type == kMiddleType) { + continue; + } else if (record_type == kLastType) { + resyncing_ = false; + continue; + } else { + resyncing_ = false; + } + } + switch (record_type) { case kFullType: if (in_fragmented_record) { @@ -168,7 +186,7 @@ uint64_t Reader::LastRecordOffset() { } void Reader::ReportCorruption(uint64_t bytes, const char* reason) { - ReportDrop(bytes, Status::Corruption(reason)); + ReportDrop(bytes, Status::Corruption(reason, file_->GetName())); } void Reader::ReportDrop(uint64_t bytes, const Status& reason) { diff --git a/src/leveldb/db/log_reader.h b/src/leveldb/db/log_reader.h index 6aff7917162b..8389d61f8f1d 100644 --- a/src/leveldb/db/log_reader.h +++ b/src/leveldb/db/log_reader.h @@ -73,6 +73,11 @@ class Reader { // Offset at which to start looking for the first record to return uint64_t const initial_offset_; + // True if we are resynchronizing after a seek (initial_offset_ > 0). In + // particular, a run of kMiddleType and kLastType records can be silently + // skipped in this mode + bool resyncing_; + // Extend record types with the following special values enum { kEof = kMaxRecordType + 1, diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc index dcf056265297..48a5928657e0 100644 --- a/src/leveldb/db/log_test.cc +++ b/src/leveldb/db/log_test.cc @@ -79,7 +79,7 @@ class LogTest { virtual Status Skip(uint64_t n) { if (n > contents_.size()) { contents_.clear(); - return Status::NotFound("in-memory file skipepd past end"); + return Status::NotFound("in-memory file skipped past end"); } contents_.remove_prefix(n); @@ -104,23 +104,34 @@ class LogTest { StringSource source_; ReportCollector report_; bool reading_; - Writer writer_; - Reader reader_; + Writer* writer_; + Reader* reader_; // Record metadata for testing initial offset functionality static size_t initial_offset_record_sizes_[]; static uint64_t initial_offset_last_record_offsets_[]; + static int num_initial_offset_records_; public: LogTest() : reading_(false), - writer_(&dest_), - reader_(&source_, &report_, true/*checksum*/, - 0/*initial_offset*/) { + writer_(new Writer(&dest_)), + reader_(new Reader(&source_, &report_, true/*checksum*/, + 0/*initial_offset*/)) { + } + + ~LogTest() { + delete writer_; + delete reader_; + } + + void ReopenForAppend() { + delete writer_; + writer_ = new Writer(&dest_, dest_.contents_.size()); } void Write(const std::string& msg) { ASSERT_TRUE(!reading_) << "Write() after starting to read"; - writer_.AddRecord(Slice(msg)); + writer_->AddRecord(Slice(msg)); } size_t WrittenBytes() const { @@ -134,7 +145,7 @@ class LogTest { } std::string scratch; Slice record; - if (reader_.ReadRecord(&record, &scratch)) { + if (reader_->ReadRecord(&record, &scratch)) { return record.ToString(); } else { return "EOF"; @@ -182,13 +193,18 @@ class LogTest { } void WriteInitialOffsetLog() { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < num_initial_offset_records_; i++) { std::string record(initial_offset_record_sizes_[i], static_cast('a' + i)); Write(record); } } + void StartReadingAt(uint64_t initial_offset) { + delete reader_; + reader_ = new Reader(&source_, &report_, true/*checksum*/, initial_offset); + } + void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { WriteInitialOffsetLog(); reading_ = true; @@ -208,32 +224,48 @@ class LogTest { source_.contents_ = Slice(dest_.contents_); Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, initial_offset); - Slice record; - std::string scratch; - ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); - ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], - record.size()); - ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], - offset_reader->LastRecordOffset()); - ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); + + // Read all records from expected_record_offset through the last one. + ASSERT_LT(expected_record_offset, num_initial_offset_records_); + for (; expected_record_offset < num_initial_offset_records_; + ++expected_record_offset) { + Slice record; + std::string scratch; + ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); + ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], + record.size()); + ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], + offset_reader->LastRecordOffset()); + ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); + } delete offset_reader; } - }; size_t LogTest::initial_offset_record_sizes_[] = {10000, // Two sizable records in first block 10000, 2 * log::kBlockSize - 1000, // Span three blocks - 1}; + 1, + 13716, // Consume all but two bytes of block 3. + log::kBlockSize - kHeaderSize, // Consume the entirety of block 4. + }; uint64_t LogTest::initial_offset_last_record_offsets_[] = {0, kHeaderSize + 10000, 2 * (kHeaderSize + 10000), 2 * (kHeaderSize + 10000) + - (2 * log::kBlockSize - 1000) + 3 * kHeaderSize}; + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, + 2 * (kHeaderSize + 10000) + + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize + + kHeaderSize + 1, + 3 * log::kBlockSize, + }; +// LogTest::initial_offset_last_record_offsets_ must be defined before this. +int LogTest::num_initial_offset_records_ = + sizeof(LogTest::initial_offset_last_record_offsets_)/sizeof(uint64_t); TEST(LogTest, Empty) { ASSERT_EQ("EOF", Read()); @@ -318,6 +350,15 @@ TEST(LogTest, AlignedEof) { ASSERT_EQ("EOF", Read()); } +TEST(LogTest, OpenForAppend) { + Write("hello"); + ReopenForAppend(); + Write("world"); + ASSERT_EQ("hello", Read()); + ASSERT_EQ("world", Read()); + ASSERT_EQ("EOF", Read()); +} + TEST(LogTest, RandomRead) { const int N = 500; Random write_rnd(301); @@ -445,6 +486,22 @@ TEST(LogTest, PartialLastIsIgnored) { ASSERT_EQ(0, DroppedBytes()); } +TEST(LogTest, SkipIntoMultiRecord) { + // Consider a fragmented record: + // first(R1), middle(R1), last(R1), first(R2) + // If initial_offset points to a record after first(R1) but before first(R2) + // incomplete fragment errors are not actual errors, and must be suppressed + // until a new first or full record is encountered. + Write(BigString("foo", 3*kBlockSize)); + Write("correct"); + StartReadingAt(kBlockSize); + + ASSERT_EQ("correct", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("EOF", Read()); +} + TEST(LogTest, ErrorJoinsRecords) { // Consider two fragmented records: // first(R1) last(R1) first(R2) last(R2) @@ -514,6 +571,10 @@ TEST(LogTest, ReadFourthStart) { 3); } +TEST(LogTest, ReadInitialOffsetIntoBlockPadding) { + CheckInitialOffsetRecord(3 * log::kBlockSize - 3, 5); +} + TEST(LogTest, ReadEnd) { CheckOffsetPastEndReturnsNoRecords(0); } diff --git a/src/leveldb/db/log_writer.cc b/src/leveldb/db/log_writer.cc index 2da99ac08866..74a03270da85 100644 --- a/src/leveldb/db/log_writer.cc +++ b/src/leveldb/db/log_writer.cc @@ -12,15 +12,24 @@ namespace leveldb { namespace log { -Writer::Writer(WritableFile* dest) - : dest_(dest), - block_offset_(0) { +static void InitTypeCrc(uint32_t* type_crc) { for (int i = 0; i <= kMaxRecordType; i++) { char t = static_cast(i); - type_crc_[i] = crc32c::Value(&t, 1); + type_crc[i] = crc32c::Value(&t, 1); } } +Writer::Writer(WritableFile* dest) + : dest_(dest), + block_offset_(0) { + InitTypeCrc(type_crc_); +} + +Writer::Writer(WritableFile* dest, uint64_t dest_length) + : dest_(dest), block_offset_(dest_length % kBlockSize) { + InitTypeCrc(type_crc_); +} + Writer::~Writer() { } diff --git a/src/leveldb/db/log_writer.h b/src/leveldb/db/log_writer.h index a3a954d96732..9e7cc4705b01 100644 --- a/src/leveldb/db/log_writer.h +++ b/src/leveldb/db/log_writer.h @@ -22,6 +22,12 @@ class Writer { // "*dest" must be initially empty. // "*dest" must remain live while this Writer is in use. explicit Writer(WritableFile* dest); + + // Create a writer that will append data to "*dest". + // "*dest" must have initial length "dest_length". + // "*dest" must remain live while this Writer is in use. + Writer(WritableFile* dest, uint64_t dest_length); + ~Writer(); Status AddRecord(const Slice& slice); diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc index 31ad995d1253..287afdbdcb90 100644 --- a/src/leveldb/db/memtable.cc +++ b/src/leveldb/db/memtable.cc @@ -101,7 +101,7 @@ void MemTable::Add(SequenceNumber s, ValueType type, p += 8; p = EncodeVarint32(p, val_size); memcpy(p, value.data(), val_size); - assert((p + val_size) - buf == (long)encoded_len); + assert(p + val_size == buf + encoded_len); table_.Insert(buf); } diff --git a/src/leveldb/db/memtable.h b/src/leveldb/db/memtable.h index 92e90bb099f3..9f41567cde23 100644 --- a/src/leveldb/db/memtable.h +++ b/src/leveldb/db/memtable.h @@ -36,10 +36,7 @@ class MemTable { } // Returns an estimate of the number of bytes of data in use by this - // data structure. - // - // REQUIRES: external synchronization to prevent simultaneous - // operations on the same MemTable. + // data structure. It is safe to call when MemTable is being modified. size_t ApproximateMemoryUsage(); // Return an iterator that yields the contents of the memtable. diff --git a/src/leveldb/db/recovery_test.cc b/src/leveldb/db/recovery_test.cc new file mode 100644 index 000000000000..9596f4288a84 --- /dev/null +++ b/src/leveldb/db/recovery_test.cc @@ -0,0 +1,324 @@ +// Copyright (c) 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class RecoveryTest { + public: + RecoveryTest() : env_(Env::Default()), db_(NULL) { + dbname_ = test::TmpDir() + "/recovery_test"; + DestroyDB(dbname_, Options()); + Open(); + } + + ~RecoveryTest() { + Close(); + DestroyDB(dbname_, Options()); + } + + DBImpl* dbfull() const { return reinterpret_cast(db_); } + Env* env() const { return env_; } + + bool CanAppend() { + WritableFile* tmp; + Status s = env_->NewAppendableFile(CurrentFileName(dbname_), &tmp); + delete tmp; + if (s.IsNotSupportedError()) { + return false; + } else { + return true; + } + } + + void Close() { + delete db_; + db_ = NULL; + } + + void Open(Options* options = NULL) { + Close(); + Options opts; + if (options != NULL) { + opts = *options; + } else { + opts.reuse_logs = true; // TODO(sanjay): test both ways + opts.create_if_missing = true; + } + if (opts.env == NULL) { + opts.env = env_; + } + ASSERT_OK(DB::Open(opts, dbname_, &db_)); + ASSERT_EQ(1, NumLogs()); + } + + Status Put(const std::string& k, const std::string& v) { + return db_->Put(WriteOptions(), k, v); + } + + std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { + std::string result; + Status s = db_->Get(ReadOptions(), k, &result); + if (s.IsNotFound()) { + result = "NOT_FOUND"; + } else if (!s.ok()) { + result = s.ToString(); + } + return result; + } + + std::string ManifestFileName() { + std::string current; + ASSERT_OK(ReadFileToString(env_, CurrentFileName(dbname_), ¤t)); + size_t len = current.size(); + if (len > 0 && current[len-1] == '\n') { + current.resize(len - 1); + } + return dbname_ + "/" + current; + } + + std::string LogName(uint64_t number) { + return LogFileName(dbname_, number); + } + + size_t DeleteLogFiles() { + std::vector logs = GetFiles(kLogFile); + for (size_t i = 0; i < logs.size(); i++) { + ASSERT_OK(env_->DeleteFile(LogName(logs[i]))) << LogName(logs[i]); + } + return logs.size(); + } + + uint64_t FirstLogFile() { + return GetFiles(kLogFile)[0]; + } + + std::vector GetFiles(FileType t) { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + std::vector result; + for (size_t i = 0; i < filenames.size(); i++) { + uint64_t number; + FileType type; + if (ParseFileName(filenames[i], &number, &type) && type == t) { + result.push_back(number); + } + } + return result; + } + + int NumLogs() { + return GetFiles(kLogFile).size(); + } + + int NumTables() { + return GetFiles(kTableFile).size(); + } + + uint64_t FileSize(const std::string& fname) { + uint64_t result; + ASSERT_OK(env_->GetFileSize(fname, &result)) << fname; + return result; + } + + void CompactMemTable() { + dbfull()->TEST_CompactMemTable(); + } + + // Directly construct a log file that sets key to val. + void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Slice val) { + std::string fname = LogFileName(dbname_, lognum); + WritableFile* file; + ASSERT_OK(env_->NewWritableFile(fname, &file)); + log::Writer writer(file); + WriteBatch batch; + batch.Put(key, val); + WriteBatchInternal::SetSequence(&batch, seq); + ASSERT_OK(writer.AddRecord(WriteBatchInternal::Contents(&batch))); + ASSERT_OK(file->Flush()); + delete file; + } + + private: + std::string dbname_; + Env* env_; + DB* db_; +}; + +TEST(RecoveryTest, ManifestReused) { + if (!CanAppend()) { + fprintf(stderr, "skipping test because env does not support appending\n"); + return; + } + ASSERT_OK(Put("foo", "bar")); + Close(); + std::string old_manifest = ManifestFileName(); + Open(); + ASSERT_EQ(old_manifest, ManifestFileName()); + ASSERT_EQ("bar", Get("foo")); + Open(); + ASSERT_EQ(old_manifest, ManifestFileName()); + ASSERT_EQ("bar", Get("foo")); +} + +TEST(RecoveryTest, LargeManifestCompacted) { + if (!CanAppend()) { + fprintf(stderr, "skipping test because env does not support appending\n"); + return; + } + ASSERT_OK(Put("foo", "bar")); + Close(); + std::string old_manifest = ManifestFileName(); + + // Pad with zeroes to make manifest file very big. + { + uint64_t len = FileSize(old_manifest); + WritableFile* file; + ASSERT_OK(env()->NewAppendableFile(old_manifest, &file)); + std::string zeroes(3*1048576 - static_cast(len), 0); + ASSERT_OK(file->Append(zeroes)); + ASSERT_OK(file->Flush()); + delete file; + } + + Open(); + std::string new_manifest = ManifestFileName(); + ASSERT_NE(old_manifest, new_manifest); + ASSERT_GT(10000, FileSize(new_manifest)); + ASSERT_EQ("bar", Get("foo")); + + Open(); + ASSERT_EQ(new_manifest, ManifestFileName()); + ASSERT_EQ("bar", Get("foo")); +} + +TEST(RecoveryTest, NoLogFiles) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ(1, DeleteLogFiles()); + Open(); + ASSERT_EQ("NOT_FOUND", Get("foo")); + Open(); + ASSERT_EQ("NOT_FOUND", Get("foo")); +} + +TEST(RecoveryTest, LogFileReuse) { + if (!CanAppend()) { + fprintf(stderr, "skipping test because env does not support appending\n"); + return; + } + for (int i = 0; i < 2; i++) { + ASSERT_OK(Put("foo", "bar")); + if (i == 0) { + // Compact to ensure current log is empty + CompactMemTable(); + } + Close(); + ASSERT_EQ(1, NumLogs()); + uint64_t number = FirstLogFile(); + if (i == 0) { + ASSERT_EQ(0, FileSize(LogName(number))); + } else { + ASSERT_LT(0, FileSize(LogName(number))); + } + Open(); + ASSERT_EQ(1, NumLogs()); + ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file"; + ASSERT_EQ("bar", Get("foo")); + Open(); + ASSERT_EQ(1, NumLogs()); + ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file"; + ASSERT_EQ("bar", Get("foo")); + } +} + +TEST(RecoveryTest, MultipleMemTables) { + // Make a large log. + const int kNum = 1000; + for (int i = 0; i < kNum; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "%050d", i); + ASSERT_OK(Put(buf, buf)); + } + ASSERT_EQ(0, NumTables()); + Close(); + ASSERT_EQ(0, NumTables()); + ASSERT_EQ(1, NumLogs()); + uint64_t old_log_file = FirstLogFile(); + + // Force creation of multiple memtables by reducing the write buffer size. + Options opt; + opt.reuse_logs = true; + opt.write_buffer_size = (kNum*100) / 2; + Open(&opt); + ASSERT_LE(2, NumTables()); + ASSERT_EQ(1, NumLogs()); + ASSERT_NE(old_log_file, FirstLogFile()) << "must not reuse log"; + for (int i = 0; i < kNum; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "%050d", i); + ASSERT_EQ(buf, Get(buf)); + } +} + +TEST(RecoveryTest, MultipleLogFiles) { + ASSERT_OK(Put("foo", "bar")); + Close(); + ASSERT_EQ(1, NumLogs()); + + // Make a bunch of uncompacted log files. + uint64_t old_log = FirstLogFile(); + MakeLogFile(old_log+1, 1000, "hello", "world"); + MakeLogFile(old_log+2, 1001, "hi", "there"); + MakeLogFile(old_log+3, 1002, "foo", "bar2"); + + // Recover and check that all log files were processed. + Open(); + ASSERT_LE(1, NumTables()); + ASSERT_EQ(1, NumLogs()); + uint64_t new_log = FirstLogFile(); + ASSERT_LE(old_log+3, new_log); + ASSERT_EQ("bar2", Get("foo")); + ASSERT_EQ("world", Get("hello")); + ASSERT_EQ("there", Get("hi")); + + // Test that previous recovery produced recoverable state. + Open(); + ASSERT_LE(1, NumTables()); + ASSERT_EQ(1, NumLogs()); + if (CanAppend()) { + ASSERT_EQ(new_log, FirstLogFile()); + } + ASSERT_EQ("bar2", Get("foo")); + ASSERT_EQ("world", Get("hello")); + ASSERT_EQ("there", Get("hi")); + + // Check that introducing an older log file does not cause it to be re-read. + Close(); + MakeLogFile(old_log+1, 2000, "hello", "stale write"); + Open(); + ASSERT_LE(1, NumTables()); + ASSERT_EQ(1, NumLogs()); + if (CanAppend()) { + ASSERT_EQ(new_log, FirstLogFile()); + } + ASSERT_EQ("bar2", Get("foo")); + ASSERT_EQ("world", Get("hello")); + ASSERT_EQ("there", Get("hi")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc index 4cd4bb047f48..7281e3d3457f 100644 --- a/src/leveldb/db/repair.cc +++ b/src/leveldb/db/repair.cc @@ -203,7 +203,7 @@ class Repairer { while (reader.ReadRecord(&record, &scratch)) { if (record.size() < 12) { reporter.Corruption( - record.size(), Status::Corruption("log record too small")); + record.size(), Status::Corruption("log record too small", logname)); continue; } WriteBatchInternal::SetContents(&batch, record); diff --git a/src/leveldb/db/skiplist.h b/src/leveldb/db/skiplist.h index ed8b092203b6..8bd77764d8fb 100644 --- a/src/leveldb/db/skiplist.h +++ b/src/leveldb/db/skiplist.h @@ -1,10 +1,10 @@ -#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ -#define STORAGE_LEVELDB_DB_SKIPLIST_H_ - // Copyright (c) 2011 The LevelDB Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. -// + +#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ +#define STORAGE_LEVELDB_DB_SKIPLIST_H_ + // Thread safety // ------------- // diff --git a/src/leveldb/db/skiplist_test.cc b/src/leveldb/db/skiplist_test.cc index c78f4b4fb1a0..aee1461e1b25 100644 --- a/src/leveldb/db/skiplist_test.cc +++ b/src/leveldb/db/skiplist_test.cc @@ -250,7 +250,7 @@ class ConcurrentTest { // Note that generation 0 is never inserted, so it is ok if // <*,0,*> is missing. ASSERT_TRUE((gen(pos) == 0) || - (gen(pos) > initial_state.Get(key(pos))) + (gen(pos) > static_cast(initial_state.Get(key(pos)))) ) << "key: " << key(pos) << "; gen: " << gen(pos) << "; initgen: " diff --git a/src/leveldb/db/snapshot.h b/src/leveldb/db/snapshot.h index e7f8fd2c37cf..6ed413c42d4f 100644 --- a/src/leveldb/db/snapshot.h +++ b/src/leveldb/db/snapshot.h @@ -5,6 +5,7 @@ #ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ #define STORAGE_LEVELDB_DB_SNAPSHOT_H_ +#include "db/dbformat.h" #include "leveldb/db.h" namespace leveldb { diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index aa83df55e4ce..2cb6d80ed3cf 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -20,21 +20,29 @@ namespace leveldb { -static const int kTargetFileSize = 2 * 1048576; +static size_t TargetFileSize(const Options* options) { + return options->max_file_size; +} // Maximum bytes of overlaps in grandparent (i.e., level+2) before we // stop building a single file in a level->level+1 compaction. -static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; +static int64_t MaxGrandParentOverlapBytes(const Options* options) { + return 10 * TargetFileSize(options); +} // Maximum number of bytes in all compacted files. We avoid expanding // the lower level file set of a compaction if it would make the // total compaction cover more than this many bytes. -static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; +static int64_t ExpandedCompactionByteSizeLimit(const Options* options) { + return 25 * TargetFileSize(options); +} -static double MaxBytesForLevel(int level) { +static double MaxBytesForLevel(const Options* options, int level) { // Note: the result for level zero is not really used since we set // the level-0 compaction threshold based on number of files. - double result = 10 * 1048576.0; // Result for both level-0 and level-1 + + // Result for both level-0 and level-1 + double result = 10. * 1048576.0; while (level > 1) { result *= 10; level--; @@ -42,8 +50,9 @@ static double MaxBytesForLevel(int level) { return result; } -static uint64_t MaxFileSizeForLevel(int level) { - return kTargetFileSize; // We could vary per level to reduce number of files? +static uint64_t MaxFileSizeForLevel(const Options* options, int level) { + // We could vary per level to reduce number of files? + return TargetFileSize(options); } static int64_t TotalFileSize(const std::vector& files) { @@ -508,7 +517,7 @@ int Version::PickLevelForMemTableOutput( // Check that file does not overlap too many grandparent bytes. GetOverlappingInputs(level + 2, &start, &limit, &overlaps); const int64_t sum = TotalFileSize(overlaps); - if (sum > kMaxGrandParentOverlapBytes) { + if (sum > MaxGrandParentOverlapBytes(vset_->options_)) { break; } } @@ -893,7 +902,7 @@ Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { return s; } -Status VersionSet::Recover() { +Status VersionSet::Recover(bool *save_manifest) { struct LogReporter : public log::Reader::Reporter { Status* status; virtual void Corruption(size_t bytes, const Status& s) { @@ -1003,11 +1012,49 @@ Status VersionSet::Recover() { last_sequence_ = last_sequence; log_number_ = log_number; prev_log_number_ = prev_log_number; + + // See if we can reuse the existing MANIFEST file. + if (ReuseManifest(dscname, current)) { + // No need to save new manifest + } else { + *save_manifest = true; + } } return s; } +bool VersionSet::ReuseManifest(const std::string& dscname, + const std::string& dscbase) { + if (!options_->reuse_logs) { + return false; + } + FileType manifest_type; + uint64_t manifest_number; + uint64_t manifest_size; + if (!ParseFileName(dscbase, &manifest_number, &manifest_type) || + manifest_type != kDescriptorFile || + !env_->GetFileSize(dscname, &manifest_size).ok() || + // Make new compacted MANIFEST if old one is too big + manifest_size >= TargetFileSize(options_)) { + return false; + } + + assert(descriptor_file_ == NULL); + assert(descriptor_log_ == NULL); + Status r = env_->NewAppendableFile(dscname, &descriptor_file_); + if (!r.ok()) { + Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str()); + assert(descriptor_file_ == NULL); + return false; + } + + Log(options_->info_log, "Reusing MANIFEST %s\n", dscname.c_str()); + descriptor_log_ = new log::Writer(descriptor_file_, manifest_size); + manifest_file_number_ = manifest_number; + return true; +} + void VersionSet::MarkFileNumberUsed(uint64_t number) { if (next_file_number_ <= number) { next_file_number_ = number + 1; @@ -1038,7 +1085,8 @@ void VersionSet::Finalize(Version* v) { } else { // Compute the ratio of current size to size limit. const uint64_t level_bytes = TotalFileSize(v->files_[level]); - score = static_cast(level_bytes) / MaxBytesForLevel(level); + score = + static_cast(level_bytes) / MaxBytesForLevel(options_, level); } if (score > best_score) { @@ -1252,7 +1300,7 @@ Compaction* VersionSet::PickCompaction() { level = current_->compaction_level_; assert(level >= 0); assert(level+1 < config::kNumLevels); - c = new Compaction(level); + c = new Compaction(options_, level); // Pick the first file that comes after compact_pointer_[level] for (size_t i = 0; i < current_->files_[level].size(); i++) { @@ -1269,7 +1317,7 @@ Compaction* VersionSet::PickCompaction() { } } else if (seek_compaction) { level = current_->file_to_compact_level_; - c = new Compaction(level); + c = new Compaction(options_, level); c->inputs_[0].push_back(current_->file_to_compact_); } else { return NULL; @@ -1314,7 +1362,8 @@ void VersionSet::SetupOtherInputs(Compaction* c) { const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); const int64_t expanded0_size = TotalFileSize(expanded0); if (expanded0.size() > c->inputs_[0].size() && - inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { + inputs1_size + expanded0_size < + ExpandedCompactionByteSizeLimit(options_)) { InternalKey new_start, new_limit; GetRange(expanded0, &new_start, &new_limit); std::vector expanded1; @@ -1376,7 +1425,7 @@ Compaction* VersionSet::CompactRange( // and we must not pick one file and drop another older file if the // two files overlap. if (level > 0) { - const uint64_t limit = MaxFileSizeForLevel(level); + const uint64_t limit = MaxFileSizeForLevel(options_, level); uint64_t total = 0; for (size_t i = 0; i < inputs.size(); i++) { uint64_t s = inputs[i]->file_size; @@ -1388,7 +1437,7 @@ Compaction* VersionSet::CompactRange( } } - Compaction* c = new Compaction(level); + Compaction* c = new Compaction(options_, level); c->input_version_ = current_; c->input_version_->Ref(); c->inputs_[0] = inputs; @@ -1396,9 +1445,9 @@ Compaction* VersionSet::CompactRange( return c; } -Compaction::Compaction(int level) +Compaction::Compaction(const Options* options, int level) : level_(level), - max_output_file_size_(MaxFileSizeForLevel(level)), + max_output_file_size_(MaxFileSizeForLevel(options, level)), input_version_(NULL), grandparent_index_(0), seen_key_(false), @@ -1415,12 +1464,13 @@ Compaction::~Compaction() { } bool Compaction::IsTrivialMove() const { + const VersionSet* vset = input_version_->vset_; // Avoid a move if there is lots of overlapping grandparent data. // Otherwise, the move could create a parent file that will require // a very expensive merge later on. - return (num_input_files(0) == 1 && - num_input_files(1) == 0 && - TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); + return (num_input_files(0) == 1 && num_input_files(1) == 0 && + TotalFileSize(grandparents_) <= + MaxGrandParentOverlapBytes(vset->options_)); } void Compaction::AddInputDeletions(VersionEdit* edit) { @@ -1453,8 +1503,9 @@ bool Compaction::IsBaseLevelForKey(const Slice& user_key) { } bool Compaction::ShouldStopBefore(const Slice& internal_key) { + const VersionSet* vset = input_version_->vset_; // Scan to find earliest grandparent file that contains key. - const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; + const InternalKeyComparator* icmp = &vset->icmp_; while (grandparent_index_ < grandparents_.size() && icmp->Compare(internal_key, grandparents_[grandparent_index_]->largest.Encode()) > 0) { @@ -1465,7 +1516,7 @@ bool Compaction::ShouldStopBefore(const Slice& internal_key) { } seen_key_ = true; - if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { + if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) { // Too much overlap for current output; start new output overlapped_bytes_ = 0; return true; diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h index 8dc14b8e01c9..7935a965a7c9 100644 --- a/src/leveldb/db/version_set.h +++ b/src/leveldb/db/version_set.h @@ -179,7 +179,7 @@ class VersionSet { EXCLUSIVE_LOCKS_REQUIRED(mu); // Recover the last saved descriptor from persistent storage. - Status Recover(); + Status Recover(bool *save_manifest); // Return the current version. Version* current() const { return current_; } @@ -274,6 +274,8 @@ class VersionSet { friend class Compaction; friend class Version; + bool ReuseManifest(const std::string& dscname, const std::string& dscbase); + void Finalize(Version* v); void GetRange(const std::vector& inputs, @@ -364,7 +366,7 @@ class Compaction { friend class Version; friend class VersionSet; - explicit Compaction(int level); + Compaction(const Options* options, int level); int level_; uint64_t max_output_file_size_; @@ -374,7 +376,7 @@ class Compaction { // Each compaction reads inputs from "level_" and "level_+1" std::vector inputs_[2]; // The two sets of inputs - // State used to check for number of of overlapping grandparent files + // State used to check for number of overlapping grandparent files // (parent == level_ + 1, grandparent == level_ + 2) std::vector grandparents_; size_t grandparent_index_; // Index in grandparent_starts_ diff --git a/src/leveldb/db/write_batch_internal.h b/src/leveldb/db/write_batch_internal.h index 310a3c891220..9448ef7b21c3 100644 --- a/src/leveldb/db/write_batch_internal.h +++ b/src/leveldb/db/write_batch_internal.h @@ -5,6 +5,7 @@ #ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ #define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ +#include "db/dbformat.h" #include "leveldb/write_batch.h" namespace leveldb { diff --git a/src/leveldb/doc/doc.css b/src/leveldb/doc/doc.css deleted file mode 100644 index 700c564e4338..000000000000 --- a/src/leveldb/doc/doc.css +++ /dev/null @@ -1,89 +0,0 @@ -body { - margin-left: 0.5in; - margin-right: 0.5in; - background: white; - color: black; -} - -h1 { - margin-left: -0.2in; - font-size: 14pt; -} -h2 { - margin-left: -0in; - font-size: 12pt; -} -h3 { - margin-left: -0in; -} -h4 { - margin-left: -0in; -} -hr { - margin-left: -0in; -} - -/* Definition lists: definition term bold */ -dt { - font-weight: bold; -} - -address { - text-align: center; -} -code,samp,var { - color: blue; -} -kbd { - color: #600000; -} -div.note p { - float: right; - width: 3in; - margin-right: 0%; - padding: 1px; - border: 2px solid #6060a0; - background-color: #fffff0; -} - -ul { - margin-top: -0em; - margin-bottom: -0em; -} - -ol { - margin-top: -0em; - margin-bottom: -0em; -} - -UL.nobullets { - list-style-type: none; - list-style-image: none; - margin-left: -1em; -} - -p { - margin: 1em 0 1em 0; - padding: 0 0 0 0; -} - -pre { - line-height: 1.3em; - padding: 0.4em 0 0.8em 0; - margin: 0 0 0 0; - border: 0 0 0 0; - color: blue; -} - -.datatable { - margin-left: auto; - margin-right: auto; - margin-top: 2em; - margin-bottom: 2em; - border: 1px solid; -} - -.datatable td,th { - padding: 0 0.5em 0 0.5em; - text-align: right; -} diff --git a/src/leveldb/doc/impl.html b/src/leveldb/doc/impl.html deleted file mode 100644 index 6a468be0955d..000000000000 --- a/src/leveldb/doc/impl.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - -Leveldb file layout and compactions - - - - -

Files

- -The implementation of leveldb is similar in spirit to the -representation of a single - -Bigtable tablet (section 5.3). -However the organization of the files that make up the representation -is somewhat different and is explained below. - -

-Each database is represented by a set of files stored in a directory. -There are several different types of files as documented below: -

-

Log files

-

-A log file (*.log) stores a sequence of recent updates. Each update -is appended to the current log file. When the log file reaches a -pre-determined size (approximately 4MB by default), it is converted -to a sorted table (see below) and a new log file is created for future -updates. -

-A copy of the current log file is kept in an in-memory structure (the -memtable). This copy is consulted on every read so that read -operations reflect all logged updates. -

-

Sorted tables

-

-A sorted table (*.sst) stores a sequence of entries sorted by key. -Each entry is either a value for the key, or a deletion marker for the -key. (Deletion markers are kept around to hide obsolete values -present in older sorted tables). -

-The set of sorted tables are organized into a sequence of levels. The -sorted table generated from a log file is placed in a special young -level (also called level-0). When the number of young files exceeds a -certain threshold (currently four), all of the young files are merged -together with all of the overlapping level-1 files to produce a -sequence of new level-1 files (we create a new level-1 file for every -2MB of data.) -

-Files in the young level may contain overlapping keys. However files -in other levels have distinct non-overlapping key ranges. Consider -level number L where L >= 1. When the combined size of files in -level-L exceeds (10^L) MB (i.e., 10MB for level-1, 100MB for level-2, -...), one file in level-L, and all of the overlapping files in -level-(L+1) are merged to form a set of new files for level-(L+1). -These merges have the effect of gradually migrating new updates from -the young level to the largest level using only bulk reads and writes -(i.e., minimizing expensive seeks). - -

Manifest

-

-A MANIFEST file lists the set of sorted tables that make up each -level, the corresponding key ranges, and other important metadata. -A new MANIFEST file (with a new number embedded in the file name) -is created whenever the database is reopened. The MANIFEST file is -formatted as a log, and changes made to the serving state (as files -are added or removed) are appended to this log. -

-

Current

-

-CURRENT is a simple text file that contains the name of the latest -MANIFEST file. -

-

Info logs

-

-Informational messages are printed to files named LOG and LOG.old. -

-

Others

-

-Other files used for miscellaneous purposes may also be present -(LOCK, *.dbtmp). - -

Level 0

-When the log file grows above a certain size (1MB by default): -
    -
  • Create a brand new memtable and log file and direct future updates here -
  • In the background: -
      -
    • Write the contents of the previous memtable to an sstable -
    • Discard the memtable -
    • Delete the old log file and the old memtable -
    • Add the new sstable to the young (level-0) level. -
    -
- -

Compactions

- -

-When the size of level L exceeds its limit, we compact it in a -background thread. The compaction picks a file from level L and all -overlapping files from the next level L+1. Note that if a level-L -file overlaps only part of a level-(L+1) file, the entire file at -level-(L+1) is used as an input to the compaction and will be -discarded after the compaction. Aside: because level-0 is special -(files in it may overlap each other), we treat compactions from -level-0 to level-1 specially: a level-0 compaction may pick more than -one level-0 file in case some of these files overlap each other. - -

-A compaction merges the contents of the picked files to produce a -sequence of level-(L+1) files. We switch to producing a new -level-(L+1) file after the current output file has reached the target -file size (2MB). We also switch to a new output file when the key -range of the current output file has grown enough to overlap more than -ten level-(L+2) files. This last rule ensures that a later compaction -of a level-(L+1) file will not pick up too much data from level-(L+2). - -

-The old files are discarded and the new files are added to the serving -state. - -

-Compactions for a particular level rotate through the key space. In -more detail, for each level L, we remember the ending key of the last -compaction at level L. The next compaction for level L will pick the -first file that starts after this key (wrapping around to the -beginning of the key space if there is no such file). - -

-Compactions drop overwritten values. They also drop deletion markers -if there are no higher numbered levels that contain a file whose range -overlaps the current key. - -

Timing

- -Level-0 compactions will read up to four 1MB files from level-0, and -at worst all the level-1 files (10MB). I.e., we will read 14MB and -write 14MB. - -

-Other than the special level-0 compactions, we will pick one 2MB file -from level L. In the worst case, this will overlap ~ 12 files from -level L+1 (10 because level-(L+1) is ten times the size of level-L, -and another two at the boundaries since the file ranges at level-L -will usually not be aligned with the file ranges at level-L+1). The -compaction will therefore read 26MB and write 26MB. Assuming a disk -IO rate of 100MB/s (ballpark range for modern drives), the worst -compaction cost will be approximately 0.5 second. - -

-If we throttle the background writing to something small, say 10% of -the full 100MB/s speed, a compaction may take up to 5 seconds. If the -user is writing at 10MB/s, we might build up lots of level-0 files -(~50 to hold the 5*10MB). This may significantly increase the cost of -reads due to the overhead of merging more files together on every -read. - -

-Solution 1: To reduce this problem, we might want to increase the log -switching threshold when the number of level-0 files is large. Though -the downside is that the larger this threshold, the more memory we will -need to hold the corresponding memtable. - -

-Solution 2: We might want to decrease write rate artificially when the -number of level-0 files goes up. - -

-Solution 3: We work on reducing the cost of very wide merges. -Perhaps most of the level-0 files will have their blocks sitting -uncompressed in the cache and we will only need to worry about the -O(N) complexity in the merging iterator. - -

Number of files

- -Instead of always making 2MB files, we could make larger files for -larger levels to reduce the total file count, though at the expense of -more bursty compactions. Alternatively, we could shard the set of -files into multiple directories. - -

-An experiment on an ext3 filesystem on Feb 04, 2011 shows -the following timings to do 100K file opens in directories with -varying number of files: - - - - - -
Files in directoryMicroseconds to open a file
10009
1000010
10000016
-So maybe even the sharding is not necessary on modern filesystems? - -

Recovery

- -
    -
  • Read CURRENT to find name of the latest committed MANIFEST -
  • Read the named MANIFEST file -
  • Clean up stale files -
  • We could open all sstables here, but it is probably better to be lazy... -
  • Convert log chunk to a new level-0 sstable -
  • Start directing new writes to a new log file with recovered sequence# -
- -

Garbage collection of files

- -DeleteObsoleteFiles() is called at the end of every -compaction and at the end of recovery. It finds the names of all -files in the database. It deletes all log files that are not the -current log file. It deletes all table files that are not referenced -from some level and are not the output of an active compaction. - - - diff --git a/src/leveldb/doc/impl.md b/src/leveldb/doc/impl.md new file mode 100644 index 000000000000..4b13f2a6ba73 --- /dev/null +++ b/src/leveldb/doc/impl.md @@ -0,0 +1,170 @@ +## Files + +The implementation of leveldb is similar in spirit to the representation of a +single [Bigtable tablet (section 5.3)](http://research.google.com/archive/bigtable.html). +However the organization of the files that make up the representation is +somewhat different and is explained below. + +Each database is represented by a set of files stored in a directory. There are +several different types of files as documented below: + +### Log files + +A log file (*.log) stores a sequence of recent updates. Each update is appended +to the current log file. When the log file reaches a pre-determined size +(approximately 4MB by default), it is converted to a sorted table (see below) +and a new log file is created for future updates. + +A copy of the current log file is kept in an in-memory structure (the +`memtable`). This copy is consulted on every read so that read operations +reflect all logged updates. + +## Sorted tables + +A sorted table (*.ldb) stores a sequence of entries sorted by key. Each entry is +either a value for the key, or a deletion marker for the key. (Deletion markers +are kept around to hide obsolete values present in older sorted tables). + +The set of sorted tables are organized into a sequence of levels. The sorted +table generated from a log file is placed in a special **young** level (also +called level-0). When the number of young files exceeds a certain threshold +(currently four), all of the young files are merged together with all of the +overlapping level-1 files to produce a sequence of new level-1 files (we create +a new level-1 file for every 2MB of data.) + +Files in the young level may contain overlapping keys. However files in other +levels have distinct non-overlapping key ranges. Consider level number L where +L >= 1. When the combined size of files in level-L exceeds (10^L) MB (i.e., 10MB +for level-1, 100MB for level-2, ...), one file in level-L, and all of the +overlapping files in level-(L+1) are merged to form a set of new files for +level-(L+1). These merges have the effect of gradually migrating new updates +from the young level to the largest level using only bulk reads and writes +(i.e., minimizing expensive seeks). + +### Manifest + +A MANIFEST file lists the set of sorted tables that make up each level, the +corresponding key ranges, and other important metadata. A new MANIFEST file +(with a new number embedded in the file name) is created whenever the database +is reopened. The MANIFEST file is formatted as a log, and changes made to the +serving state (as files are added or removed) are appended to this log. + +### Current + +CURRENT is a simple text file that contains the name of the latest MANIFEST +file. + +### Info logs + +Informational messages are printed to files named LOG and LOG.old. + +### Others + +Other files used for miscellaneous purposes may also be present (LOCK, *.dbtmp). + +## Level 0 + +When the log file grows above a certain size (1MB by default): +Create a brand new memtable and log file and direct future updates here +In the background: +Write the contents of the previous memtable to an sstable +Discard the memtable +Delete the old log file and the old memtable +Add the new sstable to the young (level-0) level. + +## Compactions + +When the size of level L exceeds its limit, we compact it in a background +thread. The compaction picks a file from level L and all overlapping files from +the next level L+1. Note that if a level-L file overlaps only part of a +level-(L+1) file, the entire file at level-(L+1) is used as an input to the +compaction and will be discarded after the compaction. Aside: because level-0 +is special (files in it may overlap each other), we treat compactions from +level-0 to level-1 specially: a level-0 compaction may pick more than one +level-0 file in case some of these files overlap each other. + +A compaction merges the contents of the picked files to produce a sequence of +level-(L+1) files. We switch to producing a new level-(L+1) file after the +current output file has reached the target file size (2MB). We also switch to a +new output file when the key range of the current output file has grown enough +to overlap more than ten level-(L+2) files. This last rule ensures that a later +compaction of a level-(L+1) file will not pick up too much data from +level-(L+2). + +The old files are discarded and the new files are added to the serving state. + +Compactions for a particular level rotate through the key space. In more detail, +for each level L, we remember the ending key of the last compaction at level L. +The next compaction for level L will pick the first file that starts after this +key (wrapping around to the beginning of the key space if there is no such +file). + +Compactions drop overwritten values. They also drop deletion markers if there +are no higher numbered levels that contain a file whose range overlaps the +current key. + +### Timing + +Level-0 compactions will read up to four 1MB files from level-0, and at worst +all the level-1 files (10MB). I.e., we will read 14MB and write 14MB. + +Other than the special level-0 compactions, we will pick one 2MB file from level +L. In the worst case, this will overlap ~ 12 files from level L+1 (10 because +level-(L+1) is ten times the size of level-L, and another two at the boundaries +since the file ranges at level-L will usually not be aligned with the file +ranges at level-L+1). The compaction will therefore read 26MB and write 26MB. +Assuming a disk IO rate of 100MB/s (ballpark range for modern drives), the worst +compaction cost will be approximately 0.5 second. + +If we throttle the background writing to something small, say 10% of the full +100MB/s speed, a compaction may take up to 5 seconds. If the user is writing at +10MB/s, we might build up lots of level-0 files (~50 to hold the 5*10MB). This +may significantly increase the cost of reads due to the overhead of merging more +files together on every read. + +Solution 1: To reduce this problem, we might want to increase the log switching +threshold when the number of level-0 files is large. Though the downside is that +the larger this threshold, the more memory we will need to hold the +corresponding memtable. + +Solution 2: We might want to decrease write rate artificially when the number of +level-0 files goes up. + +Solution 3: We work on reducing the cost of very wide merges. Perhaps most of +the level-0 files will have their blocks sitting uncompressed in the cache and +we will only need to worry about the O(N) complexity in the merging iterator. + +### Number of files + +Instead of always making 2MB files, we could make larger files for larger levels +to reduce the total file count, though at the expense of more bursty +compactions. Alternatively, we could shard the set of files into multiple +directories. + +An experiment on an ext3 filesystem on Feb 04, 2011 shows the following timings +to do 100K file opens in directories with varying number of files: + + +| Files in directory | Microseconds to open a file | +|-------------------:|----------------------------:| +| 1000 | 9 | +| 10000 | 10 | +| 100000 | 16 | + +So maybe even the sharding is not necessary on modern filesystems? + +## Recovery + +* Read CURRENT to find name of the latest committed MANIFEST +* Read the named MANIFEST file +* Clean up stale files +* We could open all sstables here, but it is probably better to be lazy... +* Convert log chunk to a new level-0 sstable +* Start directing new writes to a new log file with recovered sequence# + +## Garbage collection of files + +`DeleteObsoleteFiles()` is called at the end of every compaction and at the end +of recovery. It finds the names of all files in the database. It deletes all log +files that are not the current log file. It deletes all table files that are not +referenced from some level and are not the output of an active compaction. diff --git a/src/leveldb/doc/index.html b/src/leveldb/doc/index.html deleted file mode 100644 index 3ed0ed9d9e30..000000000000 --- a/src/leveldb/doc/index.html +++ /dev/null @@ -1,549 +0,0 @@ - - - - -Leveldb - - - -

Leveldb

-
Jeff Dean, Sanjay Ghemawat
-

-The leveldb library provides a persistent key value store. Keys and -values are arbitrary byte arrays. The keys are ordered within the key -value store according to a user-specified comparator function. - -

-

Opening A Database

-

-A leveldb database has a name which corresponds to a file system -directory. All of the contents of database are stored in this -directory. The following example shows how to open a database, -creating it if necessary: -

-

-  #include <assert>
-  #include "leveldb/db.h"
-
-  leveldb::DB* db;
-  leveldb::Options options;
-  options.create_if_missing = true;
-  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
-  assert(status.ok());
-  ...
-
-If you want to raise an error if the database already exists, add -the following line before the leveldb::DB::Open call: -
-  options.error_if_exists = true;
-
-

Status

-

-You may have noticed the leveldb::Status type above. Values of this -type are returned by most functions in leveldb that may encounter an -error. You can check if such a result is ok, and also print an -associated error message: -

-

-   leveldb::Status s = ...;
-   if (!s.ok()) cerr << s.ToString() << endl;
-
-

Closing A Database

-

-When you are done with a database, just delete the database object. -Example: -

-

-  ... open the db as described above ...
-  ... do something with db ...
-  delete db;
-
-

Reads And Writes

-

-The database provides Put, Delete, and Get methods to -modify/query the database. For example, the following code -moves the value stored under key1 to key2. -

-  std::string value;
-  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
-  if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
-  if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
-
- -

Atomic Updates

-

-Note that if the process dies after the Put of key2 but before the -delete of key1, the same value may be left stored under multiple keys. -Such problems can be avoided by using the WriteBatch class to -atomically apply a set of updates: -

-

-  #include "leveldb/write_batch.h"
-  ...
-  std::string value;
-  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
-  if (s.ok()) {
-    leveldb::WriteBatch batch;
-    batch.Delete(key1);
-    batch.Put(key2, value);
-    s = db->Write(leveldb::WriteOptions(), &batch);
-  }
-
-The WriteBatch holds a sequence of edits to be made to the database, -and these edits within the batch are applied in order. Note that we -called Delete before Put so that if key1 is identical to key2, -we do not end up erroneously dropping the value entirely. -

-Apart from its atomicity benefits, WriteBatch may also be used to -speed up bulk updates by placing lots of individual mutations into the -same batch. - -

Synchronous Writes

-By default, each write to leveldb is asynchronous: it -returns after pushing the write from the process into the operating -system. The transfer from operating system memory to the underlying -persistent storage happens asynchronously. The sync flag -can be turned on for a particular write to make the write operation -not return until the data being written has been pushed all the way to -persistent storage. (On Posix systems, this is implemented by calling -either fsync(...) or fdatasync(...) or -msync(..., MS_SYNC) before the write operation returns.) -
-  leveldb::WriteOptions write_options;
-  write_options.sync = true;
-  db->Put(write_options, ...);
-
-Asynchronous writes are often more than a thousand times as fast as -synchronous writes. The downside of asynchronous writes is that a -crash of the machine may cause the last few updates to be lost. Note -that a crash of just the writing process (i.e., not a reboot) will not -cause any loss since even when sync is false, an update -is pushed from the process memory into the operating system before it -is considered done. - -

-Asynchronous writes can often be used safely. For example, when -loading a large amount of data into the database you can handle lost -updates by restarting the bulk load after a crash. A hybrid scheme is -also possible where every Nth write is synchronous, and in the event -of a crash, the bulk load is restarted just after the last synchronous -write finished by the previous run. (The synchronous write can update -a marker that describes where to restart on a crash.) - -

-WriteBatch provides an alternative to asynchronous writes. -Multiple updates may be placed in the same WriteBatch and -applied together using a synchronous write (i.e., -write_options.sync is set to true). The extra cost of -the synchronous write will be amortized across all of the writes in -the batch. - -

-

Concurrency

-

-A database may only be opened by one process at a time. -The leveldb implementation acquires a lock from the -operating system to prevent misuse. Within a single process, the -same leveldb::DB object may be safely shared by multiple -concurrent threads. I.e., different threads may write into or fetch -iterators or call Get on the same database without any -external synchronization (the leveldb implementation will -automatically do the required synchronization). However other objects -(like Iterator and WriteBatch) may require external synchronization. -If two threads share such an object, they must protect access to it -using their own locking protocol. More details are available in -the public header files. -

-

Iteration

-

-The following example demonstrates how to print all key,value pairs -in a database. -

-

-  leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
-  for (it->SeekToFirst(); it->Valid(); it->Next()) {
-    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;
-  }
-  assert(it->status().ok());  // Check for any errors found during the scan
-  delete it;
-
-The following variation shows how to process just the keys in the -range [start,limit): -

-

-  for (it->Seek(start);
-       it->Valid() && it->key().ToString() < limit;
-       it->Next()) {
-    ...
-  }
-
-You can also process entries in reverse order. (Caveat: reverse -iteration may be somewhat slower than forward iteration.) -

-

-  for (it->SeekToLast(); it->Valid(); it->Prev()) {
-    ...
-  }
-
-

Snapshots

-

-Snapshots provide consistent read-only views over the entire state of -the key-value store. ReadOptions::snapshot may be non-NULL to indicate -that a read should operate on a particular version of the DB state. -If ReadOptions::snapshot is NULL, the read will operate on an -implicit snapshot of the current state. -

-Snapshots are created by the DB::GetSnapshot() method: -

-

-  leveldb::ReadOptions options;
-  options.snapshot = db->GetSnapshot();
-  ... apply some updates to db ...
-  leveldb::Iterator* iter = db->NewIterator(options);
-  ... read using iter to view the state when the snapshot was created ...
-  delete iter;
-  db->ReleaseSnapshot(options.snapshot);
-
-Note that when a snapshot is no longer needed, it should be released -using the DB::ReleaseSnapshot interface. This allows the -implementation to get rid of state that was being maintained just to -support reading as of that snapshot. -

Slice

-

-The return value of the it->key() and it->value() calls above -are instances of the leveldb::Slice type. Slice is a simple -structure that contains a length and a pointer to an external byte -array. Returning a Slice is a cheaper alternative to returning a -std::string since we do not need to copy potentially large keys and -values. In addition, leveldb methods do not return null-terminated -C-style strings since leveldb keys and values are allowed to -contain '\0' bytes. -

-C++ strings and null-terminated C-style strings can be easily converted -to a Slice: -

-

-   leveldb::Slice s1 = "hello";
-
-   std::string str("world");
-   leveldb::Slice s2 = str;
-
-A Slice can be easily converted back to a C++ string: -
-   std::string str = s1.ToString();
-   assert(str == std::string("hello"));
-
-Be careful when using Slices since it is up to the caller to ensure that -the external byte array into which the Slice points remains live while -the Slice is in use. For example, the following is buggy: -

-

-   leveldb::Slice slice;
-   if (...) {
-     std::string str = ...;
-     slice = str;
-   }
-   Use(slice);
-
-When the if statement goes out of scope, str will be destroyed and the -backing storage for slice will disappear. -

-

Comparators

-

-The preceding examples used the default ordering function for key, -which orders bytes lexicographically. You can however supply a custom -comparator when opening a database. For example, suppose each -database key consists of two numbers and we should sort by the first -number, breaking ties by the second number. First, define a proper -subclass of leveldb::Comparator that expresses these rules: -

-

-  class TwoPartComparator : public leveldb::Comparator {
-   public:
-    // Three-way comparison function:
-    //   if a < b: negative result
-    //   if a > b: positive result
-    //   else: zero result
-    int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
-      int a1, a2, b1, b2;
-      ParseKey(a, &a1, &a2);
-      ParseKey(b, &b1, &b2);
-      if (a1 < b1) return -1;
-      if (a1 > b1) return +1;
-      if (a2 < b2) return -1;
-      if (a2 > b2) return +1;
-      return 0;
-    }
-
-    // Ignore the following methods for now:
-    const char* Name() const { return "TwoPartComparator"; }
-    void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
-    void FindShortSuccessor(std::string*) const { }
-  };
-
-Now create a database using this custom comparator: -

-

-  TwoPartComparator cmp;
-  leveldb::DB* db;
-  leveldb::Options options;
-  options.create_if_missing = true;
-  options.comparator = &cmp;
-  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
-  ...
-
-

Backwards compatibility

-

-The result of the comparator's Name method is attached to the -database when it is created, and is checked on every subsequent -database open. If the name changes, the leveldb::DB::Open call will -fail. Therefore, change the name if and only if the new key format -and comparison function are incompatible with existing databases, and -it is ok to discard the contents of all existing databases. -

-You can however still gradually evolve your key format over time with -a little bit of pre-planning. For example, you could store a version -number at the end of each key (one byte should suffice for most uses). -When you wish to switch to a new key format (e.g., adding an optional -third part to the keys processed by TwoPartComparator), -(a) keep the same comparator name (b) increment the version number -for new keys (c) change the comparator function so it uses the -version numbers found in the keys to decide how to interpret them. -

-

Performance

-

-Performance can be tuned by changing the default values of the -types defined in include/leveldb/options.h. - -

-

Block size

-

-leveldb groups adjacent keys together into the same block and such a -block is the unit of transfer to and from persistent storage. The -default block size is approximately 4096 uncompressed bytes. -Applications that mostly do bulk scans over the contents of the -database may wish to increase this size. Applications that do a lot -of point reads of small values may wish to switch to a smaller block -size if performance measurements indicate an improvement. There isn't -much benefit in using blocks smaller than one kilobyte, or larger than -a few megabytes. Also note that compression will be more effective -with larger block sizes. -

-

Compression

-

-Each block is individually compressed before being written to -persistent storage. Compression is on by default since the default -compression method is very fast, and is automatically disabled for -uncompressible data. In rare cases, applications may want to disable -compression entirely, but should only do so if benchmarks show a -performance improvement: -

-

-  leveldb::Options options;
-  options.compression = leveldb::kNoCompression;
-  ... leveldb::DB::Open(options, name, ...) ....
-
-

Cache

-

-The contents of the database are stored in a set of files in the -filesystem and each file stores a sequence of compressed blocks. If -options.cache is non-NULL, it is used to cache frequently used -uncompressed block contents. -

-

-  #include "leveldb/cache.h"
-
-  leveldb::Options options;
-  options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
-  leveldb::DB* db;
-  leveldb::DB::Open(options, name, &db);
-  ... use the db ...
-  delete db
-  delete options.cache;
-
-Note that the cache holds uncompressed data, and therefore it should -be sized according to application level data sizes, without any -reduction from compression. (Caching of compressed blocks is left to -the operating system buffer cache, or any custom Env -implementation provided by the client.) -

-When performing a bulk read, the application may wish to disable -caching so that the data processed by the bulk read does not end up -displacing most of the cached contents. A per-iterator option can be -used to achieve this: -

-

-  leveldb::ReadOptions options;
-  options.fill_cache = false;
-  leveldb::Iterator* it = db->NewIterator(options);
-  for (it->SeekToFirst(); it->Valid(); it->Next()) {
-    ...
-  }
-
-

Key Layout

-

-Note that the unit of disk transfer and caching is a block. Adjacent -keys (according to the database sort order) will usually be placed in -the same block. Therefore the application can improve its performance -by placing keys that are accessed together near each other and placing -infrequently used keys in a separate region of the key space. -

-For example, suppose we are implementing a simple file system on top -of leveldb. The types of entries we might wish to store are: -

-

-   filename -> permission-bits, length, list of file_block_ids
-   file_block_id -> data
-
-We might want to prefix filename keys with one letter (say '/') and the -file_block_id keys with a different letter (say '0') so that scans -over just the metadata do not force us to fetch and cache bulky file -contents. -

-

Filters

-

-Because of the way leveldb data is organized on disk, -a single Get() call may involve multiple reads from disk. -The optional FilterPolicy mechanism can be used to reduce -the number of disk reads substantially. -

-   leveldb::Options options;
-   options.filter_policy = NewBloomFilterPolicy(10);
-   leveldb::DB* db;
-   leveldb::DB::Open(options, "/tmp/testdb", &db);
-   ... use the database ...
-   delete db;
-   delete options.filter_policy;
-
-The preceding code associates a -Bloom filter -based filtering policy with the database. Bloom filter based -filtering relies on keeping some number of bits of data in memory per -key (in this case 10 bits per key since that is the argument we passed -to NewBloomFilterPolicy). This filter will reduce the number of unnecessary -disk reads needed for Get() calls by a factor of -approximately a 100. Increasing the bits per key will lead to a -larger reduction at the cost of more memory usage. We recommend that -applications whose working set does not fit in memory and that do a -lot of random reads set a filter policy. -

-If you are using a custom comparator, you should ensure that the filter -policy you are using is compatible with your comparator. For example, -consider a comparator that ignores trailing spaces when comparing keys. -NewBloomFilterPolicy must not be used with such a comparator. -Instead, the application should provide a custom filter policy that -also ignores trailing spaces. For example: -

-  class CustomFilterPolicy : public leveldb::FilterPolicy {
-   private:
-    FilterPolicy* builtin_policy_;
-   public:
-    CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) { }
-    ~CustomFilterPolicy() { delete builtin_policy_; }
-
-    const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
-
-    void CreateFilter(const Slice* keys, int n, std::string* dst) const {
-      // Use builtin bloom filter code after removing trailing spaces
-      std::vector<Slice> trimmed(n);
-      for (int i = 0; i < n; i++) {
-        trimmed[i] = RemoveTrailingSpaces(keys[i]);
-      }
-      return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
-    }
-
-    bool KeyMayMatch(const Slice& key, const Slice& filter) const {
-      // Use builtin bloom filter code after removing trailing spaces
-      return builtin_policy_->KeyMayMatch(RemoveTrailingSpaces(key), filter);
-    }
-  };
-
-

-Advanced applications may provide a filter policy that does not use -a bloom filter but uses some other mechanism for summarizing a set -of keys. See leveldb/filter_policy.h for detail. -

-

Checksums

-

-leveldb associates checksums with all data it stores in the file system. -There are two separate controls provided over how aggressively these -checksums are verified: -

-

    -
  • ReadOptions::verify_checksums may be set to true to force - checksum verification of all data that is read from the file system on - behalf of a particular read. By default, no such verification is - done. -

    -

  • Options::paranoid_checks may be set to true before opening a - database to make the database implementation raise an error as soon as - it detects an internal corruption. Depending on which portion of the - database has been corrupted, the error may be raised when the database - is opened, or later by another database operation. By default, - paranoid checking is off so that the database can be used even if - parts of its persistent storage have been corrupted. -

    - If a database is corrupted (perhaps it cannot be opened when - paranoid checking is turned on), the leveldb::RepairDB function - may be used to recover as much of the data as possible -

    -

-

Approximate Sizes

-

-The GetApproximateSizes method can used to get the approximate -number of bytes of file system space used by one or more key ranges. -

-

-   leveldb::Range ranges[2];
-   ranges[0] = leveldb::Range("a", "c");
-   ranges[1] = leveldb::Range("x", "z");
-   uint64_t sizes[2];
-   leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
-
-The preceding call will set sizes[0] to the approximate number of -bytes of file system space used by the key range [a..c) and -sizes[1] to the approximate number of bytes used by the key range -[x..z). -

-

Environment

-

-All file operations (and other operating system calls) issued by the -leveldb implementation are routed through a leveldb::Env object. -Sophisticated clients may wish to provide their own Env -implementation to get better control. For example, an application may -introduce artificial delays in the file IO paths to limit the impact -of leveldb on other activities in the system. -

-

-  class SlowEnv : public leveldb::Env {
-    .. implementation of the Env interface ...
-  };
-
-  SlowEnv env;
-  leveldb::Options options;
-  options.env = &env;
-  Status s = leveldb::DB::Open(options, ...);
-
-

Porting

-

-leveldb may be ported to a new platform by providing platform -specific implementations of the types/methods/functions exported by -leveldb/port/port.h. See leveldb/port/port_example.h for more -details. -

-In addition, the new platform may need a new default leveldb::Env -implementation. See leveldb/util/env_posix.h for an example. - -

Other Information

- -

-Details about the leveldb implementation may be found in -the following documents: -

- - - diff --git a/src/leveldb/doc/index.md b/src/leveldb/doc/index.md new file mode 100644 index 000000000000..be8569692bb0 --- /dev/null +++ b/src/leveldb/doc/index.md @@ -0,0 +1,523 @@ +leveldb +======= + +_Jeff Dean, Sanjay Ghemawat_ + +The leveldb library provides a persistent key value store. Keys and values are +arbitrary byte arrays. The keys are ordered within the key value store +according to a user-specified comparator function. + +## Opening A Database + +A leveldb database has a name which corresponds to a file system directory. All +of the contents of database are stored in this directory. The following example +shows how to open a database, creating it if necessary: + +```c++ +#include +#include "leveldb/db.h" + +leveldb::DB* db; +leveldb::Options options; +options.create_if_missing = true; +leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); +assert(status.ok()); +... +``` + +If you want to raise an error if the database already exists, add the following +line before the `leveldb::DB::Open` call: + +```c++ +options.error_if_exists = true; +``` + +## Status + +You may have noticed the `leveldb::Status` type above. Values of this type are +returned by most functions in leveldb that may encounter an error. You can check +if such a result is ok, and also print an associated error message: + +```c++ +leveldb::Status s = ...; +if (!s.ok()) cerr << s.ToString() << endl; +``` + +## Closing A Database + +When you are done with a database, just delete the database object. Example: + +```c++ +... open the db as described above ... +... do something with db ... +delete db; +``` + +## Reads And Writes + +The database provides Put, Delete, and Get methods to modify/query the database. +For example, the following code moves the value stored under key1 to key2. + +```c++ +std::string value; +leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); +if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value); +if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1); +``` + +## Atomic Updates + +Note that if the process dies after the Put of key2 but before the delete of +key1, the same value may be left stored under multiple keys. Such problems can +be avoided by using the `WriteBatch` class to atomically apply a set of updates: + +```c++ +#include "leveldb/write_batch.h" +... +std::string value; +leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); +if (s.ok()) { + leveldb::WriteBatch batch; + batch.Delete(key1); + batch.Put(key2, value); + s = db->Write(leveldb::WriteOptions(), &batch); +} +``` + +The `WriteBatch` holds a sequence of edits to be made to the database, and these +edits within the batch are applied in order. Note that we called Delete before +Put so that if key1 is identical to key2, we do not end up erroneously dropping +the value entirely. + +Apart from its atomicity benefits, `WriteBatch` may also be used to speed up +bulk updates by placing lots of individual mutations into the same batch. + +## Synchronous Writes + +By default, each write to leveldb is asynchronous: it returns after pushing the +write from the process into the operating system. The transfer from operating +system memory to the underlying persistent storage happens asynchronously. The +sync flag can be turned on for a particular write to make the write operation +not return until the data being written has been pushed all the way to +persistent storage. (On Posix systems, this is implemented by calling either +`fsync(...)` or `fdatasync(...)` or `msync(..., MS_SYNC)` before the write +operation returns.) + +```c++ +leveldb::WriteOptions write_options; +write_options.sync = true; +db->Put(write_options, ...); +``` + +Asynchronous writes are often more than a thousand times as fast as synchronous +writes. The downside of asynchronous writes is that a crash of the machine may +cause the last few updates to be lost. Note that a crash of just the writing +process (i.e., not a reboot) will not cause any loss since even when sync is +false, an update is pushed from the process memory into the operating system +before it is considered done. + +Asynchronous writes can often be used safely. For example, when loading a large +amount of data into the database you can handle lost updates by restarting the +bulk load after a crash. A hybrid scheme is also possible where every Nth write +is synchronous, and in the event of a crash, the bulk load is restarted just +after the last synchronous write finished by the previous run. (The synchronous +write can update a marker that describes where to restart on a crash.) + +`WriteBatch` provides an alternative to asynchronous writes. Multiple updates +may be placed in the same WriteBatch and applied together using a synchronous +write (i.e., `write_options.sync` is set to true). The extra cost of the +synchronous write will be amortized across all of the writes in the batch. + +## Concurrency + +A database may only be opened by one process at a time. The leveldb +implementation acquires a lock from the operating system to prevent misuse. +Within a single process, the same `leveldb::DB` object may be safely shared by +multiple concurrent threads. I.e., different threads may write into or fetch +iterators or call Get on the same database without any external synchronization +(the leveldb implementation will automatically do the required synchronization). +However other objects (like Iterator and `WriteBatch`) may require external +synchronization. If two threads share such an object, they must protect access +to it using their own locking protocol. More details are available in the public +header files. + +## Iteration + +The following example demonstrates how to print all key,value pairs in a +database. + +```c++ +leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); +for (it->SeekToFirst(); it->Valid(); it->Next()) { + cout << it->key().ToString() << ": " << it->value().ToString() << endl; +} +assert(it->status().ok()); // Check for any errors found during the scan +delete it; +``` + +The following variation shows how to process just the keys in the range +[start,limit): + +```c++ +for (it->Seek(start); + it->Valid() && it->key().ToString() < limit; + it->Next()) { + ... +} +``` + +You can also process entries in reverse order. (Caveat: reverse iteration may be +somewhat slower than forward iteration.) + +```c++ +for (it->SeekToLast(); it->Valid(); it->Prev()) { + ... +} +``` + +## Snapshots + +Snapshots provide consistent read-only views over the entire state of the +key-value store. `ReadOptions::snapshot` may be non-NULL to indicate that a +read should operate on a particular version of the DB state. If +`ReadOptions::snapshot` is NULL, the read will operate on an implicit snapshot +of the current state. + +Snapshots are created by the `DB::GetSnapshot()` method: + +```c++ +leveldb::ReadOptions options; +options.snapshot = db->GetSnapshot(); +... apply some updates to db ... +leveldb::Iterator* iter = db->NewIterator(options); +... read using iter to view the state when the snapshot was created ... +delete iter; +db->ReleaseSnapshot(options.snapshot); +``` + +Note that when a snapshot is no longer needed, it should be released using the +`DB::ReleaseSnapshot` interface. This allows the implementation to get rid of +state that was being maintained just to support reading as of that snapshot. + +## Slice + +The return value of the `it->key()` and `it->value()` calls above are instances +of the `leveldb::Slice` type. Slice is a simple structure that contains a length +and a pointer to an external byte array. Returning a Slice is a cheaper +alternative to returning a `std::string` since we do not need to copy +potentially large keys and values. In addition, leveldb methods do not return +null-terminated C-style strings since leveldb keys and values are allowed to +contain `'\0'` bytes. + +C++ strings and null-terminated C-style strings can be easily converted to a +Slice: + +```c++ +leveldb::Slice s1 = "hello"; + +std::string str("world"); +leveldb::Slice s2 = str; +``` + +A Slice can be easily converted back to a C++ string: + +```c++ +std::string str = s1.ToString(); +assert(str == std::string("hello")); +``` + +Be careful when using Slices since it is up to the caller to ensure that the +external byte array into which the Slice points remains live while the Slice is +in use. For example, the following is buggy: + +```c++ +leveldb::Slice slice; +if (...) { + std::string str = ...; + slice = str; +} +Use(slice); +``` + +When the if statement goes out of scope, str will be destroyed and the backing +storage for slice will disappear. + +## Comparators + +The preceding examples used the default ordering function for key, which orders +bytes lexicographically. You can however supply a custom comparator when opening +a database. For example, suppose each database key consists of two numbers and +we should sort by the first number, breaking ties by the second number. First, +define a proper subclass of `leveldb::Comparator` that expresses these rules: + +```c++ +class TwoPartComparator : public leveldb::Comparator { + public: + // Three-way comparison function: + // if a < b: negative result + // if a > b: positive result + // else: zero result + int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const { + int a1, a2, b1, b2; + ParseKey(a, &a1, &a2); + ParseKey(b, &b1, &b2); + if (a1 < b1) return -1; + if (a1 > b1) return +1; + if (a2 < b2) return -1; + if (a2 > b2) return +1; + return 0; + } + + // Ignore the following methods for now: + const char* Name() const { return "TwoPartComparator"; } + void FindShortestSeparator(std::string*, const leveldb::Slice&) const {} + void FindShortSuccessor(std::string*) const {} +}; +``` + +Now create a database using this custom comparator: + +```c++ +TwoPartComparator cmp; +leveldb::DB* db; +leveldb::Options options; +options.create_if_missing = true; +options.comparator = &cmp; +leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); +... +``` + +### Backwards compatibility + +The result of the comparator's Name method is attached to the database when it +is created, and is checked on every subsequent database open. If the name +changes, the `leveldb::DB::Open` call will fail. Therefore, change the name if +and only if the new key format and comparison function are incompatible with +existing databases, and it is ok to discard the contents of all existing +databases. + +You can however still gradually evolve your key format over time with a little +bit of pre-planning. For example, you could store a version number at the end of +each key (one byte should suffice for most uses). When you wish to switch to a +new key format (e.g., adding an optional third part to the keys processed by +`TwoPartComparator`), (a) keep the same comparator name (b) increment the +version number for new keys (c) change the comparator function so it uses the +version numbers found in the keys to decide how to interpret them. + +## Performance + +Performance can be tuned by changing the default values of the types defined in +`include/leveldb/options.h`. + +### Block size + +leveldb groups adjacent keys together into the same block and such a block is +the unit of transfer to and from persistent storage. The default block size is +approximately 4096 uncompressed bytes. Applications that mostly do bulk scans +over the contents of the database may wish to increase this size. Applications +that do a lot of point reads of small values may wish to switch to a smaller +block size if performance measurements indicate an improvement. There isn't much +benefit in using blocks smaller than one kilobyte, or larger than a few +megabytes. Also note that compression will be more effective with larger block +sizes. + +### Compression + +Each block is individually compressed before being written to persistent +storage. Compression is on by default since the default compression method is +very fast, and is automatically disabled for uncompressible data. In rare cases, +applications may want to disable compression entirely, but should only do so if +benchmarks show a performance improvement: + +```c++ +leveldb::Options options; +options.compression = leveldb::kNoCompression; +... leveldb::DB::Open(options, name, ...) .... +``` + +### Cache + +The contents of the database are stored in a set of files in the filesystem and +each file stores a sequence of compressed blocks. If options.cache is non-NULL, +it is used to cache frequently used uncompressed block contents. + +```c++ +#include "leveldb/cache.h" + +leveldb::Options options; +options.cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache +leveldb::DB* db; +leveldb::DB::Open(options, name, &db); +... use the db ... +delete db +delete options.cache; +``` + +Note that the cache holds uncompressed data, and therefore it should be sized +according to application level data sizes, without any reduction from +compression. (Caching of compressed blocks is left to the operating system +buffer cache, or any custom Env implementation provided by the client.) + +When performing a bulk read, the application may wish to disable caching so that +the data processed by the bulk read does not end up displacing most of the +cached contents. A per-iterator option can be used to achieve this: + +```c++ +leveldb::ReadOptions options; +options.fill_cache = false; +leveldb::Iterator* it = db->NewIterator(options); +for (it->SeekToFirst(); it->Valid(); it->Next()) { + ... +} +``` + +### Key Layout + +Note that the unit of disk transfer and caching is a block. Adjacent keys +(according to the database sort order) will usually be placed in the same block. +Therefore the application can improve its performance by placing keys that are +accessed together near each other and placing infrequently used keys in a +separate region of the key space. + +For example, suppose we are implementing a simple file system on top of leveldb. +The types of entries we might wish to store are: + + filename -> permission-bits, length, list of file_block_ids + file_block_id -> data + +We might want to prefix filename keys with one letter (say '/') and the +`file_block_id` keys with a different letter (say '0') so that scans over just +the metadata do not force us to fetch and cache bulky file contents. + +### Filters + +Because of the way leveldb data is organized on disk, a single `Get()` call may +involve multiple reads from disk. The optional FilterPolicy mechanism can be +used to reduce the number of disk reads substantially. + +```c++ +leveldb::Options options; +options.filter_policy = NewBloomFilterPolicy(10); +leveldb::DB* db; +leveldb::DB::Open(options, "/tmp/testdb", &db); +... use the database ... +delete db; +delete options.filter_policy; +``` + +The preceding code associates a Bloom filter based filtering policy with the +database. Bloom filter based filtering relies on keeping some number of bits of +data in memory per key (in this case 10 bits per key since that is the argument +we passed to `NewBloomFilterPolicy`). This filter will reduce the number of +unnecessary disk reads needed for Get() calls by a factor of approximately +a 100. Increasing the bits per key will lead to a larger reduction at the cost +of more memory usage. We recommend that applications whose working set does not +fit in memory and that do a lot of random reads set a filter policy. + +If you are using a custom comparator, you should ensure that the filter policy +you are using is compatible with your comparator. For example, consider a +comparator that ignores trailing spaces when comparing keys. +`NewBloomFilterPolicy` must not be used with such a comparator. Instead, the +application should provide a custom filter policy that also ignores trailing +spaces. For example: + +```c++ +class CustomFilterPolicy : public leveldb::FilterPolicy { + private: + FilterPolicy* builtin_policy_; + + public: + CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {} + ~CustomFilterPolicy() { delete builtin_policy_; } + + const char* Name() const { return "IgnoreTrailingSpacesFilter"; } + + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Use builtin bloom filter code after removing trailing spaces + std::vector trimmed(n); + for (int i = 0; i < n; i++) { + trimmed[i] = RemoveTrailingSpaces(keys[i]); + } + return builtin_policy_->CreateFilter(&trimmed[i], n, dst); + } +}; +``` + +Advanced applications may provide a filter policy that does not use a bloom +filter but uses some other mechanism for summarizing a set of keys. See +`leveldb/filter_policy.h` for detail. + +## Checksums + +leveldb associates checksums with all data it stores in the file system. There +are two separate controls provided over how aggressively these checksums are +verified: + +`ReadOptions::verify_checksums` may be set to true to force checksum +verification of all data that is read from the file system on behalf of a +particular read. By default, no such verification is done. + +`Options::paranoid_checks` may be set to true before opening a database to make +the database implementation raise an error as soon as it detects an internal +corruption. Depending on which portion of the database has been corrupted, the +error may be raised when the database is opened, or later by another database +operation. By default, paranoid checking is off so that the database can be used +even if parts of its persistent storage have been corrupted. + +If a database is corrupted (perhaps it cannot be opened when paranoid checking +is turned on), the `leveldb::RepairDB` function may be used to recover as much +of the data as possible + +## Approximate Sizes + +The `GetApproximateSizes` method can used to get the approximate number of bytes +of file system space used by one or more key ranges. + +```c++ +leveldb::Range ranges[2]; +ranges[0] = leveldb::Range("a", "c"); +ranges[1] = leveldb::Range("x", "z"); +uint64_t sizes[2]; +leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes); +``` + +The preceding call will set `sizes[0]` to the approximate number of bytes of +file system space used by the key range `[a..c)` and `sizes[1]` to the +approximate number of bytes used by the key range `[x..z)`. + +## Environment + +All file operations (and other operating system calls) issued by the leveldb +implementation are routed through a `leveldb::Env` object. Sophisticated clients +may wish to provide their own Env implementation to get better control. +For example, an application may introduce artificial delays in the file IO +paths to limit the impact of leveldb on other activities in the system. + +```c++ +class SlowEnv : public leveldb::Env { + ... implementation of the Env interface ... +}; + +SlowEnv env; +leveldb::Options options; +options.env = &env; +Status s = leveldb::DB::Open(options, ...); +``` + +## Porting + +leveldb may be ported to a new platform by providing platform specific +implementations of the types/methods/functions exported by +`leveldb/port/port.h`. See `leveldb/port/port_example.h` for more details. + +In addition, the new platform may need a new default `leveldb::Env` +implementation. See `leveldb/util/env_posix.h` for an example. + +## Other Information + +Details about the leveldb implementation may be found in the following +documents: + +1. [Implementation notes](impl.md) +2. [Format of an immutable Table file](table_format.md) +3. [Format of a log file](log_format.md) diff --git a/src/leveldb/doc/log_format.md b/src/leveldb/doc/log_format.md new file mode 100644 index 000000000000..f32cb5d7dac4 --- /dev/null +++ b/src/leveldb/doc/log_format.md @@ -0,0 +1,75 @@ +leveldb Log format +================== +The log file contents are a sequence of 32KB blocks. The only exception is that +the tail of the file may contain a partial block. + +Each block consists of a sequence of records: + + block := record* trailer? + record := + checksum: uint32 // crc32c of type and data[] ; little-endian + length: uint16 // little-endian + type: uint8 // One of FULL, FIRST, MIDDLE, LAST + data: uint8[length] + +A record never starts within the last six bytes of a block (since it won't fit). +Any leftover bytes here form the trailer, which must consist entirely of zero +bytes and must be skipped by readers. + +Aside: if exactly seven bytes are left in the current block, and a new non-zero +length record is added, the writer must emit a FIRST record (which contains zero +bytes of user data) to fill up the trailing seven bytes of the block and then +emit all of the user data in subsequent blocks. + +More types may be added in the future. Some Readers may skip record types they +do not understand, others may report that some data was skipped. + + FULL == 1 + FIRST == 2 + MIDDLE == 3 + LAST == 4 + +The FULL record contains the contents of an entire user record. + +FIRST, MIDDLE, LAST are types used for user records that have been split into +multiple fragments (typically because of block boundaries). FIRST is the type +of the first fragment of a user record, LAST is the type of the last fragment of +a user record, and MIDDLE is the type of all interior fragments of a user +record. + +Example: consider a sequence of user records: + + A: length 1000 + B: length 97270 + C: length 8000 + +**A** will be stored as a FULL record in the first block. + +**B** will be split into three fragments: first fragment occupies the rest of +the first block, second fragment occupies the entirety of the second block, and +the third fragment occupies a prefix of the third block. This will leave six +bytes free in the third block, which will be left empty as the trailer. + +**C** will be stored as a FULL record in the fourth block. + +---- + +## Some benefits over the recordio format: + +1. We do not need any heuristics for resyncing - just go to next block boundary + and scan. If there is a corruption, skip to the next block. As a + side-benefit, we do not get confused when part of the contents of one log + file are embedded as a record inside another log file. + +2. Splitting at approximate boundaries (e.g., for mapreduce) is simple: find the + next block boundary and skip records until we hit a FULL or FIRST record. + +3. We do not need extra buffering for large records. + +## Some downsides compared to recordio format: + +1. No packing of tiny records. This could be fixed by adding a new record type, + so it is a shortcoming of the current implementation, not necessarily the + format. + +2. No compression. Again, this could be fixed by adding new record types. diff --git a/src/leveldb/doc/log_format.txt b/src/leveldb/doc/log_format.txt deleted file mode 100644 index 4cca5ef6ead3..000000000000 --- a/src/leveldb/doc/log_format.txt +++ /dev/null @@ -1,75 +0,0 @@ -The log file contents are a sequence of 32KB blocks. The only -exception is that the tail of the file may contain a partial block. - -Each block consists of a sequence of records: - block := record* trailer? - record := - checksum: uint32 // crc32c of type and data[] ; little-endian - length: uint16 // little-endian - type: uint8 // One of FULL, FIRST, MIDDLE, LAST - data: uint8[length] - -A record never starts within the last six bytes of a block (since it -won't fit). Any leftover bytes here form the trailer, which must -consist entirely of zero bytes and must be skipped by readers. - -Aside: if exactly seven bytes are left in the current block, and a new -non-zero length record is added, the writer must emit a FIRST record -(which contains zero bytes of user data) to fill up the trailing seven -bytes of the block and then emit all of the user data in subsequent -blocks. - -More types may be added in the future. Some Readers may skip record -types they do not understand, others may report that some data was -skipped. - -FULL == 1 -FIRST == 2 -MIDDLE == 3 -LAST == 4 - -The FULL record contains the contents of an entire user record. - -FIRST, MIDDLE, LAST are types used for user records that have been -split into multiple fragments (typically because of block boundaries). -FIRST is the type of the first fragment of a user record, LAST is the -type of the last fragment of a user record, and MIDDLE is the type of -all interior fragments of a user record. - -Example: consider a sequence of user records: - A: length 1000 - B: length 97270 - C: length 8000 -A will be stored as a FULL record in the first block. - -B will be split into three fragments: first fragment occupies the rest -of the first block, second fragment occupies the entirety of the -second block, and the third fragment occupies a prefix of the third -block. This will leave six bytes free in the third block, which will -be left empty as the trailer. - -C will be stored as a FULL record in the fourth block. - -=================== - -Some benefits over the recordio format: - -(1) We do not need any heuristics for resyncing - just go to next -block boundary and scan. If there is a corruption, skip to the next -block. As a side-benefit, we do not get confused when part of the -contents of one log file are embedded as a record inside another log -file. - -(2) Splitting at approximate boundaries (e.g., for mapreduce) is -simple: find the next block boundary and skip records until we -hit a FULL or FIRST record. - -(3) We do not need extra buffering for large records. - -Some downsides compared to recordio format: - -(1) No packing of tiny records. This could be fixed by adding a new -record type, so it is a shortcoming of the current implementation, -not necessarily the format. - -(2) No compression. Again, this could be fixed by adding new record types. diff --git a/src/leveldb/doc/table_format.md b/src/leveldb/doc/table_format.md new file mode 100644 index 000000000000..5fe7e72411b8 --- /dev/null +++ b/src/leveldb/doc/table_format.md @@ -0,0 +1,107 @@ +leveldb File format +=================== + + + [data block 1] + [data block 2] + ... + [data block N] + [meta block 1] + ... + [meta block K] + [metaindex block] + [index block] + [Footer] (fixed size; starts at file_size - sizeof(Footer)) + + +The file contains internal pointers. Each such pointer is called +a BlockHandle and contains the following information: + + offset: varint64 + size: varint64 + +See [varints](https://developers.google.com/protocol-buffers/docs/encoding#varints) +for an explanation of varint64 format. + +1. The sequence of key/value pairs in the file are stored in sorted +order and partitioned into a sequence of data blocks. These blocks +come one after another at the beginning of the file. Each data block +is formatted according to the code in `block_builder.cc`, and then +optionally compressed. + +2. After the data blocks we store a bunch of meta blocks. The +supported meta block types are described below. More meta block types +may be added in the future. Each meta block is again formatted using +`block_builder.cc` and then optionally compressed. + +3. A "metaindex" block. It contains one entry for every other meta +block where the key is the name of the meta block and the value is a +BlockHandle pointing to that meta block. + +4. An "index" block. This block contains one entry per data block, +where the key is a string >= last key in that data block and before +the first key in the successive data block. The value is the +BlockHandle for the data block. + +5. At the very end of the file is a fixed length footer that contains +the BlockHandle of the metaindex and index blocks as well as a magic number. + + metaindex_handle: char[p]; // Block handle for metaindex + index_handle: char[q]; // Block handle for index + padding: char[40-p-q];// zeroed bytes to make fixed length + // (40==2*BlockHandle::kMaxEncodedLength) + magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) + +## "filter" Meta Block + +If a `FilterPolicy` was specified when the database was opened, a +filter block is stored in each table. The "metaindex" block contains +an entry that maps from `filter.` to the BlockHandle for the filter +block where `` is the string returned by the filter policy's +`Name()` method. + +The filter block stores a sequence of filters, where filter i contains +the output of `FilterPolicy::CreateFilter()` on all keys that are stored +in a block whose file offset falls within the range + + [ i*base ... (i+1)*base-1 ] + +Currently, "base" is 2KB. So for example, if blocks X and Y start in +the range `[ 0KB .. 2KB-1 ]`, all of the keys in X and Y will be +converted to a filter by calling `FilterPolicy::CreateFilter()`, and the +resulting filter will be stored as the first filter in the filter +block. + +The filter block is formatted as follows: + + [filter 0] + [filter 1] + [filter 2] + ... + [filter N-1] + + [offset of filter 0] : 4 bytes + [offset of filter 1] : 4 bytes + [offset of filter 2] : 4 bytes + ... + [offset of filter N-1] : 4 bytes + + [offset of beginning of offset array] : 4 bytes + lg(base) : 1 byte + +The offset array at the end of the filter block allows efficient +mapping from a data block offset to the corresponding filter. + +## "stats" Meta Block + +This meta block contains a bunch of stats. The key is the name +of the statistic. The value contains the statistic. + +TODO(postrelease): record following stats. + + data size + index size + key size (uncompressed) + value size (uncompressed) + number of entries + number of data blocks diff --git a/src/leveldb/doc/table_format.txt b/src/leveldb/doc/table_format.txt deleted file mode 100644 index ca8f9b4460ad..000000000000 --- a/src/leveldb/doc/table_format.txt +++ /dev/null @@ -1,104 +0,0 @@ -File format -=========== - - - [data block 1] - [data block 2] - ... - [data block N] - [meta block 1] - ... - [meta block K] - [metaindex block] - [index block] - [Footer] (fixed size; starts at file_size - sizeof(Footer)) - - -The file contains internal pointers. Each such pointer is called -a BlockHandle and contains the following information: - offset: varint64 - size: varint64 -See https://developers.google.com/protocol-buffers/docs/encoding#varints -for an explanation of varint64 format. - -(1) The sequence of key/value pairs in the file are stored in sorted -order and partitioned into a sequence of data blocks. These blocks -come one after another at the beginning of the file. Each data block -is formatted according to the code in block_builder.cc, and then -optionally compressed. - -(2) After the data blocks we store a bunch of meta blocks. The -supported meta block types are described below. More meta block types -may be added in the future. Each meta block is again formatted using -block_builder.cc and then optionally compressed. - -(3) A "metaindex" block. It contains one entry for every other meta -block where the key is the name of the meta block and the value is a -BlockHandle pointing to that meta block. - -(4) An "index" block. This block contains one entry per data block, -where the key is a string >= last key in that data block and before -the first key in the successive data block. The value is the -BlockHandle for the data block. - -(6) At the very end of the file is a fixed length footer that contains -the BlockHandle of the metaindex and index blocks as well as a magic number. - metaindex_handle: char[p]; // Block handle for metaindex - index_handle: char[q]; // Block handle for index - padding: char[40-p-q]; // zeroed bytes to make fixed length - // (40==2*BlockHandle::kMaxEncodedLength) - magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) - -"filter" Meta Block -------------------- - -If a "FilterPolicy" was specified when the database was opened, a -filter block is stored in each table. The "metaindex" block contains -an entry that maps from "filter." to the BlockHandle for the filter -block where "" is the string returned by the filter policy's -"Name()" method. - -The filter block stores a sequence of filters, where filter i contains -the output of FilterPolicy::CreateFilter() on all keys that are stored -in a block whose file offset falls within the range - - [ i*base ... (i+1)*base-1 ] - -Currently, "base" is 2KB. So for example, if blocks X and Y start in -the range [ 0KB .. 2KB-1 ], all of the keys in X and Y will be -converted to a filter by calling FilterPolicy::CreateFilter(), and the -resulting filter will be stored as the first filter in the filter -block. - -The filter block is formatted as follows: - - [filter 0] - [filter 1] - [filter 2] - ... - [filter N-1] - - [offset of filter 0] : 4 bytes - [offset of filter 1] : 4 bytes - [offset of filter 2] : 4 bytes - ... - [offset of filter N-1] : 4 bytes - - [offset of beginning of offset array] : 4 bytes - lg(base) : 1 byte - -The offset array at the end of the filter block allows efficient -mapping from a data block offset to the corresponding filter. - -"stats" Meta Block ------------------- - -This meta block contains a bunch of stats. The key is the name -of the statistic. The value contains the statistic. -TODO(postrelease): record following stats. - data size - index size - key size (uncompressed) - value size (uncompressed) - number of entries - number of data blocks diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc index 43ef2e072975..68c0614a59e5 100644 --- a/src/leveldb/helpers/memenv/memenv.cc +++ b/src/leveldb/helpers/memenv/memenv.cc @@ -176,6 +176,7 @@ class SequentialFileImpl : public SequentialFile { return Status::OK(); } + virtual std::string GetName() const { return "[memenv]"; } private: FileState* file_; uint64_t pos_; @@ -196,6 +197,7 @@ class RandomAccessFileImpl : public RandomAccessFile { return file_->Read(offset, n, result, scratch); } + virtual std::string GetName() const { return "[memenv]"; } private: FileState* file_; }; @@ -218,6 +220,7 @@ class WritableFileImpl : public WritableFile { virtual Status Flush() { return Status::OK(); } virtual Status Sync() { return Status::OK(); } + virtual std::string GetName() const { return "[memenv]"; } private: FileState* file_; }; @@ -277,6 +280,19 @@ class InMemoryEnv : public EnvWrapper { return Status::OK(); } + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result) { + MutexLock lock(&mutex_); + FileState** sptr = &file_map_[fname]; + FileState* file = *sptr; + if (file == NULL) { + file = new FileState(); + file->Ref(); + } + *result = new WritableFileImpl(file); + return Status::OK(); + } + virtual bool FileExists(const std::string& fname) { MutexLock lock(&mutex_); return file_map_.find(fname) != file_map_.end(); diff --git a/src/leveldb/helpers/memenv/memenv_test.cc b/src/leveldb/helpers/memenv/memenv_test.cc index a44310fed80c..5cff77613f11 100644 --- a/src/leveldb/helpers/memenv/memenv_test.cc +++ b/src/leveldb/helpers/memenv/memenv_test.cc @@ -40,6 +40,8 @@ TEST(MemEnvTest, Basics) { // Create a file. ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(0, file_size); delete writable_file; // Check that the file exists. @@ -55,9 +57,16 @@ TEST(MemEnvTest, Basics) { ASSERT_OK(writable_file->Append("abc")); delete writable_file; - // Check for expected size. + // Check that append works. + ASSERT_OK(env_->NewAppendableFile("/dir/f", &writable_file)); ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); ASSERT_EQ(3, file_size); + ASSERT_OK(writable_file->Append("hello")); + delete writable_file; + + // Check for expected size. + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(8, file_size); // Check that renaming works. ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); @@ -65,7 +74,7 @@ TEST(MemEnvTest, Basics) { ASSERT_TRUE(!env_->FileExists("/dir/f")); ASSERT_TRUE(env_->FileExists("/dir/g")); ASSERT_OK(env_->GetFileSize("/dir/g", &file_size)); - ASSERT_EQ(3, file_size); + ASSERT_EQ(8, file_size); // Check that opening non-existent file fails. SequentialFile* seq_file; diff --git a/src/leveldb/include/leveldb/cache.h b/src/leveldb/include/leveldb/cache.h index 1a201e5e0a99..6819d5bc49f6 100644 --- a/src/leveldb/include/leveldb/cache.h +++ b/src/leveldb/include/leveldb/cache.h @@ -81,6 +81,17 @@ class Cache { // its cache keys. virtual uint64_t NewId() = 0; + // Remove all cache entries that are not actively in use. Memory-constrained + // applications may wish to call this method to reduce memory usage. + // Default implementation of Prune() does nothing. Subclasses are strongly + // encouraged to override the default implementation. A future release of + // leveldb may change Prune() to a pure abstract method. + virtual void Prune() {} + + // Return an estimate of the combined charges of all elements stored in the + // cache. + virtual size_t TotalCharge() const = 0; + private: void LRU_Remove(Handle* e); void LRU_Append(Handle* e); diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h index 4c169bf22ed9..bfab10a0b725 100644 --- a/src/leveldb/include/leveldb/db.h +++ b/src/leveldb/include/leveldb/db.h @@ -14,7 +14,7 @@ namespace leveldb { // Update Makefile if you change these static const int kMajorVersion = 1; -static const int kMinorVersion = 18; +static const int kMinorVersion = 20; struct Options; struct ReadOptions; @@ -115,6 +115,8 @@ class DB { // about the internal operation of the DB. // "leveldb.sstables" - returns a multi-line string that describes all // of the sstables that make up the db contents. + // "leveldb.approximate-memory-usage" - returns the approximate number of + // bytes of memory in use by the DB. virtual bool GetProperty(const Slice& property, std::string* value) = 0; // For each i in [0,n-1], store in "sizes[i]", the approximate diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h index f709514da6c2..275d441eaeee 100644 --- a/src/leveldb/include/leveldb/env.h +++ b/src/leveldb/include/leveldb/env.h @@ -69,6 +69,21 @@ class Env { virtual Status NewWritableFile(const std::string& fname, WritableFile** result) = 0; + // Create an object that either appends to an existing file, or + // writes to a new file (if the file does not exist to begin with). + // On success, stores a pointer to the new file in *result and + // returns OK. On failure stores NULL in *result and returns + // non-OK. + // + // The returned file will only be accessed by one thread at a time. + // + // May return an IsNotSupportedError error if this Env does + // not allow appending to an existing file. Users of Env (including + // the leveldb implementation) must be prepared to deal with + // an Env that does not support appending. + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); + // Returns true iff the named file exists. virtual bool FileExists(const std::string& fname) = 0; @@ -176,6 +191,9 @@ class SequentialFile { // REQUIRES: External synchronization virtual Status Skip(uint64_t n) = 0; + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + private: // No copying allowed SequentialFile(const SequentialFile&); @@ -200,6 +218,9 @@ class RandomAccessFile { virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const = 0; + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + private: // No copying allowed RandomAccessFile(const RandomAccessFile&); @@ -219,6 +240,9 @@ class WritableFile { virtual Status Flush() = 0; virtual Status Sync() = 0; + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + private: // No copying allowed WritableFile(const WritableFile&); @@ -289,6 +313,9 @@ class EnvWrapper : public Env { Status NewWritableFile(const std::string& f, WritableFile** r) { return target_->NewWritableFile(f, r); } + Status NewAppendableFile(const std::string& f, WritableFile** r) { + return target_->NewAppendableFile(f, r); + } bool FileExists(const std::string& f) { return target_->FileExists(f); } Status GetChildren(const std::string& dir, std::vector* r) { return target_->GetChildren(dir, r); diff --git a/src/leveldb/include/leveldb/iterator.h b/src/leveldb/include/leveldb/iterator.h index 76aced04bddf..da631ed9d89b 100644 --- a/src/leveldb/include/leveldb/iterator.h +++ b/src/leveldb/include/leveldb/iterator.h @@ -37,7 +37,7 @@ class Iterator { // Valid() after this call iff the source is not empty. virtual void SeekToLast() = 0; - // Position at the first key in the source that at or past target + // Position at the first key in the source that is at or past target. // The iterator is Valid() after this call iff the source contains // an entry that comes at or past target. virtual void Seek(const Slice& target) = 0; diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h index 7c9b973454e2..976e38122aaf 100644 --- a/src/leveldb/include/leveldb/options.h +++ b/src/leveldb/include/leveldb/options.h @@ -112,6 +112,18 @@ struct Options { // Default: 16 int block_restart_interval; + // Leveldb will write up to this amount of bytes to a file before + // switching to a new one. + // Most clients should leave this parameter alone. However if your + // filesystem is more efficient with larger files, you could + // consider increasing the value. The downside will be longer + // compactions and hence longer latency/performance hiccups. + // Another reason to increase this parameter might be when you are + // initially populating a large database. + // + // Default: 2MB + size_t max_file_size; + // Compress blocks using the specified compression algorithm. This // parameter can be changed dynamically. // @@ -128,6 +140,12 @@ struct Options { // efficiently detect that and will switch to uncompressed mode. CompressionType compression; + // EXPERIMENTAL: If true, append to existing MANIFEST and log files + // when a database is opened. This can significantly speed up open. + // + // Default: currently false, but may become true later. + bool reuse_logs; + // If non-NULL, use the specified filter policy to reduce disk reads. // Many applications will benefit from passing the result of // NewBloomFilterPolicy() here. diff --git a/src/leveldb/include/leveldb/status.h b/src/leveldb/include/leveldb/status.h index 11dbd4b47ed3..d9575f97532e 100644 --- a/src/leveldb/include/leveldb/status.h +++ b/src/leveldb/include/leveldb/status.h @@ -60,6 +60,12 @@ class Status { // Returns true iff the status indicates an IOError. bool IsIOError() const { return code() == kIOError; } + // Returns true iff the status indicates a NotSupportedError. + bool IsNotSupportedError() const { return code() == kNotSupported; } + + // Returns true iff the status indicates an InvalidArgument. + bool IsInvalidArgument() const { return code() == kInvalidArgument; } + // Return a string representation of this status suitable for printing. // Returns the string "OK" for success. std::string ToString() const; diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h index 9bf091f757c2..d79a02230d57 100644 --- a/src/leveldb/port/atomic_pointer.h +++ b/src/leveldb/port/atomic_pointer.h @@ -35,13 +35,41 @@ #define ARCH_CPU_X86_FAMILY 1 #elif defined(__ARMEL__) #define ARCH_CPU_ARM_FAMILY 1 +#elif defined(__aarch64__) +#define ARCH_CPU_ARM64_FAMILY 1 #elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) #define ARCH_CPU_PPC_FAMILY 1 +#elif defined(__mips__) +#define ARCH_CPU_MIPS_FAMILY 1 #endif namespace leveldb { namespace port { +// AtomicPointer based on if available +#if defined(LEVELDB_ATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +#else + // Define MemoryBarrier() if available // Windows on x86 #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) @@ -92,6 +120,13 @@ inline void MemoryBarrier() { } #define LEVELDB_HAVE_MEMORY_BARRIER +// ARM64 +#elif defined(ARCH_CPU_ARM64_FAMILY) +inline void MemoryBarrier() { + asm volatile("dmb sy" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + // PPC #elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) inline void MemoryBarrier() { @@ -101,6 +136,13 @@ inline void MemoryBarrier() { } #define LEVELDB_HAVE_MEMORY_BARRIER +// MIPS +#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + __asm__ __volatile__("sync" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + #endif // AtomicPointer built using platform-specific MemoryBarrier() @@ -124,28 +166,6 @@ class AtomicPointer { } }; -// AtomicPointer based on -#elif defined(LEVELDB_ATOMIC_PRESENT) -class AtomicPointer { - private: - std::atomic rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - return rep_.load(std::memory_order_acquire); - } - inline void Release_Store(void* v) { - rep_.store(v, std::memory_order_release); - } - inline void* NoBarrier_Load() const { - return rep_.load(std::memory_order_relaxed); - } - inline void NoBarrier_Store(void* v) { - rep_.store(v, std::memory_order_relaxed); - } -}; - // Atomic pointer based on sparc memory barriers #elif defined(__sparcv9) && defined(__GNUC__) class AtomicPointer { @@ -210,11 +230,13 @@ class AtomicPointer { #else #error Please implement AtomicPointer for this platform. +#endif #endif #undef LEVELDB_HAVE_MEMORY_BARRIER #undef ARCH_CPU_X86_FAMILY #undef ARCH_CPU_ARM_FAMILY +#undef ARCH_CPU_ARM64_FAMILY #undef ARCH_CPU_PPC_FAMILY } // namespace port diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h index ab9e489b32d8..5b1d027de556 100644 --- a/src/leveldb/port/port_example.h +++ b/src/leveldb/port/port_example.h @@ -129,6 +129,16 @@ extern bool Snappy_Uncompress(const char* input_data, size_t input_length, // The concatenation of all "data[0,n-1]" fragments is the heap profile. extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); +// Determine whether a working accelerated crc32 implementation exists +// Returns true if AcceleratedCRC32C is safe to call +bool HasAcceleratedCRC32C(); + +// Extend the CRC to include the first n bytes of buf. +// +// Returns zero if the CRC cannot be extended using acceleration, else returns +// the newly extended CRC value (which may also be zero). +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + } // namespace port } // namespace leveldb diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc index 5ba127a5b91b..ec39e921957f 100644 --- a/src/leveldb/port/port_posix.cc +++ b/src/leveldb/port/port_posix.cc @@ -7,7 +7,10 @@ #include #include #include -#include "util/logging.h" + +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) +#include +#endif namespace leveldb { namespace port { @@ -50,5 +53,15 @@ void InitOnce(OnceType* once, void (*initializer)()) { PthreadCall("once", pthread_once(once, initializer)); } +bool HasAcceleratedCRC32C() { +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) + unsigned int eax, ebx, ecx, edx; + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + return (ecx & (1 << 20)) != 0; +#else + return false; +#endif +} + } // namespace port } // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index ccca9939d3dc..d85fa5d63fe0 100644 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -152,6 +152,9 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } +bool HasAcceleratedCRC32C(); +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + } // namespace port } // namespace leveldb diff --git a/src/leveldb/port/port_posix_sse.cc b/src/leveldb/port/port_posix_sse.cc new file mode 100644 index 000000000000..2d49c21dd8b0 --- /dev/null +++ b/src/leveldb/port/port_posix_sse.cc @@ -0,0 +1,110 @@ +// Copyright 2016 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. +// +// In a separate source file to allow this accelerated CRC32C function to be +// compiled with the appropriate compiler flags to enable x86 SSE 4.2 +// instructions. + +#include +#include +#include "port/port.h" + +#if defined(LEVELDB_PLATFORM_POSIX_SSE) + +#if defined(_MSC_VER) +#include +#elif defined(__GNUC__) && defined(__SSE4_2__) +#include +#endif + +#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) + +namespace leveldb { +namespace port { + +#if defined(LEVELDB_PLATFORM_POSIX_SSE) + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + // SSE is x86 only, so ensured that |p| is always little-endian. + uint32_t word; + memcpy(&word, p, sizeof(word)); + return word; +} + +#if defined(_M_X64) || defined(__x86_64__) // LE_LOAD64 is only used on x64. + +// Used to fetch a naturally-aligned 64-bit word in little endian byte-order +static inline uint64_t LE_LOAD64(const uint8_t *p) { + uint64_t dword; + memcpy(&dword, p, sizeof(dword)); + return dword; +} + +#endif // defined(_M_X64) || defined(__x86_64__) + +#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) + +// For further improvements see Intel publication at: +// http://download.intel.com/design/intarch/papers/323405.pdf +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { +#if !defined(LEVELDB_PLATFORM_POSIX_SSE) + return 0; +#else + + const uint8_t *p = reinterpret_cast(buf); + const uint8_t *e = p + size; + uint32_t l = crc ^ 0xffffffffu; + +#define STEP1 do { \ + l = _mm_crc32_u8(l, *p++); \ +} while (0) +#define STEP4 do { \ + l = _mm_crc32_u32(l, LE_LOAD32(p)); \ + p += 4; \ +} while (0) +#define STEP8 do { \ + l = _mm_crc32_u64(l, LE_LOAD64(p)); \ + p += 8; \ +} while (0) + + if (size > 16) { + // Process unaligned bytes + for (unsigned int i = reinterpret_cast(p) % 8; i; --i) { + STEP1; + } + + // _mm_crc32_u64 is only available on x64. +#if defined(_M_X64) || defined(__x86_64__) + // Process 8 bytes at a time + while ((e-p) >= 8) { + STEP8; + } + // Process 4 bytes at a time + if ((e-p) >= 4) { + STEP4; + } +#else // !(defined(_M_X64) || defined(__x86_64__)) + // Process 4 bytes at a time + while ((e-p) >= 4) { + STEP4; + } +#endif // defined(_M_X64) || defined(__x86_64__) + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP8 +#undef STEP4 +#undef STEP1 + return l ^ 0xffffffffu; +#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) +} + +} // namespace port +} // namespace leveldb diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc index 1b0f060a19ca..1be9e8d5b0b4 100644 --- a/src/leveldb/port/port_win.cc +++ b/src/leveldb/port/port_win.cc @@ -32,6 +32,7 @@ #include #include +#include namespace leveldb { namespace port { @@ -143,5 +144,15 @@ void AtomicPointer::NoBarrier_Store(void* v) { rep_ = v; } +bool HasAcceleratedCRC32C() { +#if defined(__x86_64__) || defined(__i386__) + int cpu_info[4]; + __cpuid(cpu_info, 1); + return (cpu_info[2] & (1 << 20)) != 0; +#else + return false; +#endif +} + } } diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h index 45bf2f0ea749..e8bf46ef27cd 100644 --- a/src/leveldb/port/port_win.h +++ b/src/leveldb/port/port_win.h @@ -168,6 +168,9 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } +bool HasAcceleratedCRC32C(); +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + } } diff --git a/src/leveldb/table/filter_block.cc b/src/leveldb/table/filter_block.cc index 203e15c8bcb1..1ed5134170e5 100644 --- a/src/leveldb/table/filter_block.cc +++ b/src/leveldb/table/filter_block.cc @@ -9,7 +9,7 @@ namespace leveldb { -// See doc/table_format.txt for an explanation of the filter block format. +// See doc/table_format.md for an explanation of the filter block format. // Generate new filter every 2KB of data static const size_t kFilterBaseLg = 11; @@ -68,7 +68,7 @@ void FilterBlockBuilder::GenerateFilter() { // Generate filter for current set of keys and append to result_. filter_offsets_.push_back(result_.size()); - policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_); + policy_->CreateFilter(&tmp_keys_[0], static_cast(num_keys), &result_); tmp_keys_.clear(); keys_.clear(); @@ -97,7 +97,7 @@ bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { if (index < num_) { uint32_t start = DecodeFixed32(offset_ + index*4); uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); - if (start <= limit && limit <= (offset_ - data_)) { + if (start <= limit && limit <= static_cast(offset_ - data_)) { Slice filter = Slice(data_ + start, limit - start); return policy_->KeyMayMatch(key, filter); } else if (start == limit) { diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc index aa63144c9e7a..285e1c0de39d 100644 --- a/src/leveldb/table/format.cc +++ b/src/leveldb/table/format.cc @@ -30,15 +30,14 @@ Status BlockHandle::DecodeFrom(Slice* input) { } void Footer::EncodeTo(std::string* dst) const { -#ifndef NDEBUG const size_t original_size = dst->size(); -#endif metaindex_handle_.EncodeTo(dst); index_handle_.EncodeTo(dst); dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); assert(dst->size() == original_size + kEncodedLength); + (void)original_size; // Disable unused variable warning. } Status Footer::DecodeFrom(Slice* input) { @@ -83,7 +82,7 @@ Status ReadBlock(RandomAccessFile* file, } if (contents.size() != n + kBlockTrailerSize) { delete[] buf; - return Status::Corruption("truncated block read"); + return Status::Corruption("truncated block read", file->GetName()); } // Check the crc of the type and the block contents @@ -93,7 +92,7 @@ Status ReadBlock(RandomAccessFile* file, const uint32_t actual = crc32c::Value(data, n + 1); if (actual != crc) { delete[] buf; - s = Status::Corruption("block checksum mismatch"); + s = Status::Corruption("block checksum mismatch", file->GetName()); return s; } } @@ -120,13 +119,13 @@ Status ReadBlock(RandomAccessFile* file, size_t ulength = 0; if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { delete[] buf; - return Status::Corruption("corrupted compressed block contents"); + return Status::Corruption("corrupted compressed block contents", file->GetName()); } char* ubuf = new char[ulength]; if (!port::Snappy_Uncompress(data, n, ubuf)) { delete[] buf; delete[] ubuf; - return Status::Corruption("corrupted compressed block contents"); + return Status::Corruption("corrupted compressed block contents", file->GetName()); } delete[] buf; result->data = Slice(ubuf, ulength); @@ -136,7 +135,7 @@ Status ReadBlock(RandomAccessFile* file, } default: delete[] buf; - return Status::Corruption("bad block type"); + return Status::Corruption("bad block type", file->GetName()); } return Status::OK(); diff --git a/src/leveldb/table/iterator_wrapper.h b/src/leveldb/table/iterator_wrapper.h index 9e16b3dbedeb..f410c3fabe61 100644 --- a/src/leveldb/table/iterator_wrapper.h +++ b/src/leveldb/table/iterator_wrapper.h @@ -5,6 +5,9 @@ #ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ #define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ +#include "leveldb/iterator.h" +#include "leveldb/slice.h" + namespace leveldb { // A internal wrapper class with an interface similar to Iterator that diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc index dff8a82590a6..decf8082cc18 100644 --- a/src/leveldb/table/table.cc +++ b/src/leveldb/table/table.cc @@ -82,7 +82,7 @@ Status Table::Open(const Options& options, *table = new Table(rep); (*table)->ReadMeta(footer); } else { - if (index_block) delete index_block; + delete index_block; } return s; diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc index c723bf84cf5f..abf6e246ff8e 100644 --- a/src/leveldb/table/table_test.cc +++ b/src/leveldb/table/table_test.cc @@ -853,12 +853,20 @@ TEST(TableTest, ApproximateOffsetOfCompressed) { options.compression = kSnappyCompression; c.Finish(options, &keys, &kvmap); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000)); + // Expected upper and lower bounds of space used by compressible strings. + static const int kSlop = 1000; // Compressor effectiveness varies. + const int expected = 2500; // 10000 * compression ratio (0.25) + const int min_z = expected - kSlop; + const int max_z = expected + kSlop; + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, kSlop)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, kSlop)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, kSlop)); + // Have now emitted a large compressible string, so adjust expected offset. + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), min_z, max_z)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), min_z, max_z)); + // Have now emitted two large compressible strings, so adjust expected offset. + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 2 * min_z, 2 * max_z)); } } // namespace leveldb diff --git a/src/leveldb/util/arena.cc b/src/leveldb/util/arena.cc index 9367f714924d..74078213eeda 100644 --- a/src/leveldb/util/arena.cc +++ b/src/leveldb/util/arena.cc @@ -9,8 +9,7 @@ namespace leveldb { static const int kBlockSize = 4096; -Arena::Arena() { - blocks_memory_ = 0; +Arena::Arena() : memory_usage_(0) { alloc_ptr_ = NULL; // First allocation will allocate a block alloc_bytes_remaining_ = 0; } @@ -60,8 +59,9 @@ char* Arena::AllocateAligned(size_t bytes) { char* Arena::AllocateNewBlock(size_t block_bytes) { char* result = new char[block_bytes]; - blocks_memory_ += block_bytes; blocks_.push_back(result); + memory_usage_.NoBarrier_Store( + reinterpret_cast(MemoryUsage() + block_bytes + sizeof(char*))); return result; } diff --git a/src/leveldb/util/arena.h b/src/leveldb/util/arena.h index 73bbf1cb9bfb..48bab3374159 100644 --- a/src/leveldb/util/arena.h +++ b/src/leveldb/util/arena.h @@ -9,6 +9,7 @@ #include #include #include +#include "port/port.h" namespace leveldb { @@ -24,10 +25,9 @@ class Arena { char* AllocateAligned(size_t bytes); // Returns an estimate of the total memory usage of data allocated - // by the arena (including space allocated but not yet used for user - // allocations). + // by the arena. size_t MemoryUsage() const { - return blocks_memory_ + blocks_.capacity() * sizeof(char*); + return reinterpret_cast(memory_usage_.NoBarrier_Load()); } private: @@ -41,8 +41,8 @@ class Arena { // Array of new[] allocated memory blocks std::vector blocks_; - // Bytes of memory in blocks allocated so far - size_t blocks_memory_; + // Total memory usage of the arena. + port::AtomicPointer memory_usage_; // No copying allowed Arena(const Arena&); diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc index 79276b847694..bf3e4ca6e931 100644 --- a/src/leveldb/util/bloom.cc +++ b/src/leveldb/util/bloom.cc @@ -47,7 +47,7 @@ class BloomFilterPolicy : public FilterPolicy { dst->resize(init_size + bytes, 0); dst->push_back(static_cast(k_)); // Remember # of probes in filter char* array = &(*dst)[init_size]; - for (size_t i = 0; i < (size_t)n; i++) { + for (int i = 0; i < n; i++) { // Use double-hashing to generate a sequence of hash values. // See analysis in [Kirsch,Mitzenmacher 2006]. uint32_t h = BloomHash(keys[i]); diff --git a/src/leveldb/util/bloom_test.cc b/src/leveldb/util/bloom_test.cc index 77fb1b315958..1b87a2be3f54 100644 --- a/src/leveldb/util/bloom_test.cc +++ b/src/leveldb/util/bloom_test.cc @@ -46,7 +46,8 @@ class BloomTest { key_slices.push_back(Slice(keys_[i])); } filter_.clear(); - policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_); + policy_->CreateFilter(&key_slices[0], static_cast(key_slices.size()), + &filter_); keys_.clear(); if (kVerbose >= 2) DumpFilter(); } diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc index 8b197bc02a98..ce46886171ad 100644 --- a/src/leveldb/util/cache.cc +++ b/src/leveldb/util/cache.cc @@ -19,6 +19,23 @@ Cache::~Cache() { namespace { // LRU cache implementation +// +// Cache entries have an "in_cache" boolean indicating whether the cache has a +// reference on the entry. The only ways that this can become false without the +// entry being passed to its "deleter" are via Erase(), via Insert() when +// an element with a duplicate key is inserted, or on destruction of the cache. +// +// The cache keeps two linked lists of items in the cache. All items in the +// cache are in one list or the other, and never both. Items still referenced +// by clients but erased from the cache are in neither list. The lists are: +// - in-use: contains the items currently referenced by clients, in no +// particular order. (This list is used for invariant checking. If we +// removed the check, elements that would otherwise be on this list could be +// left as disconnected singleton lists.) +// - LRU: contains the items not currently referenced by clients, in LRU order +// Elements are moved between these lists by the Ref() and Unref() methods, +// when they detect an element in the cache acquiring or losing its only +// external reference. // An entry is a variable length heap-allocated structure. Entries // are kept in a circular doubly linked list ordered by access time. @@ -30,7 +47,8 @@ struct LRUHandle { LRUHandle* prev; size_t charge; // TODO(opt): Only allow uint32_t? size_t key_length; - uint32_t refs; + bool in_cache; // Whether entry is in the cache. + uint32_t refs; // References, including cache reference, if present. uint32_t hash; // Hash of key(); used for fast sharding and comparisons char key_data[1]; // Beginning of key @@ -147,49 +165,77 @@ class LRUCache { Cache::Handle* Lookup(const Slice& key, uint32_t hash); void Release(Cache::Handle* handle); void Erase(const Slice& key, uint32_t hash); + void Prune(); + size_t TotalCharge() const { + MutexLock l(&mutex_); + return usage_; + } private: void LRU_Remove(LRUHandle* e); - void LRU_Append(LRUHandle* e); + void LRU_Append(LRUHandle*list, LRUHandle* e); + void Ref(LRUHandle* e); void Unref(LRUHandle* e); + bool FinishErase(LRUHandle* e); // Initialized before use. size_t capacity_; // mutex_ protects the following state. - port::Mutex mutex_; + mutable port::Mutex mutex_; size_t usage_; // Dummy head of LRU list. // lru.prev is newest entry, lru.next is oldest entry. + // Entries have refs==1 and in_cache==true. LRUHandle lru_; + // Dummy head of in-use list. + // Entries are in use by clients, and have refs >= 2 and in_cache==true. + LRUHandle in_use_; + HandleTable table_; }; LRUCache::LRUCache() : usage_(0) { - // Make empty circular linked list + // Make empty circular linked lists. lru_.next = &lru_; lru_.prev = &lru_; + in_use_.next = &in_use_; + in_use_.prev = &in_use_; } LRUCache::~LRUCache() { + assert(in_use_.next == &in_use_); // Error if caller has an unreleased handle for (LRUHandle* e = lru_.next; e != &lru_; ) { LRUHandle* next = e->next; - assert(e->refs == 1); // Error if caller has an unreleased handle + assert(e->in_cache); + e->in_cache = false; + assert(e->refs == 1); // Invariant of lru_ list. Unref(e); e = next; } } +void LRUCache::Ref(LRUHandle* e) { + if (e->refs == 1 && e->in_cache) { // If on lru_ list, move to in_use_ list. + LRU_Remove(e); + LRU_Append(&in_use_, e); + } + e->refs++; +} + void LRUCache::Unref(LRUHandle* e) { assert(e->refs > 0); e->refs--; - if (e->refs <= 0) { - usage_ -= e->charge; + if (e->refs == 0) { // Deallocate. + assert(!e->in_cache); (*e->deleter)(e->key(), e->value); free(e); + } else if (e->in_cache && e->refs == 1) { // No longer in use; move to lru_ list. + LRU_Remove(e); + LRU_Append(&lru_, e); } } @@ -198,10 +244,10 @@ void LRUCache::LRU_Remove(LRUHandle* e) { e->prev->next = e->next; } -void LRUCache::LRU_Append(LRUHandle* e) { - // Make "e" newest entry by inserting just before lru_ - e->next = &lru_; - e->prev = lru_.prev; +void LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) { + // Make "e" newest entry by inserting just before *list + e->next = list; + e->prev = list->prev; e->prev->next = e; e->next->prev = e; } @@ -210,9 +256,7 @@ Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { MutexLock l(&mutex_); LRUHandle* e = table_.Lookup(key, hash); if (e != NULL) { - e->refs++; - LRU_Remove(e); - LRU_Append(e); + Ref(e); } return reinterpret_cast(e); } @@ -234,34 +278,58 @@ Cache::Handle* LRUCache::Insert( e->charge = charge; e->key_length = key.size(); e->hash = hash; - e->refs = 2; // One from LRUCache, one for the returned handle + e->in_cache = false; + e->refs = 1; // for the returned handle. memcpy(e->key_data, key.data(), key.size()); - LRU_Append(e); - usage_ += charge; - LRUHandle* old = table_.Insert(e); - if (old != NULL) { - LRU_Remove(old); - Unref(old); - } + if (capacity_ > 0) { + e->refs++; // for the cache's reference. + e->in_cache = true; + LRU_Append(&in_use_, e); + usage_ += charge; + FinishErase(table_.Insert(e)); + } // else don't cache. (Tests use capacity_==0 to turn off caching.) while (usage_ > capacity_ && lru_.next != &lru_) { LRUHandle* old = lru_.next; - LRU_Remove(old); - table_.Remove(old->key(), old->hash); - Unref(old); + assert(old->refs == 1); + bool erased = FinishErase(table_.Remove(old->key(), old->hash)); + if (!erased) { // to avoid unused variable when compiled NDEBUG + assert(erased); + } } return reinterpret_cast(e); } -void LRUCache::Erase(const Slice& key, uint32_t hash) { - MutexLock l(&mutex_); - LRUHandle* e = table_.Remove(key, hash); +// If e != NULL, finish removing *e from the cache; it has already been removed +// from the hash table. Return whether e != NULL. Requires mutex_ held. +bool LRUCache::FinishErase(LRUHandle* e) { if (e != NULL) { + assert(e->in_cache); LRU_Remove(e); + e->in_cache = false; + usage_ -= e->charge; Unref(e); } + return e != NULL; +} + +void LRUCache::Erase(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + FinishErase(table_.Remove(key, hash)); +} + +void LRUCache::Prune() { + MutexLock l(&mutex_); + while (lru_.next != &lru_) { + LRUHandle* e = lru_.next; + assert(e->refs == 1); + bool erased = FinishErase(table_.Remove(e->key(), e->hash)); + if (!erased) { // to avoid unused variable when compiled NDEBUG + assert(erased); + } + } } static const int kNumShardBits = 4; @@ -314,6 +382,18 @@ class ShardedLRUCache : public Cache { MutexLock l(&id_mutex_); return ++(last_id_); } + virtual void Prune() { + for (int s = 0; s < kNumShards; s++) { + shard_[s].Prune(); + } + } + virtual size_t TotalCharge() const { + size_t total = 0; + for (int s = 0; s < kNumShards; s++) { + total += shard_[s].TotalCharge(); + } + return total; + } }; } // end anonymous namespace diff --git a/src/leveldb/util/cache_test.cc b/src/leveldb/util/cache_test.cc index 43716715a89f..468f7a6425bf 100644 --- a/src/leveldb/util/cache_test.cc +++ b/src/leveldb/util/cache_test.cc @@ -59,6 +59,11 @@ class CacheTest { &CacheTest::Deleter)); } + Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) { + return cache_->Insert(EncodeKey(key), EncodeValue(value), charge, + &CacheTest::Deleter); + } + void Erase(int key) { cache_->Erase(EncodeKey(key)); } @@ -135,8 +140,11 @@ TEST(CacheTest, EntriesArePinned) { TEST(CacheTest, EvictionPolicy) { Insert(100, 101); Insert(200, 201); + Insert(300, 301); + Cache::Handle* h = cache_->Lookup(EncodeKey(300)); - // Frequently used entry must be kept around + // Frequently used entry must be kept around, + // as must things that are still in use. for (int i = 0; i < kCacheSize + 100; i++) { Insert(1000+i, 2000+i); ASSERT_EQ(2000+i, Lookup(1000+i)); @@ -144,6 +152,25 @@ TEST(CacheTest, EvictionPolicy) { } ASSERT_EQ(101, Lookup(100)); ASSERT_EQ(-1, Lookup(200)); + ASSERT_EQ(301, Lookup(300)); + cache_->Release(h); +} + +TEST(CacheTest, UseExceedsCacheSize) { + // Overfill the cache, keeping handles on all inserted entries. + std::vector h; + for (int i = 0; i < kCacheSize + 100; i++) { + h.push_back(InsertAndReturnHandle(1000+i, 2000+i)); + } + + // Check that all the entries can be found in the cache. + for (int i = 0; i < h.size(); i++) { + ASSERT_EQ(2000+i, Lookup(1000+i)); + } + + for (int i = 0; i < h.size(); i++) { + cache_->Release(h[i]); + } } TEST(CacheTest, HeavyEntries) { @@ -179,6 +206,19 @@ TEST(CacheTest, NewId) { ASSERT_NE(a, b); } +TEST(CacheTest, Prune) { + Insert(1, 100); + Insert(2, 200); + + Cache::Handle* handle = cache_->Lookup(EncodeKey(1)); + ASSERT_TRUE(handle); + cache_->Prune(); + cache_->Release(handle); + + ASSERT_EQ(100, Lookup(1)); + ASSERT_EQ(-1, Lookup(2)); +} + } // namespace leveldb int main(int argc, char** argv) { diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc index 6db9e770774d..b3f40eeeed45 100644 --- a/src/leveldb/util/crc32c.cc +++ b/src/leveldb/util/crc32c.cc @@ -8,6 +8,8 @@ #include "util/crc32c.h" #include + +#include "port/port.h" #include "util/coding.h" namespace leveldb { @@ -283,7 +285,27 @@ static inline uint32_t LE_LOAD32(const uint8_t *p) { return DecodeFixed32(reinterpret_cast(p)); } +// Determine if the CPU running this program can accelerate the CRC32C +// calculation. +static bool CanAccelerateCRC32C() { + if (!port::HasAcceleratedCRC32C()) + return false; + + // Double-check that the accelerated implementation functions correctly. + // port::AcceleretedCRC32C returns zero when unable to accelerate. + static const char kTestCRCBuffer[] = "TestCRCBuffer"; + static const char kBufSize = sizeof(kTestCRCBuffer) - 1; + static const uint32_t kTestCRCValue = 0xdcbc59fa; + + return port::AcceleratedCRC32C(0, kTestCRCBuffer, kBufSize) == kTestCRCValue; +} + uint32_t Extend(uint32_t crc, const char* buf, size_t size) { + static bool accelerate = CanAccelerateCRC32C(); + if (accelerate) { + return port::AcceleratedCRC32C(crc, buf, size); + } + const uint8_t *p = reinterpret_cast(buf); const uint8_t *e = p + size; uint32_t l = crc ^ 0xffffffffu; diff --git a/src/leveldb/util/env.cc b/src/leveldb/util/env.cc index c2600e964a26..c58a0821ef7a 100644 --- a/src/leveldb/util/env.cc +++ b/src/leveldb/util/env.cc @@ -9,6 +9,10 @@ namespace leveldb { Env::~Env() { } +Status Env::NewAppendableFile(const std::string& fname, WritableFile** result) { + return Status::NotSupported("NewAppendableFile", fname); +} + SequentialFile::~SequentialFile() { } diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc index ba2667864acb..4676bc2240c9 100644 --- a/src/leveldb/util/env_posix.cc +++ b/src/leveldb/util/env_posix.cc @@ -11,12 +11,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include "leveldb/env.h" #include "leveldb/slice.h" @@ -24,15 +26,70 @@ #include "util/logging.h" #include "util/mutexlock.h" #include "util/posix_logger.h" +#include "util/env_posix_test_helper.h" namespace leveldb { namespace { +static int open_read_only_file_limit = -1; +static int mmap_limit = -1; + static Status IOError(const std::string& context, int err_number) { return Status::IOError(context, strerror(err_number)); } +// Helper class to limit resource usage to avoid exhaustion. +// Currently used to limit read-only file descriptors and mmap file usage +// so that we do not end up running out of file descriptors, virtual memory, +// or running into kernel performance problems for very large databases. +class Limiter { + public: + // Limit maximum number of resources to |n|. + Limiter(intptr_t n) { + SetAllowed(n); + } + + // If another resource is available, acquire it and return true. + // Else return false. + bool Acquire() { + if (GetAllowed() <= 0) { + return false; + } + MutexLock l(&mu_); + intptr_t x = GetAllowed(); + if (x <= 0) { + return false; + } else { + SetAllowed(x - 1); + return true; + } + } + + // Release a resource acquired by a previous call to Acquire() that returned + // true. + void Release() { + MutexLock l(&mu_); + SetAllowed(GetAllowed() + 1); + } + + private: + port::Mutex mu_; + port::AtomicPointer allowed_; + + intptr_t GetAllowed() const { + return reinterpret_cast(allowed_.Acquire_Load()); + } + + // REQUIRES: mu_ must be held + void SetAllowed(intptr_t v) { + allowed_.Release_Store(reinterpret_cast(v)); + } + + Limiter(const Limiter&); + void operator=(const Limiter&); +}; + class PosixSequentialFile: public SequentialFile { private: std::string filename_; @@ -64,79 +121,61 @@ class PosixSequentialFile: public SequentialFile { } return Status::OK(); } + + virtual std::string GetName() const { return filename_; } }; // pread() based random-access class PosixRandomAccessFile: public RandomAccessFile { private: std::string filename_; + bool temporary_fd_; // If true, fd_ is -1 and we open on every read. int fd_; + Limiter* limiter_; public: - PosixRandomAccessFile(const std::string& fname, int fd) - : filename_(fname), fd_(fd) { } - virtual ~PosixRandomAccessFile() { close(fd_); } + PosixRandomAccessFile(const std::string& fname, int fd, Limiter* limiter) + : filename_(fname), fd_(fd), limiter_(limiter) { + temporary_fd_ = !limiter->Acquire(); + if (temporary_fd_) { + // Open file on every access. + close(fd_); + fd_ = -1; + } + } + + virtual ~PosixRandomAccessFile() { + if (!temporary_fd_) { + close(fd_); + limiter_->Release(); + } + } virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { + int fd = fd_; + if (temporary_fd_) { + fd = open(filename_.c_str(), O_RDONLY); + if (fd < 0) { + return IOError(filename_, errno); + } + } + Status s; - ssize_t r = pread(fd_, scratch, n, static_cast(offset)); + ssize_t r = pread(fd, scratch, n, static_cast(offset)); *result = Slice(scratch, (r < 0) ? 0 : r); if (r < 0) { // An error: return a non-ok status s = IOError(filename_, errno); } - return s; - } -}; - -// Helper class to limit mmap file usage so that we do not end up -// running out virtual memory or running into kernel performance -// problems for very large databases. -class MmapLimiter { - public: - // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. - MmapLimiter() { - SetAllowed(sizeof(void*) >= 8 ? 1000 : 0); - } - - // If another mmap slot is available, acquire it and return true. - // Else return false. - bool Acquire() { - if (GetAllowed() <= 0) { - return false; - } - MutexLock l(&mu_); - intptr_t x = GetAllowed(); - if (x <= 0) { - return false; - } else { - SetAllowed(x - 1); - return true; + if (temporary_fd_) { + // Close the temporary file descriptor opened earlier. + close(fd); } + return s; } - // Release a slot acquired by a previous call to Acquire() that returned true. - void Release() { - MutexLock l(&mu_); - SetAllowed(GetAllowed() + 1); - } - - private: - port::Mutex mu_; - port::AtomicPointer allowed_; - - intptr_t GetAllowed() const { - return reinterpret_cast(allowed_.Acquire_Load()); - } - - // REQUIRES: mu_ must be held - void SetAllowed(intptr_t v) { - allowed_.Release_Store(reinterpret_cast(v)); - } - - MmapLimiter(const MmapLimiter&); - void operator=(const MmapLimiter&); + virtual std::string GetName() const { return filename_; } }; // mmap() based random-access @@ -145,12 +184,12 @@ class PosixMmapReadableFile: public RandomAccessFile { std::string filename_; void* mmapped_region_; size_t length_; - MmapLimiter* limiter_; + Limiter* limiter_; public: // base[0,length-1] contains the mmapped contents of the file. PosixMmapReadableFile(const std::string& fname, void* base, size_t length, - MmapLimiter* limiter) + Limiter* limiter) : filename_(fname), mmapped_region_(base), length_(length), limiter_(limiter) { } @@ -171,6 +210,8 @@ class PosixMmapReadableFile: public RandomAccessFile { } return s; } + + virtual std::string GetName() const { return filename_; } }; class PosixWritableFile : public WritableFile { @@ -231,7 +272,7 @@ class PosixWritableFile : public WritableFile { if (fd < 0) { s = IOError(dir, errno); } else { - if (fsync(fd) < 0) { + if (fsync(fd) < 0 && errno != EINVAL) { s = IOError(dir, errno); } close(fd); @@ -252,6 +293,8 @@ class PosixWritableFile : public WritableFile { } return s; } + + virtual std::string GetName() const { return filename_; } }; static int LockOrUnlock(int fd, bool lock) { @@ -333,7 +376,7 @@ class PosixEnv : public Env { mmap_limit_.Release(); } } else { - *result = new PosixRandomAccessFile(fname, fd); + *result = new PosixRandomAccessFile(fname, fd, &fd_limit_); } return s; } @@ -351,6 +394,19 @@ class PosixEnv : public Env { return s; } + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result) { + Status s; + FILE* f = fopen(fname.c_str(), "a"); + if (f == NULL) { + *result = NULL; + s = IOError(fname, errno); + } else { + *result = new PosixWritableFile(fname, f); + } + return s; + } + virtual bool FileExists(const std::string& fname) { return access(fname.c_str(), F_OK) == 0; } @@ -520,10 +576,42 @@ class PosixEnv : public Env { BGQueue queue_; PosixLockTable locks_; - MmapLimiter mmap_limit_; + Limiter mmap_limit_; + Limiter fd_limit_; }; -PosixEnv::PosixEnv() : started_bgthread_(false) { +// Return the maximum number of concurrent mmaps. +static int MaxMmaps() { + if (mmap_limit >= 0) { + return mmap_limit; + } + // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. + mmap_limit = sizeof(void*) >= 8 ? 1000 : 0; + return mmap_limit; +} + +// Return the maximum number of read-only files to keep open. +static intptr_t MaxOpenFiles() { + if (open_read_only_file_limit >= 0) { + return open_read_only_file_limit; + } + struct rlimit rlim; + if (getrlimit(RLIMIT_NOFILE, &rlim)) { + // getrlimit failed, fallback to hard-coded default. + open_read_only_file_limit = 50; + } else if (rlim.rlim_cur == RLIM_INFINITY) { + open_read_only_file_limit = std::numeric_limits::max(); + } else { + // Allow use of 20% of available file descriptors for read-only files. + open_read_only_file_limit = rlim.rlim_cur / 5; + } + return open_read_only_file_limit; +} + +PosixEnv::PosixEnv() + : started_bgthread_(false), + mmap_limit_(MaxMmaps()), + fd_limit_(MaxOpenFiles()) { PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); } @@ -598,6 +686,16 @@ static pthread_once_t once = PTHREAD_ONCE_INIT; static Env* default_env; static void InitDefaultEnv() { default_env = new PosixEnv; } +void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) { + assert(default_env == NULL); + open_read_only_file_limit = limit; +} + +void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) { + assert(default_env == NULL); + mmap_limit = limit; +} + Env* Env::Default() { pthread_once(&once, InitDefaultEnv); return default_env; diff --git a/src/leveldb/util/env_posix_test.cc b/src/leveldb/util/env_posix_test.cc new file mode 100644 index 000000000000..295f8ae4409f --- /dev/null +++ b/src/leveldb/util/env_posix_test.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +#include "port/port.h" +#include "util/testharness.h" +#include "util/env_posix_test_helper.h" + +namespace leveldb { + +static const int kDelayMicros = 100000; +static const int kReadOnlyFileLimit = 4; +static const int kMMapLimit = 4; + +class EnvPosixTest { + public: + Env* env_; + EnvPosixTest() : env_(Env::Default()) { } + + static void SetFileLimits(int read_only_file_limit, int mmap_limit) { + EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit); + EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit); + } +}; + +TEST(EnvPosixTest, TestOpenOnRead) { + // Write some test data to a single file that will be opened |n| times. + std::string test_dir; + ASSERT_OK(env_->GetTestDirectory(&test_dir)); + std::string test_file = test_dir + "/open_on_read.txt"; + + FILE* f = fopen(test_file.c_str(), "w"); + ASSERT_TRUE(f != NULL); + const char kFileData[] = "abcdefghijklmnopqrstuvwxyz"; + fputs(kFileData, f); + fclose(f); + + // Open test file some number above the sum of the two limits to force + // open-on-read behavior of POSIX Env leveldb::RandomAccessFile. + const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5; + leveldb::RandomAccessFile* files[kNumFiles] = {0}; + for (int i = 0; i < kNumFiles; i++) { + ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i])); + } + char scratch; + Slice read_result; + for (int i = 0; i < kNumFiles; i++) { + ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch)); + ASSERT_EQ(kFileData[i], read_result[0]); + } + for (int i = 0; i < kNumFiles; i++) { + delete files[i]; + } + ASSERT_OK(env_->DeleteFile(test_file)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + // All tests currently run with the same read-only file limits. + leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit, + leveldb::kMMapLimit); + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/util/env_posix_test_helper.h b/src/leveldb/util/env_posix_test_helper.h new file mode 100644 index 000000000000..038696059826 --- /dev/null +++ b/src/leveldb/util/env_posix_test_helper.h @@ -0,0 +1,28 @@ +// Copyright 2017 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ +#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ + +namespace leveldb { + +class EnvPosixTest; + +// A helper for the POSIX Env to facilitate testing. +class EnvPosixTestHelper { + private: + friend class EnvPosixTest; + + // Set the maximum number of read-only files that will be opened. + // Must be called before creating an Env. + static void SetReadOnlyFDLimit(int limit); + + // Set the maximum number of read-only files that will be mapped via mmap. + // Must be called before creating an Env. + static void SetReadOnlyMMapLimit(int limit); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ diff --git a/src/leveldb/util/env_test.cc b/src/leveldb/util/env_test.cc index b72cb4438425..839ae56a1a49 100644 --- a/src/leveldb/util/env_test.cc +++ b/src/leveldb/util/env_test.cc @@ -10,29 +10,31 @@ namespace leveldb { static const int kDelayMicros = 100000; +static const int kReadOnlyFileLimit = 4; +static const int kMMapLimit = 4; -class EnvPosixTest { +class EnvTest { private: port::Mutex mu_; std::string events_; public: Env* env_; - EnvPosixTest() : env_(Env::Default()) { } + EnvTest() : env_(Env::Default()) { } }; static void SetBool(void* ptr) { reinterpret_cast(ptr)->NoBarrier_Store(ptr); } -TEST(EnvPosixTest, RunImmediately) { +TEST(EnvTest, RunImmediately) { port::AtomicPointer called (NULL); env_->Schedule(&SetBool, &called); - Env::Default()->SleepForMicroseconds(kDelayMicros); + env_->SleepForMicroseconds(kDelayMicros); ASSERT_TRUE(called.NoBarrier_Load() != NULL); } -TEST(EnvPosixTest, RunMany) { +TEST(EnvTest, RunMany) { port::AtomicPointer last_id (NULL); struct CB { @@ -59,7 +61,7 @@ TEST(EnvPosixTest, RunMany) { env_->Schedule(&CB::Run, &cb3); env_->Schedule(&CB::Run, &cb4); - Env::Default()->SleepForMicroseconds(kDelayMicros); + env_->SleepForMicroseconds(kDelayMicros); void* cur = last_id.Acquire_Load(); ASSERT_EQ(4, reinterpret_cast(cur)); } @@ -78,7 +80,7 @@ static void ThreadBody(void* arg) { s->mu.Unlock(); } -TEST(EnvPosixTest, StartThread) { +TEST(EnvTest, StartThread) { State state; state.val = 0; state.num_running = 3; @@ -92,7 +94,7 @@ TEST(EnvPosixTest, StartThread) { if (num == 0) { break; } - Env::Default()->SleepForMicroseconds(kDelayMicros); + env_->SleepForMicroseconds(kDelayMicros); } ASSERT_EQ(state.val, 3); } diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc index ef2ecae83066..81380216bb09 100644 --- a/src/leveldb/util/env_win.cc +++ b/src/leveldb/util/env_win.cc @@ -1,7 +1,7 @@ // This file contains source that originates from: // http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h // http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc -// Those files dont' have any explict license headers but the +// Those files don't have any explicit license headers but the // project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' // as the license. #if defined(LEVELDB_PLATFORM_WINDOWS) @@ -78,6 +78,7 @@ class Win32SequentialFile : public SequentialFile virtual Status Read(size_t n, Slice* result, char* scratch); virtual Status Skip(uint64_t n); BOOL isEnable(); + virtual std::string GetName() const { return _filename; } private: BOOL _Init(); void _CleanUp(); @@ -94,6 +95,7 @@ class Win32RandomAccessFile : public RandomAccessFile virtual ~Win32RandomAccessFile(); virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; BOOL isEnable(); + virtual std::string GetName() const { return _filename; } private: BOOL _Init(LPCWSTR path); void _CleanUp(); @@ -103,39 +105,21 @@ class Win32RandomAccessFile : public RandomAccessFile DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); }; -class Win32MapFile : public WritableFile +class Win32WritableFile : public WritableFile { public: - Win32MapFile(const std::string& fname); + Win32WritableFile(const std::string& fname, bool append); + ~Win32WritableFile(); - ~Win32MapFile(); virtual Status Append(const Slice& data); virtual Status Close(); virtual Status Flush(); virtual Status Sync(); BOOL isEnable(); + virtual std::string GetName() const { return filename_; } private: - std::string _filename; - HANDLE _hFile; - size_t _page_size; - size_t _map_size; // How much extra memory to map at a time - char* _base; // The mapped region - HANDLE _base_handle; - char* _limit; // Limit of the mapped region - char* _dst; // Where to write next (in range [base_,limit_]) - char* _last_sync; // Where have we synced up to - uint64_t _file_offset; // Offset of base_ in file - //LARGE_INTEGER file_offset_; - // Have we done an munmap of unsynced data? - bool _pending_sync; - - // Roundup x to a multiple of y - static size_t _Roundup(size_t x, size_t y); - size_t _TruncateToPageBoundary(size_t s); - bool _UnmapCurrentRegion(); - bool _MapNewRegion(); - DISALLOW_COPY_AND_ASSIGN(Win32MapFile); - BOOL _Init(LPCWSTR Path); + std::string filename_; + ::HANDLE _hFile; }; class Win32FileLock : public FileLock @@ -177,6 +161,8 @@ class Win32Env : public Env RandomAccessFile** result); virtual Status NewWritableFile(const std::string& fname, WritableFile** result); + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); virtual bool FileExists(const std::string& fname); @@ -372,11 +358,13 @@ BOOL Win32SequentialFile::_Init() ToWidePath(_filename, path); _hFile = CreateFileW(path.c_str(), GENERIC_READ, - FILE_SHARE_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (_hFile == INVALID_HANDLE_VALUE) + _hFile = NULL; return _hFile ? TRUE : FALSE; } @@ -420,7 +408,7 @@ BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) { BOOL bRet = FALSE; if(!_hFile) - _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, + _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) _hFile = NULL; @@ -442,202 +430,69 @@ void Win32RandomAccessFile::_CleanUp() } } -size_t Win32MapFile::_Roundup( size_t x, size_t y ) -{ - return ((x + y - 1) / y) * y; -} - -size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) +Win32WritableFile::Win32WritableFile(const std::string& fname, bool append) + : filename_(fname) { - s -= (s & (_page_size - 1)); - assert((s % _page_size) == 0); - return s; + std::wstring path; + ToWidePath(fname, path); + // NewAppendableFile: append to an existing file, or create a new one + // if none exists - this is OPEN_ALWAYS behavior, with + // FILE_APPEND_DATA to avoid having to manually position the file + // pointer at the end of the file. + // NewWritableFile: create a new file, delete if it exists - this is + // CREATE_ALWAYS behavior. This file is used for writing only so + // use GENERIC_WRITE. + _hFile = CreateFileW(path.c_str(), + append ? FILE_APPEND_DATA : GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, + NULL, + append ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + // CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use } -bool Win32MapFile::_UnmapCurrentRegion() +Win32WritableFile::~Win32WritableFile() { - bool result = true; - if (_base != NULL) { - if (_last_sync < _limit) { - // Defer syncing this data until next Sync() call, if any - _pending_sync = true; - } - if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) - result = false; - _file_offset += _limit - _base; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - _last_sync = NULL; - _dst = NULL; - // Increase the amount we map the next time, but capped at 1MB - if (_map_size < (1<<20)) { - _map_size *= 2; - } - } - return result; + if (_hFile != INVALID_HANDLE_VALUE) + Close(); } -bool Win32MapFile::_MapNewRegion() +Status Win32WritableFile::Append(const Slice& data) { - assert(_base == NULL); - //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); - //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); - DWORD off_hi = (DWORD)(_file_offset >> 32); - DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset + _map_size; - SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); - SetEndOfFile(_hFile); - - _base_handle = CreateFileMappingA( - _hFile, - NULL, - PAGE_READWRITE, - 0, - 0, - 0); - if (_base_handle != NULL) { - _base = (char*) MapViewOfFile(_base_handle, - FILE_MAP_ALL_ACCESS, - off_hi, - off_lo, - _map_size); - if (_base != NULL) { - _limit = _base + _map_size; - _dst = _base; - _last_sync = _base; - return true; - } + DWORD r = 0; + if (!WriteFile(_hFile, data.data(), data.size(), &r, NULL) || r != data.size()) { + return Status::IOError("Win32WritableFile.Append::WriteFile: "+filename_, Win32::GetLastErrSz()); } - return false; + return Status::OK(); } -Win32MapFile::Win32MapFile( const std::string& fname) : - _filename(fname), - _hFile(NULL), - _page_size(Win32::g_PageSize), - _map_size(_Roundup(65536, Win32::g_PageSize)), - _base(NULL), - _base_handle(NULL), - _limit(NULL), - _dst(NULL), - _last_sync(NULL), - _file_offset(0), - _pending_sync(false) +Status Win32WritableFile::Close() { - std::wstring path; - ToWidePath(fname, path); - _Init(path.c_str()); - assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); -} - -Status Win32MapFile::Append( const Slice& data ) -{ - const char* src = data.data(); - size_t left = data.size(); - Status s; - while (left > 0) { - assert(_base <= _dst); - assert(_dst <= _limit); - size_t avail = _limit - _dst; - if (avail == 0) { - if (!_UnmapCurrentRegion() || - !_MapNewRegion()) { - return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); - } - } - size_t n = (left <= avail) ? left : avail; - memcpy(_dst, src, n); - _dst += n; - src += n; - left -= n; - } - return s; -} - -Status Win32MapFile::Close() -{ - Status s; - size_t unused = _limit - _dst; - if (!_UnmapCurrentRegion()) { - s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); - } else if (unused > 0) { - // Trim the extra space at the end of the file - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset - unused; - if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { - s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); - } else - SetEndOfFile(_hFile); - } if (!CloseHandle(_hFile)) { - if (s.ok()) { - s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); - } + return Status::IOError("Win32WritableFile.Close::CloseHandle: "+filename_, Win32::GetLastErrSz()); } _hFile = INVALID_HANDLE_VALUE; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - - return s; -} - -Status Win32MapFile::Sync() -{ - Status s; - if (_pending_sync) { - // Some unmapped data was not synced - _pending_sync = false; - if (!FlushFileBuffers(_hFile)) { - s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); - } - } - if (_dst > _last_sync) { - // Find the beginnings of the pages that contain the first and last - // bytes to be synced. - size_t p1 = _TruncateToPageBoundary(_last_sync - _base); - size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); - _last_sync = _dst; - if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { - s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); - } - } - return s; + return Status::OK(); } -Status Win32MapFile::Flush() +Status Win32WritableFile::Flush() { + // Nothing to do here, there are no application-side buffers return Status::OK(); } -Win32MapFile::~Win32MapFile() +Status Win32WritableFile::Sync() { - if (_hFile != INVALID_HANDLE_VALUE) { - Win32MapFile::Close(); + if (!FlushFileBuffers(_hFile)) { + return Status::IOError("Win32WritableFile.Sync::FlushFileBuffers "+filename_, Win32::GetLastErrSz()); } + return Status::OK(); } -BOOL Win32MapFile::_Init( LPCWSTR Path ) -{ - DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; - _hFile = CreateFileW(Path, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, - NULL, - Flag, - FILE_ATTRIBUTE_NORMAL, - NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE) - return FALSE; - else - return TRUE; -} - -BOOL Win32MapFile::isEnable() +BOOL Win32WritableFile::isEnable() { - return _hFile ? TRUE : FALSE; + return _hFile != INVALID_HANDLE_VALUE; } Win32FileLock::Win32FileLock( const std::string& fname ) : @@ -819,7 +674,7 @@ Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) ToWidePath(ModifyPath(path), wpath); HANDLE file = ::CreateFileW(wpath.c_str(), - GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); LARGE_INTEGER li; if(::GetFileSizeEx(file,&li)){ *file_size = (uint64_t)li.QuadPart; @@ -981,7 +836,9 @@ Status Win32Env::NewLogger( const std::string& fname, Logger** result ) { Status sRet; std::string path = fname; - Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); + // Logs are opened with write semantics, not with append semantics + // (see PosixEnv::NewLogger) + Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path), false); if(!pMapFile->isEnable()){ delete pMapFile; *result = NULL; @@ -995,7 +852,20 @@ Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** resul { Status sRet; std::string path = fname; - Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); + Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), false); + if(!pFile->isEnable()){ + *result = NULL; + sRet = Status::IOError(fname,Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Status Win32Env::NewAppendableFile( const std::string& fname, WritableFile** result ) +{ + Status sRet; + std::string path = fname; + Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), true); if(!pFile->isEnable()){ *result = NULL; sRet = Status::IOError(fname,Win32::GetLastErrSz()); diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc index 2a1028a2c265..db6160c8f199 100644 --- a/src/leveldb/util/logging.cc +++ b/src/leveldb/util/logging.cc @@ -49,13 +49,13 @@ bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { uint64_t v = 0; int digits = 0; while (!in->empty()) { - char c = (*in)[0]; + unsigned char c = (*in)[0]; if (c >= '0' && c <= '9') { ++digits; const int delta = (c - '0'); static const uint64_t kMaxUint64 = ~static_cast(0); if (v > kMaxUint64/10 || - (v == kMaxUint64/10 && (uint64_t)delta > kMaxUint64%10)) { + (v == kMaxUint64/10 && delta > kMaxUint64%10)) { // Overflow return false; } diff --git a/src/leveldb/util/options.cc b/src/leveldb/util/options.cc index 76af5b9302d4..b5e622761357 100644 --- a/src/leveldb/util/options.cc +++ b/src/leveldb/util/options.cc @@ -21,9 +21,10 @@ Options::Options() block_cache(NULL), block_size(4096), block_restart_interval(16), + max_file_size(2<<20), compression(kSnappyCompression), + reuse_logs(false), filter_policy(NULL) { } - } // namespace leveldb diff --git a/src/leveldb/util/testutil.h b/src/leveldb/util/testutil.h index adad3fc1eacb..d7e45837027d 100644 --- a/src/leveldb/util/testutil.h +++ b/src/leveldb/util/testutil.h @@ -45,6 +45,16 @@ class ErrorEnv : public EnvWrapper { } return target()->NewWritableFile(fname, result); } + + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result) { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = NULL; + return Status::IOError(fname, "fake error"); + } + return target()->NewAppendableFile(fname, result); + } }; } // namespace test diff --git a/src/libzerocoin/Accumulator.cpp b/src/libzerocoin/Accumulator.cpp index 5a56564bc22c..350fc377a76b 100644 --- a/src/libzerocoin/Accumulator.cpp +++ b/src/libzerocoin/Accumulator.cpp @@ -20,25 +20,25 @@ namespace libzerocoin { //Accumulator class Accumulator::Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d): params(p) { - if (!(params->initialized)) { - throw std::runtime_error("Invalid parameters for accumulator"); - } + if (!(params->initialized)) { + throw std::runtime_error("Invalid parameters for accumulator"); + } denomination = d; - this->value = this->params->accumulatorBase; + this->value = this->params->accumulatorBase; } Accumulator::Accumulator(const ZerocoinParams* p, const CoinDenomination d, const Bignum bnValue) { - this->params = &(p->accumulatorParams); + this->params = &(p->accumulatorParams); denomination = d; - if (!(params->initialized)) { - throw std::runtime_error("Invalid parameters for accumulator"); - } + if (!(params->initialized)) { + throw std::runtime_error("Invalid parameters for accumulator"); + } - if(bnValue != 0) - this->value = bnValue; - else - this->value = this->params->accumulatorBase; + if(bnValue != 0) + this->value = bnValue; + else + this->value = this->params->accumulatorBase; } void Accumulator::increment(const CBigNum& bnValue) { @@ -47,44 +47,44 @@ void Accumulator::increment(const CBigNum& bnValue) { } void Accumulator::accumulate(const PublicCoin& coin) { - // Make sure we're initialized - if(!(this->value)) { - throw std::runtime_error("Accumulator is not initialized"); - } + // Make sure we're initialized + if(!(this->value)) { + throw std::runtime_error("Accumulator is not initialized"); + } - if(this->denomination != coin.getDenomination()) { - std::cout << "Wrong denomination for coin. Expected coins of denomination: "; + if(this->denomination != coin.getDenomination()) { + std::cout << "Wrong denomination for coin. Expected coins of denomination: "; std::cout << this->denomination; std::cout << ". Instead, got a coin of denomination: "; std::cout << coin.getDenomination(); std::cout << "\n"; - throw std::runtime_error("Wrong denomination for coin"); - } + throw std::runtime_error("Wrong denomination for coin"); + } - if(coin.validate()) { - increment(coin.getValue()); - } else { - std::cout << "Coin not valid\n"; + if(coin.validate()) { + increment(coin.getValue()); + } else { + std::cout << "Coin not valid\n"; throw std::runtime_error("Coin is not valid"); - } + } } CoinDenomination Accumulator::getDenomination() const { - return this->denomination; + return this->denomination; } const CBigNum& Accumulator::getValue() const { - return this->value; + return this->value; } //Manually set accumulator value void Accumulator::setValue(CBigNum bnValue) { - this->value = bnValue; + this->value = bnValue; } Accumulator& Accumulator::operator += (const PublicCoin& c) { - this->accumulate(c); - return *this; + this->accumulate(c); + return *this; } Accumulator& Accumulator::operator = (Accumulator rhs) { @@ -93,7 +93,7 @@ Accumulator& Accumulator::operator = (Accumulator rhs) { } bool Accumulator::operator == (const Accumulator rhs) const { - return this->value == rhs.value; + return this->value == rhs.value; } //AccumulatorWitness class @@ -107,9 +107,9 @@ void AccumulatorWitness::resetValue(const Accumulator& checkpoint, const PublicC } void AccumulatorWitness::AddElement(const PublicCoin& c) { - if(element.getValue() != c.getValue()) { - witness += c; - } + if(element.getValue() != c.getValue()) { + witness += c; + } } //warning check pubcoin value & denom outside of this function! @@ -118,32 +118,32 @@ void AccumulatorWitness::addRawValue(const CBigNum& bnValue) { } const CBigNum& AccumulatorWitness::getValue() const { - return this->witness.getValue(); + return this->witness.getValue(); } bool AccumulatorWitness::VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const { - Accumulator temp(witness); - temp += element; - if (!(temp == a)) { - LogPrintf("Accumulator does not verify.\n"); - } - if (this->element != publicCoin) { - LogPrintf("Pubcoin does not verify.\n"); - } - return (temp == a && this->element == publicCoin); + Accumulator temp(witness); + temp += element; + if (!(temp == a)) { + LogPrintf("Accumulator does not verify.\n"); + } + if (this->element != publicCoin) { + LogPrintf("Pubcoin does not verify.\n"); + } + return (temp == a && this->element == publicCoin); } AccumulatorWitness& AccumulatorWitness::operator +=( const PublicCoin& rhs) { - this->AddElement(rhs); - return *this; + this->AddElement(rhs); + return *this; } AccumulatorWitness& AccumulatorWitness::operator =(AccumulatorWitness rhs) { // Not pretty, but seems to work (SPOCK) if (&witness != &rhs.witness) this->witness = rhs.witness; if (&element != &rhs.element) std::swap(element, rhs.element); - return *this; + return *this; } } /* namespace libzerocoin */ diff --git a/src/libzerocoin/Accumulator.h b/src/libzerocoin/Accumulator.h index 8e4d3ef1e174..d1c5e0ed8c7f 100644 --- a/src/libzerocoin/Accumulator.h +++ b/src/libzerocoin/Accumulator.h @@ -23,80 +23,80 @@ namespace libzerocoin { class Accumulator { public: - /** - * @brief Construct an Accumulator from a stream. - * @param p An AccumulatorAndProofParams object containing global parameters - * @param d the denomination of coins we are accumulating - * @throw Zerocoin exception in case of invalid parameters - **/ - template - Accumulator(const AccumulatorAndProofParams* p, Stream& strm): params(p) { - strm >> *this; - } - - template - Accumulator(const ZerocoinParams* p, Stream& strm) { - strm >> *this; - this->params = &(p->accumulatorParams); - } - - /** - * @brief Construct an Accumulator from a Params object. - * @param p A Params object containing global parameters - * @param d the denomination of coins we are accumulating - * @throw Zerocoin exception in case of invalid parameters - **/ - Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d); - - Accumulator(const ZerocoinParams* p, const CoinDenomination d, Bignum bnValue = 0); - - /** - * Accumulate a coin into the accumulator. Validates - * the coin prior to accumulation. - * - * @param coin A PublicCoin to accumulate. - * - * @throw Zerocoin exception if the coin is not valid. - * - **/ - void accumulate(const PublicCoin &coin); + /** + * @brief Construct an Accumulator from a stream. + * @param p An AccumulatorAndProofParams object containing global parameters + * @param d the denomination of coins we are accumulating + * @throw Zerocoin exception in case of invalid parameters + **/ + template + Accumulator(const AccumulatorAndProofParams* p, Stream& strm): params(p) { + strm >> *this; + } + + template + Accumulator(const ZerocoinParams* p, Stream& strm) { + strm >> *this; + this->params = &(p->accumulatorParams); + } + + /** + * @brief Construct an Accumulator from a Params object. + * @param p A Params object containing global parameters + * @param d the denomination of coins we are accumulating + * @throw Zerocoin exception in case of invalid parameters + **/ + Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d); + + Accumulator(const ZerocoinParams* p, const CoinDenomination d, Bignum bnValue = 0); + + /** + * Accumulate a coin into the accumulator. Validates + * the coin prior to accumulation. + * + * @param coin A PublicCoin to accumulate. + * + * @throw Zerocoin exception if the coin is not valid. + * + **/ + void accumulate(const PublicCoin &coin); void increment(const CBigNum& bnValue); - CoinDenomination getDenomination() const; - /** Get the accumulator result - * - * @return a CBigNum containing the result. - */ - const CBigNum& getValue() const; - - void setValue(CBigNum bnValue); - - - // /** - // * Used to set the accumulator value - // * - // * Use this to handle accumulator checkpoints - // * @param b the value to set the accumulator to. - // * @throw A ZerocoinException if the accumulator value is invalid. - // */ - // void setValue(CBigNum &b); // shouldn't this be a constructor? - - /** Used to accumulate a coin - * - * @param c the coin to accumulate - * @return a refrence to the updated accumulator. - */ - Accumulator& operator +=(const PublicCoin& c); + CoinDenomination getDenomination() const; + /** Get the accumulator result + * + * @return a CBigNum containing the result. + */ + const CBigNum& getValue() const; + + void setValue(CBigNum bnValue); + + + // /** + // * Used to set the accumulator value + // * + // * Use this to handle accumulator checkpoints + // * @param b the value to set the accumulator to. + // * @throw A ZerocoinException if the accumulator value is invalid. + // */ + // void setValue(CBigNum &b); // shouldn't this be a constructor? + + /** Used to accumulate a coin + * + * @param c the coin to accumulate + * @return a refrence to the updated accumulator. + */ + Accumulator& operator +=(const PublicCoin& c); Accumulator& operator =(Accumulator rhs); - bool operator==(const Accumulator rhs) const; - ADD_SERIALIZE_METHODS; + bool operator==(const Accumulator rhs) const; + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(value); + READWRITE(value); READWRITE(denomination); - } + } private: - const AccumulatorAndProofParams* params; - CBigNum value; + const AccumulatorAndProofParams* params; + CBigNum value; CoinDenomination denomination; }; @@ -105,54 +105,54 @@ class Accumulator { */ class AccumulatorWitness { public: - template - AccumulatorWitness(const ZerocoinParams* p, Stream& strm) { - strm >> *this; - } - - /** Construct's a witness. You must add all elements after the witness - * @param p pointer to params - * @param checkpoint the last known accumulator value before the element was added - * @param coin the coin we want a witness to - */ - AccumulatorWitness(const ZerocoinParams* p, const Accumulator& checkpoint, const PublicCoin coin); - - /** Adds element to the set whose's accumulation we are proving coin is a member of - * - * @param c the coin to add - */ - void AddElement(const PublicCoin& c); + template + AccumulatorWitness(const ZerocoinParams* p, Stream& strm) { + strm >> *this; + } + + /** Construct's a witness. You must add all elements after the witness + * @param p pointer to params + * @param checkpoint the last known accumulator value before the element was added + * @param coin the coin we want a witness to + */ + AccumulatorWitness(const ZerocoinParams* p, const Accumulator& checkpoint, const PublicCoin coin); + + /** Adds element to the set whose's accumulation we are proving coin is a member of + * + * @param c the coin to add + */ + void AddElement(const PublicCoin& c); /** Adds element to the set whose's accumulation we are proving coin is a member of. No checks performed! - * - * @param bnValue the coin's value to add - */ + * + * @param bnValue the coin's value to add + */ void addRawValue(const CBigNum& bnValue); - /** - * - * @return the value of the witness - */ - const CBigNum& getValue() const; + /** + * + * @return the value of the witness + */ + const CBigNum& getValue() const; void resetValue(const Accumulator& checkpoint, const PublicCoin coin); - /** Checks that this is a witness to the accumulation of coin - * @param a the accumulator we are checking against. - * @param publicCoin the coin we're providing a witness for - * @return True if the witness computation validates - */ - bool VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const; + /** Checks that this is a witness to the accumulation of coin + * @param a the accumulator we are checking against. + * @param publicCoin the coin we're providing a witness for + * @return True if the witness computation validates + */ + bool VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const; - /** - * Adds rhs to the set whose's accumulation ware proving coin is a member of - * @param rhs the PublicCoin to add - * @return - */ - AccumulatorWitness& operator +=(const PublicCoin& rhs); + /** + * Adds rhs to the set whose's accumulation ware proving coin is a member of + * @param rhs the PublicCoin to add + * @return + */ + AccumulatorWitness& operator +=(const PublicCoin& rhs); AccumulatorWitness& operator =(AccumulatorWitness rhs); private: - Accumulator witness; + Accumulator witness; PublicCoin element; // was const but changed to use setting in assignment }; diff --git a/src/libzerocoin/AccumulatorProofOfKnowledge.cpp b/src/libzerocoin/AccumulatorProofOfKnowledge.cpp index b3a102dd3f2d..eedeec2040e2 100644 --- a/src/libzerocoin/AccumulatorProofOfKnowledge.cpp +++ b/src/libzerocoin/AccumulatorProofOfKnowledge.cpp @@ -21,126 +21,126 @@ AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndPro const Commitment& commitmentToCoin, const AccumulatorWitness& witness, Accumulator& a): params(p) { - CBigNum sg = params->accumulatorPoKCommitmentGroup.g; - CBigNum sh = params->accumulatorPoKCommitmentGroup.h; - - CBigNum g_n = params->accumulatorQRNCommitmentGroup.g; - CBigNum h_n = params->accumulatorQRNCommitmentGroup.h; - - CBigNum e = commitmentToCoin.getContents(); - CBigNum r = commitmentToCoin.getRandomness(); - - CBigNum aM_4 = params->accumulatorModulus/CBigNum((long)4); - - CBigNum r_1 = CBigNum::randBignum(params->accumulatorModulus/4); - CBigNum r_2 = CBigNum::randBignum(params->accumulatorModulus/4); - CBigNum r_3 = CBigNum::randBignum(params->accumulatorModulus/4); - - this->C_e = g_n.pow_mod(e, params->accumulatorModulus) * h_n.pow_mod(r_1, params->accumulatorModulus); - this->C_u = witness.getValue() * h_n.pow_mod(r_2, params->accumulatorModulus); - this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus); - - CBigNum r_alpha = CBigNum::randBignum(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime)); - if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { - r_alpha = 0-r_alpha; - } - - CBigNum r_gamma = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); - CBigNum r_phi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); - CBigNum r_psi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); - CBigNum r_sigma = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); - CBigNum r_xi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); - - CBigNum r_epsilon = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); - if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { - r_epsilon = 0-r_epsilon; - } - CBigNum r_eta = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); - if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { - r_eta = 0-r_eta; - } - CBigNum r_zeta = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); - if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { - r_zeta = 0-r_zeta; - } - - CBigNum r_beta = CBigNum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * CBigNum(2).pow(params->k_prime + params->k_dprime)); - if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { - r_beta = 0-r_beta; - } - CBigNum r_delta = CBigNum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * CBigNum(2).pow(params->k_prime + params->k_dprime)); - if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { - r_delta = 0-r_delta; - } - - this->st_1 = (sg.pow_mod(r_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; - this->st_2 = (((commitmentToCoin.getCommitmentValue() * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(r_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(r_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; - this->st_3 = ((sg * commitmentToCoin.getCommitmentValue()).pow_mod(r_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; - - this->t_1 = (h_n.pow_mod(r_zeta, params->accumulatorModulus) * g_n.pow_mod(r_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; - this->t_2 = (h_n.pow_mod(r_eta, params->accumulatorModulus) * g_n.pow_mod(r_alpha, params->accumulatorModulus)) % params->accumulatorModulus; - this->t_3 = (C_u.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; - this->t_4 = (C_r.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; - - CHashWriter hasher(0,0); - hasher << *params << sg << sh << g_n << h_n << commitmentToCoin.getCommitmentValue() << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; - - //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. - CBigNum c = CBigNum(hasher.GetHash()); - - this->s_alpha = r_alpha - c*e; - this->s_beta = r_beta - c*r_2*e; - this->s_zeta = r_zeta - c*r_3; - this->s_sigma = r_sigma - c*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); - this->s_eta = r_eta - c*r_1; - this->s_epsilon = r_epsilon - c*r_2; - this->s_delta = r_delta - c*r_3*e; - this->s_xi = r_xi + c*r*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); - this->s_phi = (r_phi - c*r) % params->accumulatorPoKCommitmentGroup.groupOrder; - this->s_gamma = r_gamma - c*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); - this->s_psi = r_psi + c*r*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + CBigNum sg = params->accumulatorPoKCommitmentGroup.g; + CBigNum sh = params->accumulatorPoKCommitmentGroup.h; + + CBigNum g_n = params->accumulatorQRNCommitmentGroup.g; + CBigNum h_n = params->accumulatorQRNCommitmentGroup.h; + + CBigNum e = commitmentToCoin.getContents(); + CBigNum r = commitmentToCoin.getRandomness(); + + CBigNum aM_4 = params->accumulatorModulus/CBigNum((long)4); + + CBigNum r_1 = CBigNum::randBignum(params->accumulatorModulus/4); + CBigNum r_2 = CBigNum::randBignum(params->accumulatorModulus/4); + CBigNum r_3 = CBigNum::randBignum(params->accumulatorModulus/4); + + this->C_e = g_n.pow_mod(e, params->accumulatorModulus) * h_n.pow_mod(r_1, params->accumulatorModulus); + this->C_u = witness.getValue() * h_n.pow_mod(r_2, params->accumulatorModulus); + this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus); + + CBigNum r_alpha = CBigNum::randBignum(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_alpha = 0-r_alpha; + } + + CBigNum r_gamma = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_phi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_psi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_sigma = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_xi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + + CBigNum r_epsilon = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_epsilon = 0-r_epsilon; + } + CBigNum r_eta = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_eta = 0-r_eta; + } + CBigNum r_zeta = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_zeta = 0-r_zeta; + } + + CBigNum r_beta = CBigNum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_beta = 0-r_beta; + } + CBigNum r_delta = CBigNum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_delta = 0-r_delta; + } + + this->st_1 = (sg.pow_mod(r_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + this->st_2 = (((commitmentToCoin.getCommitmentValue() * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(r_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(r_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + this->st_3 = ((sg * commitmentToCoin.getCommitmentValue()).pow_mod(r_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + + this->t_1 = (h_n.pow_mod(r_zeta, params->accumulatorModulus) * g_n.pow_mod(r_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; + this->t_2 = (h_n.pow_mod(r_eta, params->accumulatorModulus) * g_n.pow_mod(r_alpha, params->accumulatorModulus)) % params->accumulatorModulus; + this->t_3 = (C_u.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; + this->t_4 = (C_r.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; + + CHashWriter hasher(0,0); + hasher << *params << sg << sh << g_n << h_n << commitmentToCoin.getCommitmentValue() << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; + + //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. + CBigNum c = CBigNum(hasher.GetHash()); + + this->s_alpha = r_alpha - c*e; + this->s_beta = r_beta - c*r_2*e; + this->s_zeta = r_zeta - c*r_3; + this->s_sigma = r_sigma - c*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + this->s_eta = r_eta - c*r_1; + this->s_epsilon = r_epsilon - c*r_2; + this->s_delta = r_delta - c*r_3*e; + this->s_xi = r_xi + c*r*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + this->s_phi = (r_phi - c*r) % params->accumulatorPoKCommitmentGroup.groupOrder; + this->s_gamma = r_gamma - c*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + this->s_psi = r_psi + c*r*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); } /** Verifies that a commitment c is accumulated in accumulator a */ bool AccumulatorProofOfKnowledge:: Verify(const Accumulator& a, const CBigNum& valueOfCommitmentToCoin) const { - CBigNum sg = params->accumulatorPoKCommitmentGroup.g; - CBigNum sh = params->accumulatorPoKCommitmentGroup.h; + CBigNum sg = params->accumulatorPoKCommitmentGroup.g; + CBigNum sh = params->accumulatorPoKCommitmentGroup.h; - CBigNum g_n = params->accumulatorQRNCommitmentGroup.g; - CBigNum h_n = params->accumulatorQRNCommitmentGroup.h; + CBigNum g_n = params->accumulatorQRNCommitmentGroup.g; + CBigNum h_n = params->accumulatorQRNCommitmentGroup.h; - //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. - CHashWriter hasher(0,0); - hasher << *params << sg << sh << g_n << h_n << valueOfCommitmentToCoin << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; + //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. + CHashWriter hasher(0,0); + hasher << *params << sg << sh << g_n << h_n << valueOfCommitmentToCoin << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; - CBigNum c = CBigNum(hasher.GetHash()); //this hash should be of length k_prime bits + CBigNum c = CBigNum(hasher.GetHash()); //this hash should be of length k_prime bits - CBigNum st_1_prime = (valueOfCommitmentToCoin.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * sg.pow_mod(s_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; - CBigNum st_2_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * ((valueOfCommitmentToCoin * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(s_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(s_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; - CBigNum st_3_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * (sg * valueOfCommitmentToCoin).pow_mod(s_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + CBigNum st_1_prime = (valueOfCommitmentToCoin.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * sg.pow_mod(s_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + CBigNum st_2_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * ((valueOfCommitmentToCoin * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(s_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(s_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + CBigNum st_3_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * (sg * valueOfCommitmentToCoin).pow_mod(s_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; - CBigNum t_1_prime = (C_r.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_zeta, params->accumulatorModulus) * g_n.pow_mod(s_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; - CBigNum t_2_prime = (C_e.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_eta, params->accumulatorModulus) * g_n.pow_mod(s_alpha, params->accumulatorModulus)) % params->accumulatorModulus; - CBigNum t_3_prime = ((a.getValue()).pow_mod(c, params->accumulatorModulus) * C_u.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus; - CBigNum t_4_prime = (C_r.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus; + CBigNum t_1_prime = (C_r.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_zeta, params->accumulatorModulus) * g_n.pow_mod(s_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; + CBigNum t_2_prime = (C_e.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_eta, params->accumulatorModulus) * g_n.pow_mod(s_alpha, params->accumulatorModulus)) % params->accumulatorModulus; + CBigNum t_3_prime = ((a.getValue()).pow_mod(c, params->accumulatorModulus) * C_u.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus; + CBigNum t_4_prime = (C_r.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus; - bool result = false; + bool result = false; - bool result_st1 = (st_1 == st_1_prime); - bool result_st2 = (st_2 == st_2_prime); - bool result_st3 = (st_3 == st_3_prime); + bool result_st1 = (st_1 == st_1_prime); + bool result_st2 = (st_2 == st_2_prime); + bool result_st3 = (st_3 == st_3_prime); - bool result_t1 = (t_1 == t_1_prime); - bool result_t2 = (t_2 == t_2_prime); - bool result_t3 = (t_3 == t_3_prime); - bool result_t4 = (t_4 == t_4_prime); + bool result_t1 = (t_1 == t_1_prime); + bool result_t2 = (t_2 == t_2_prime); + bool result_t3 = (t_3 == t_3_prime); + bool result_t4 = (t_4 == t_4_prime); - bool result_range = ((s_alpha >= -(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1)))); + bool result_range = ((s_alpha >= -(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1)))); - result = result_st1 && result_st2 && result_st3 && result_t1 && result_t2 && result_t3 && result_t4 && result_range; + result = result_st1 && result_st2 && result_st3 && result_t1 && result_t2 && result_t3 && result_t4 && result_range; - return result; + return result; } } /* namespace libzerocoin */ diff --git a/src/libzerocoin/AccumulatorProofOfKnowledge.h b/src/libzerocoin/AccumulatorProofOfKnowledge.h index 8fa0f467baa4..4b9329f453ec 100644 --- a/src/libzerocoin/AccumulatorProofOfKnowledge.h +++ b/src/libzerocoin/AccumulatorProofOfKnowledge.h @@ -24,71 +24,71 @@ namespace libzerocoin { */ class AccumulatorProofOfKnowledge { public: - AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p); + AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p); - /** Generates a proof that a commitment to a coin c was accumulated - * @param p Cryptographic parameters - * @param commitmentToCoin commitment containing the coin we want to prove is accumulated - * @param witness The witness to the accumulation of the coin - * @param a - */ - AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p, const Commitment& commitmentToCoin, const AccumulatorWitness& witness, Accumulator& a); - /** Verifies that a commitment c is accumulated in accumulated a - */ - bool Verify(const Accumulator& a,const CBigNum& valueOfCommitmentToCoin) const; - - ADD_SERIALIZE_METHODS; + /** Generates a proof that a commitment to a coin c was accumulated + * @param p Cryptographic parameters + * @param commitmentToCoin commitment containing the coin we want to prove is accumulated + * @param witness The witness to the accumulation of the coin + * @param a + */ + AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p, const Commitment& commitmentToCoin, const AccumulatorWitness& witness, Accumulator& a); + /** Verifies that a commitment c is accumulated in accumulated a + */ + bool Verify(const Accumulator& a,const CBigNum& valueOfCommitmentToCoin) const; + + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(C_e); - READWRITE(C_u); - READWRITE(C_r); - READWRITE(st_1); - READWRITE(st_2); - READWRITE(st_3); - READWRITE(t_1); - READWRITE(t_2); - READWRITE(t_3); - READWRITE(t_4); - READWRITE(s_alpha); - READWRITE(s_beta); - READWRITE(s_zeta); - READWRITE(s_sigma); - READWRITE(s_eta); - READWRITE(s_epsilon); - READWRITE(s_delta); - READWRITE(s_xi); - READWRITE(s_phi); - READWRITE(s_gamma); - READWRITE(s_psi); - } + READWRITE(C_e); + READWRITE(C_u); + READWRITE(C_r); + READWRITE(st_1); + READWRITE(st_2); + READWRITE(st_3); + READWRITE(t_1); + READWRITE(t_2); + READWRITE(t_3); + READWRITE(t_4); + READWRITE(s_alpha); + READWRITE(s_beta); + READWRITE(s_zeta); + READWRITE(s_sigma); + READWRITE(s_eta); + READWRITE(s_epsilon); + READWRITE(s_delta); + READWRITE(s_xi); + READWRITE(s_phi); + READWRITE(s_gamma); + READWRITE(s_psi); + } private: - const AccumulatorAndProofParams* params; + const AccumulatorAndProofParams* params; - /* Return values for proof */ - CBigNum C_e; - CBigNum C_u; - CBigNum C_r; + /* Return values for proof */ + CBigNum C_e; + CBigNum C_u; + CBigNum C_r; - CBigNum st_1; - CBigNum st_2; - CBigNum st_3; + CBigNum st_1; + CBigNum st_2; + CBigNum st_3; - CBigNum t_1; - CBigNum t_2; - CBigNum t_3; - CBigNum t_4; + CBigNum t_1; + CBigNum t_2; + CBigNum t_3; + CBigNum t_4; - CBigNum s_alpha; - CBigNum s_beta; - CBigNum s_zeta; - CBigNum s_sigma; - CBigNum s_eta; - CBigNum s_epsilon; - CBigNum s_delta; - CBigNum s_xi; - CBigNum s_phi; - CBigNum s_gamma; - CBigNum s_psi; + CBigNum s_alpha; + CBigNum s_beta; + CBigNum s_zeta; + CBigNum s_sigma; + CBigNum s_eta; + CBigNum s_epsilon; + CBigNum s_delta; + CBigNum s_xi; + CBigNum s_phi; + CBigNum s_gamma; + CBigNum s_psi; }; } /* namespace libzerocoin */ diff --git a/src/libzerocoin/Coin.cpp b/src/libzerocoin/Coin.cpp index 105f96fefc8c..4ccbc2a21f8c 100644 --- a/src/libzerocoin/Coin.cpp +++ b/src/libzerocoin/Coin.cpp @@ -21,45 +21,45 @@ namespace libzerocoin { //PublicCoin class PublicCoin::PublicCoin(const ZerocoinParams* p): - params(p) { - if (this->params->initialized == false) { - throw std::runtime_error("Params are not initialized"); - } + params(p) { + if (this->params->initialized == false) { + throw std::runtime_error("Params are not initialized"); + } // Assume this will get set by another method later denomination = ZQ_ERROR; }; PublicCoin::PublicCoin(const ZerocoinParams* p, const CBigNum& coin, const CoinDenomination d): - params(p), value(coin) { - if (this->params->initialized == false) { - throw std::runtime_error("Params are not initialized"); - } - - denomination = d; - for(const CoinDenomination denom : zerocoinDenomList) { - if(denom == d) - denomination = d; - } + params(p), value(coin) { + if (this->params->initialized == false) { + throw std::runtime_error("Params are not initialized"); + } + + denomination = d; + for(const CoinDenomination denom : libzerocoin::zerocoinDenomList) { + if(denom == d) + denomination = d; + } if(denomination == 0){ - std::cout << "denom does not exist\n"; - throw std::runtime_error("Denomination does not exist"); - } + std::cout << "denom does not exist\n"; + throw std::runtime_error("Denomination does not exist"); + } }; bool PublicCoin::validate() const { if (this->params->accumulatorParams.minCoinValue >= value) { - cout << "PublicCoin::validate value is too low\n"; + std::cout << "PublicCoin::validate value is too low\n"; return false; } if (value > this->params->accumulatorParams.maxCoinValue) { - cout << "PublicCoin::validate value is too high\n"; + std::cout << "PublicCoin::validate value is too high\n"; return false; } if (!value.isPrime(params->zkp_iterations)) { - cout << "PublicCoin::validate value is not prime\n"; + std::cout << "PublicCoin::validate value is not prime\n"; return false; } @@ -68,10 +68,10 @@ bool PublicCoin::validate() const //PrivateCoin class PrivateCoin::PrivateCoin(const ZerocoinParams* p, const CoinDenomination denomination, bool fMintNew): params(p), publicCoin(p) { - // Verify that the parameters are valid - if(this->params->initialized == false) { - throw std::runtime_error("Params are not initialized"); - } + // Verify that the parameters are valid + if(this->params->initialized == false) { + throw std::runtime_error("Params are not initialized"); + } if (fMintNew) { #ifdef ZEROCOIN_FAST_MINT @@ -105,7 +105,7 @@ PrivateCoin::PrivateCoin(const ZerocoinParams* p, const CoinDenomination denomin bool PrivateCoin::IsValid() { if (!IsValidSerial(params, serialNumber)) { - cout << "Serial not valid\n"; + std::cout << "Serial not valid\n"; return false; } @@ -146,120 +146,120 @@ bool GenerateKeyPair(const CBigNum& bnGroupOrder, const uint256& nPrivkey, CKey& const CPubKey PrivateCoin::getPubKey() const { - CKey key; - key.SetPrivKey(privkey, true); - return key.GetPubKey(); + CKey key; + key.SetPrivKey(privkey, true); + return key.GetPubKey(); } -bool PrivateCoin::sign(const uint256& hash, vector& vchSig) const +bool PrivateCoin::sign(const uint256& hash, std::vector& vchSig) const { - CKey key; - key.SetPrivKey(privkey, true); - return key.Sign(hash, vchSig); + CKey key; + key.SetPrivKey(privkey, true); + return key.Sign(hash, vchSig); } void PrivateCoin::mintCoin(const CoinDenomination denomination) { - // Repeat this process up to MAX_COINMINT_ATTEMPTS times until - // we obtain a prime number - for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) { - - // Generate a random serial number in the range 0...{q-1} where - // "q" is the order of the commitment group. - // And where the serial also doubles as a public key - CKey key; - CBigNum s; + // Repeat this process up to MAX_COINMINT_ATTEMPTS times until + // we obtain a prime number + for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) { + + // Generate a random serial number in the range 0...{q-1} where + // "q" is the order of the commitment group. + // And where the serial also doubles as a public key + CKey key; + CBigNum s; bool isValid = false; while (!isValid) { isValid = GenerateKeyPair(this->params->coinCommitmentGroup.groupOrder, uint256(0), key, s); } - // Generate a Pedersen commitment to the serial number "s" - Commitment coin(¶ms->coinCommitmentGroup, s); - - // Now verify that the commitment is a prime number - // in the appropriate range. If not, we'll throw this coin - // away and generate a new one. - if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) && - coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue && - coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) { - // Found a valid coin. Store it. - this->serialNumber = s; - this->randomness = coin.getRandomness(); - this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination); - this->privkey = key.GetPrivKey(); - this->version = 2; - - // Success! We're done. - return; - } - } - - // We only get here if we did not find a coin within - // MAX_COINMINT_ATTEMPTS. Throw an exception. - throw std::runtime_error("Unable to mint a new Zerocoin (too many attempts)"); + // Generate a Pedersen commitment to the serial number "s" + Commitment coin(¶ms->coinCommitmentGroup, s); + + // Now verify that the commitment is a prime number + // in the appropriate range. If not, we'll throw this coin + // away and generate a new one. + if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) && + coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue && + coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) { + // Found a valid coin. Store it. + this->serialNumber = s; + this->randomness = coin.getRandomness(); + this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination); + this->privkey = key.GetPrivKey(); + this->version = 2; + + // Success! We're done. + return; + } + } + + // We only get here if we did not find a coin within + // MAX_COINMINT_ATTEMPTS. Throw an exception. + throw std::runtime_error("Unable to mint a new Zerocoin (too many attempts)"); } void PrivateCoin::mintCoinFast(const CoinDenomination denomination) { - // Generate a random serial number in the range 0...{q-1} where - // "q" is the order of the commitment group. - // And where the serial also doubles as a public key - CKey key; - CBigNum s; + // Generate a random serial number in the range 0...{q-1} where + // "q" is the order of the commitment group. + // And where the serial also doubles as a public key + CKey key; + CBigNum s; bool isValid = false; while (!isValid) { isValid = GenerateKeyPair(this->params->coinCommitmentGroup.groupOrder, uint256(0), key, s); } - // Generate a random number "r" in the range 0...{q-1} - CBigNum r = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); - - // Manually compute a Pedersen commitment to the serial number "s" under randomness "r" - // C = g^s * h^r mod p - CBigNum commitmentValue = this->params->coinCommitmentGroup.g.pow_mod(s, this->params->coinCommitmentGroup.modulus).mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus); - - // Repeat this process up to MAX_COINMINT_ATTEMPTS times until - // we obtain a prime number - for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) { - // First verify that the commitment is a prime number - // in the appropriate range. If not, we'll throw this coin - // away and generate a new one. - if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) && - commitmentValue >= params->accumulatorParams.minCoinValue && - commitmentValue <= params->accumulatorParams.maxCoinValue) { - // Found a valid coin. Store it. - this->serialNumber = s; - this->randomness = r; - this->publicCoin = PublicCoin(params, commitmentValue, denomination); - this->privkey = key.GetPrivKey(); - this->version = 2; - - // Success! We're done. - return; - } - - // Generate a new random "r_delta" in 0...{q-1} - CBigNum r_delta = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); - - // The commitment was not prime. Increment "r" and recalculate "C": - // r = r + r_delta mod q - // C = C * h mod p - r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder; - commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus); - } - - // We only get here if we did not find a coin within - // MAX_COINMINT_ATTEMPTS. Throw an exception. - throw std::runtime_error("Unable to mint a new Zerocoin (too many attempts)"); + // Generate a random number "r" in the range 0...{q-1} + CBigNum r = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); + + // Manually compute a Pedersen commitment to the serial number "s" under randomness "r" + // C = g^s * h^r mod p + CBigNum commitmentValue = this->params->coinCommitmentGroup.g.pow_mod(s, this->params->coinCommitmentGroup.modulus).mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus); + + // Repeat this process up to MAX_COINMINT_ATTEMPTS times until + // we obtain a prime number + for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) { + // First verify that the commitment is a prime number + // in the appropriate range. If not, we'll throw this coin + // away and generate a new one. + if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) && + commitmentValue >= params->accumulatorParams.minCoinValue && + commitmentValue <= params->accumulatorParams.maxCoinValue) { + // Found a valid coin. Store it. + this->serialNumber = s; + this->randomness = r; + this->publicCoin = PublicCoin(params, commitmentValue, denomination); + this->privkey = key.GetPrivKey(); + this->version = 2; + + // Success! We're done. + return; + } + + // Generate a new random "r_delta" in 0...{q-1} + CBigNum r_delta = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); + + // The commitment was not prime. Increment "r" and recalculate "C": + // r = r + r_delta mod q + // C = C * h mod p + r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder; + commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus); + } + + // We only get here if we did not find a coin within + // MAX_COINMINT_ATTEMPTS. Throw an exception. + throw std::runtime_error("Unable to mint a new Zerocoin (too many attempts)"); } int ExtractVersionFromSerial(const CBigNum& bnSerial) { - //Serial is marked as v2 only if the first byte is 0xF - uint256 nMark = bnSerial.getuint256() >> (256 - PrivateCoin::V2_BITSHIFT); - if (nMark == 0xf) - return PrivateCoin::PUBKEY_VERSION; + //Serial is marked as v2 only if the first byte is 0xF + uint256 nMark = bnSerial.getuint256() >> (256 - PrivateCoin::V2_BITSHIFT); + if (nMark == 0xf) + return PrivateCoin::PUBKEY_VERSION; - return 1; + return 1; } //Remove the first four bits for V2 serials diff --git a/src/libzerocoin/Coin.h b/src/libzerocoin/Coin.h index 2578a52e5582..14162567bed8 100644 --- a/src/libzerocoin/Coin.h +++ b/src/libzerocoin/Coin.h @@ -45,11 +45,11 @@ class PublicCoin PublicCoin(const ZerocoinParams* p); /**Generates a public coin - * - * @param p cryptographic paramters - * @param coin the value of the commitment. - * @param denomination The denomination of the coin. - */ + * + * @param p cryptographic paramters + * @param coin the value of the commitment. + * @param denomination The denomination of the coin. + */ PublicCoin(const ZerocoinParams* p, const CBigNum& coin, const CoinDenomination d); const CBigNum& getValue() const { return this->value; } @@ -141,31 +141,31 @@ class PrivateCoin CPrivKey privkey; /** - * @brief Mint a new coin. - * @param denomination the denomination of the coin to mint - * @throws ZerocoinException if the process takes too long - * - * Generates a new Zerocoin by (a) selecting a random serial - * number, (b) committing to this serial number and repeating until - * the resulting commitment is prime. Stores the - * resulting commitment (coin) and randomness (trapdoor). - **/ + * @brief Mint a new coin. + * @param denomination the denomination of the coin to mint + * @throws ZerocoinException if the process takes too long + * + * Generates a new Zerocoin by (a) selecting a random serial + * number, (b) committing to this serial number and repeating until + * the resulting commitment is prime. Stores the + * resulting commitment (coin) and randomness (trapdoor). + **/ void mintCoin(const CoinDenomination denomination); /** - * @brief Mint a new coin using a faster process. - * @param denomination the denomination of the coin to mint - * @throws ZerocoinException if the process takes too long - * - * Generates a new Zerocoin by (a) selecting a random serial - * number, (b) committing to this serial number and repeating until - * the resulting commitment is prime. Stores the - * resulting commitment (coin) and randomness (trapdoor). - * This routine is substantially faster than the - * mintCoin() routine, but could be more vulnerable - * to timing attacks. Don't use it if you think someone - * could be timing your coin minting. - **/ + * @brief Mint a new coin using a faster process. + * @param denomination the denomination of the coin to mint + * @throws ZerocoinException if the process takes too long + * + * Generates a new Zerocoin by (a) selecting a random serial + * number, (b) committing to this serial number and repeating until + * the resulting commitment is prime. Stores the + * resulting commitment (coin) and randomness (trapdoor). + * This routine is substantially faster than the + * mintCoin() routine, but could be more vulnerable + * to timing attacks. Don't use it if you think someone + * could be timing your coin minting. + **/ void mintCoinFast(const CoinDenomination denomination); }; diff --git a/src/libzerocoin/CoinSpend.h b/src/libzerocoin/CoinSpend.h index 55ccca415b83..d2bf1baaa95c 100644 --- a/src/libzerocoin/CoinSpend.h +++ b/src/libzerocoin/CoinSpend.h @@ -60,53 +60,53 @@ class CoinSpend } /**Generates a proof spending a zerocoin. - * - * To use this, provide an unspent PrivateCoin, the latest Accumulator - * (e.g from the most recent Bitcoin block) containing the public part - * of the coin, a witness to that, and whatever medeta data is needed. - * - * Once constructed, this proof can be serialized and sent. - * It is validated simply be calling validate. - * @warning Validation only checks that the proof is correct - * @warning for the specified values in this class. These values must be validated - * Clients ought to check that - * 1) params is the right params - * 2) the accumulator actually is in some block - * 3) that the serial number is unspent - * 4) that the transaction - * - * @param p cryptographic parameters - * @param coin The coin to be spend - * @param a The current accumulator containing the coin - * @param witness The witness showing that the accumulator contains the coin - * @param a hash of the partial transaction that contains this coin spend - * @throw ZerocoinException if the process fails - */ + * + * To use this, provide an unspent PrivateCoin, the latest Accumulator + * (e.g from the most recent Bitcoin block) containing the public part + * of the coin, a witness to that, and whatever medeta data is needed. + * + * Once constructed, this proof can be serialized and sent. + * It is validated simply be calling validate. + * @warning Validation only checks that the proof is correct + * @warning for the specified values in this class. These values must be validated + * Clients ought to check that + * 1) params is the right params + * 2) the accumulator actually is in some block + * 3) that the serial number is unspent + * 4) that the transaction + * + * @param p cryptographic parameters + * @param coin The coin to be spend + * @param a The current accumulator containing the coin + * @param witness The witness showing that the accumulator contains the coin + * @param a hash of the partial transaction that contains this coin spend + * @throw ZerocoinException if the process fails + */ CoinSpend(const ZerocoinParams* paramsCoin, const ZerocoinParams* paramsAcc, const PrivateCoin& coin, Accumulator& a, const uint32_t& checksum, const AccumulatorWitness& witness, const uint256& ptxHash, const SpendType& spendType); /** Returns the serial number of the coin spend by this proof. - * - * @return the coin's serial number - */ + * + * @return the coin's serial number + */ const CBigNum& getCoinSerialNumber() const { return this->coinSerialNumber; } /**Gets the denomination of the coin spent in this proof. - * - * @return the denomination - */ + * + * @return the denomination + */ CoinDenomination getDenomination() const { return this->denomination; } /**Gets the checksum of the accumulator used in this proof. - * - * @return the checksum - */ + * + * @return the checksum + */ uint32_t getAccumulatorChecksum() const { return this->accChecksum; } /**Gets the txout hash used in this proof. - * - * @return the txout hash - */ + * + * @return the txout hash + */ uint256 getTxOutHash() const { return ptxHash; } CBigNum getAccCommitment() const { return accCommitmentToCoinValue; } CBigNum getSerialComm() const { return serialCommitmentToCoinValue; } diff --git a/src/libzerocoin/Commitment.cpp b/src/libzerocoin/Commitment.cpp index 6b8f1212d553..c6783ef4ee56 100644 --- a/src/libzerocoin/Commitment.cpp +++ b/src/libzerocoin/Commitment.cpp @@ -19,9 +19,9 @@ namespace libzerocoin { //Commitment class Commitment::Commitment(const IntegerGroupParams* p, const CBigNum& value): params(p), contents(value) { - this->randomness = CBigNum::randBignum(params->groupOrder); - this->commitmentValue = (params->g.pow_mod(this->contents, params->modulus).mul_mod( - params->h.pow_mod(this->randomness, params->modulus), params->modulus)); + this->randomness = CBigNum::randBignum(params->groupOrder); + this->commitmentValue = (params->g.pow_mod(this->contents, params->modulus).mul_mod( + params->h.pow_mod(this->randomness, params->modulus), params->modulus)); } Commitment::Commitment(const IntegerGroupParams* p, const CBigNum& bnSerial, const CBigNum& bnRandomness): params(p), contents(bnSerial) { @@ -31,15 +31,15 @@ Commitment::Commitment(const IntegerGroupParams* p, const CBigNum& bnSerial, con } const CBigNum& Commitment::getCommitmentValue() const { - return this->commitmentValue; + return this->commitmentValue; } const CBigNum& Commitment::getRandomness() const { - return this->randomness; + return this->randomness; } const CBigNum& Commitment::getContents() const { - return this->contents; + return this->contents; } //CommitmentProofOfKnowledge class @@ -48,127 +48,127 @@ CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* // TODO: get parameters from the commitment group CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b): - ap(aParams),bp(bParams) + ap(aParams),bp(bParams) { - CBigNum r1, r2, r3; - - // First: make sure that the two commitments have the - // same contents. - if (a.getContents() != b.getContents()) { - throw std::runtime_error("Both commitments must contain the same value"); - } - - // Select three random values "r1, r2, r3" in the range 0 to (2^l)-1 where l is: - // length of challenge value + max(modulus 1, modulus 2, order 1, order 2) + margin. - // We set "margin" to be a relatively generous security parameter. - // - // We choose these large values to ensure statistical zero knowledge. - uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + - std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), - std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize())); - CBigNum maxRange = (CBigNum(2).pow(randomSize) - CBigNum(1)); - - r1 = CBigNum::randBignum(maxRange); - r2 = CBigNum::randBignum(maxRange); - r3 = CBigNum::randBignum(maxRange); - - // Generate two random, ephemeral commitments "T1, T2" - // of the form: - // T1 = g1^r1 * h1^r2 mod p1 - // T2 = g2^r1 * h2^r3 mod p2 - // - // Where (g1, h1, p1) are from "aParams" and (g2, h2, p2) are from "bParams". - CBigNum T1 = this->ap->g.pow_mod(r1, this->ap->modulus).mul_mod((this->ap->h.pow_mod(r2, this->ap->modulus)), this->ap->modulus); - CBigNum T2 = this->bp->g.pow_mod(r1, this->bp->modulus).mul_mod((this->bp->h.pow_mod(r3, this->bp->modulus)), this->bp->modulus); - - // Now hash commitment "A" with commitment "B" as well as the - // parameters and the two ephemeral commitments "T1, T2" we just generated - this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2); - - // Let "m" be the contents of the commitments "A, B". We have: - // A = g1^m * h1^x mod p1 - // B = g2^m * h2^y mod p2 - // T1 = g1^r1 * h1^r2 mod p1 - // T2 = g2^r1 * h2^r3 mod p2 - // - // Now compute: - // S1 = r1 + (m * challenge) -- note, not modular arithmetic - // S2 = r2 + (x * challenge) -- note, not modular arithmetic - // S3 = r3 + (y * challenge) -- note, not modular arithmetic - this->S1 = r1 + (a.getContents() * this->challenge); - this->S2 = r2 + (a.getRandomness() * this->challenge); - this->S3 = r3 + (b.getRandomness() * this->challenge); - - // We're done. The proof is S1, S2, S3 and "challenge", all of which - // are stored in member variables. + CBigNum r1, r2, r3; + + // First: make sure that the two commitments have the + // same contents. + if (a.getContents() != b.getContents()) { + throw std::runtime_error("Both commitments must contain the same value"); + } + + // Select three random values "r1, r2, r3" in the range 0 to (2^l)-1 where l is: + // length of challenge value + std::max(modulus 1, modulus 2, order 1, order 2) + margin. + // We set "margin" to be a relatively generous security parameter. + // + // We choose these large values to ensure statistical zero knowledge. + uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + + std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), + std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize())); + CBigNum maxRange = (CBigNum(2).pow(randomSize) - CBigNum(1)); + + r1 = CBigNum::randBignum(maxRange); + r2 = CBigNum::randBignum(maxRange); + r3 = CBigNum::randBignum(maxRange); + + // Generate two random, ephemeral commitments "T1, T2" + // of the form: + // T1 = g1^r1 * h1^r2 mod p1 + // T2 = g2^r1 * h2^r3 mod p2 + // + // Where (g1, h1, p1) are from "aParams" and (g2, h2, p2) are from "bParams". + CBigNum T1 = this->ap->g.pow_mod(r1, this->ap->modulus).mul_mod((this->ap->h.pow_mod(r2, this->ap->modulus)), this->ap->modulus); + CBigNum T2 = this->bp->g.pow_mod(r1, this->bp->modulus).mul_mod((this->bp->h.pow_mod(r3, this->bp->modulus)), this->bp->modulus); + + // Now hash commitment "A" with commitment "B" as well as the + // parameters and the two ephemeral commitments "T1, T2" we just generated + this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2); + + // Let "m" be the contents of the commitments "A, B". We have: + // A = g1^m * h1^x mod p1 + // B = g2^m * h2^y mod p2 + // T1 = g1^r1 * h1^r2 mod p1 + // T2 = g2^r1 * h2^r3 mod p2 + // + // Now compute: + // S1 = r1 + (m * challenge) -- note, not modular arithmetic + // S2 = r2 + (x * challenge) -- note, not modular arithmetic + // S3 = r3 + (y * challenge) -- note, not modular arithmetic + this->S1 = r1 + (a.getContents() * this->challenge); + this->S2 = r2 + (a.getRandomness() * this->challenge); + this->S3 = r3 + (b.getRandomness() * this->challenge); + + // We're done. The proof is S1, S2, S3 and "challenge", all of which + // are stored in member variables. } bool CommitmentProofOfKnowledge::Verify(const CBigNum& A, const CBigNum& B) const { - // Compute the maximum range of S1, S2, S3 and verify that the given values are - // in a correct range. This might be an unnecessary check. - uint32_t maxSize = 64 * (COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + - std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), - std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize()))); - - if ((uint32_t)this->S1.bitSize() > maxSize || - (uint32_t)this->S2.bitSize() > maxSize || - (uint32_t)this->S3.bitSize() > maxSize || - this->S1 < CBigNum(0) || - this->S2 < CBigNum(0) || - this->S3 < CBigNum(0) || - this->challenge < CBigNum(0) || - this->challenge > (CBigNum(2).pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - CBigNum(1))) { - // Invalid inputs. Reject. - return false; - } - - // Compute T1 = g1^S1 * h1^S2 * inverse(A^{challenge}) mod p1 - CBigNum T1 = A.pow_mod(this->challenge, ap->modulus).inverse(ap->modulus).mul_mod( - (ap->g.pow_mod(S1, ap->modulus).mul_mod(ap->h.pow_mod(S2, ap->modulus), ap->modulus)), - ap->modulus); - - // Compute T2 = g2^S1 * h2^S3 * inverse(B^{challenge}) mod p2 - CBigNum T2 = B.pow_mod(this->challenge, bp->modulus).inverse(bp->modulus).mul_mod( - (bp->g.pow_mod(S1, bp->modulus).mul_mod(bp->h.pow_mod(S3, bp->modulus), bp->modulus)), - bp->modulus); - - // Hash T1 and T2 along with all of the public parameters - CBigNum computedChallenge = calculateChallenge(A, B, T1, T2); - - // Return success if the computed challenge matches the incoming challenge - return computedChallenge == this->challenge; + // Compute the maximum range of S1, S2, S3 and verify that the given values are + // in a correct range. This might be an unnecessary check. + uint32_t maxSize = 64 * (COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + + std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), + std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize()))); + + if ((uint32_t)this->S1.bitSize() > maxSize || + (uint32_t)this->S2.bitSize() > maxSize || + (uint32_t)this->S3.bitSize() > maxSize || + this->S1 < CBigNum(0) || + this->S2 < CBigNum(0) || + this->S3 < CBigNum(0) || + this->challenge < CBigNum(0) || + this->challenge > (CBigNum(2).pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - CBigNum(1))) { + // Invalid inputs. Reject. + return false; + } + + // Compute T1 = g1^S1 * h1^S2 * inverse(A^{challenge}) mod p1 + CBigNum T1 = A.pow_mod(this->challenge, ap->modulus).inverse(ap->modulus).mul_mod( + (ap->g.pow_mod(S1, ap->modulus).mul_mod(ap->h.pow_mod(S2, ap->modulus), ap->modulus)), + ap->modulus); + + // Compute T2 = g2^S1 * h2^S3 * inverse(B^{challenge}) mod p2 + CBigNum T2 = B.pow_mod(this->challenge, bp->modulus).inverse(bp->modulus).mul_mod( + (bp->g.pow_mod(S1, bp->modulus).mul_mod(bp->h.pow_mod(S3, bp->modulus), bp->modulus)), + bp->modulus); + + // Hash T1 and T2 along with all of the public parameters + CBigNum computedChallenge = calculateChallenge(A, B, T1, T2); + + // Return success if the computed challenge matches the incoming challenge + return computedChallenge == this->challenge; } const CBigNum CommitmentProofOfKnowledge::calculateChallenge(const CBigNum& a, const CBigNum& b, const CBigNum &commitOne, const CBigNum &commitTwo) const { - CHashWriter hasher(0,0); - - // Hash together the following elements: - // * A string identifying the proof - // * Commitment A - // * Commitment B - // * Ephemeral commitment T1 - // * Ephemeral commitment T2 - // * A serialized instance of the commitment A parameters - // * A serialized instance of the commitment B parameters - - hasher << std::string(ZEROCOIN_COMMITMENT_EQUALITY_PROOF); - hasher << commitOne; - hasher << std::string("||"); - hasher << commitTwo; - hasher << std::string("||"); - hasher << a; - hasher << std::string("||"); - hasher << b; - hasher << std::string("||"); - hasher << *(this->ap); - hasher << std::string("||"); - hasher << *(this->bp); - - // Convert the SHA256 result into a Bignum - // Note that if we ever change the size of the hash function we will have - // to update COMMITMENT_EQUALITY_CHALLENGE_SIZE appropriately! - return CBigNum(hasher.GetHash()); + CHashWriter hasher(0,0); + + // Hash together the following elements: + // * A string identifying the proof + // * Commitment A + // * Commitment B + // * Ephemeral commitment T1 + // * Ephemeral commitment T2 + // * A serialized instance of the commitment A parameters + // * A serialized instance of the commitment B parameters + + hasher << std::string(ZEROCOIN_COMMITMENT_EQUALITY_PROOF); + hasher << commitOne; + hasher << std::string("||"); + hasher << commitTwo; + hasher << std::string("||"); + hasher << a; + hasher << std::string("||"); + hasher << b; + hasher << std::string("||"); + hasher << *(this->ap); + hasher << std::string("||"); + hasher << *(this->bp); + + // Convert the SHA256 result into a Bignum + // Note that if we ever change the size of the hash function we will have + // to update COMMITMENT_EQUALITY_CHALLENGE_SIZE appropriately! + return CBigNum(hasher.GetHash()); } } /* namespace libzerocoin */ diff --git a/src/libzerocoin/Commitment.h b/src/libzerocoin/Commitment.h index 572c3367b7c6..5e5594b08050 100644 --- a/src/libzerocoin/Commitment.h +++ b/src/libzerocoin/Commitment.h @@ -32,27 +32,27 @@ namespace libzerocoin { */ class Commitment { public: - /**Generates a Pedersen commitment to the given value. - * - * @param p the group parameters for the coin - * @param value the value to commit to - */ - Commitment(const IntegerGroupParams* p, const CBigNum& value); + /**Generates a Pedersen commitment to the given value. + * + * @param p the group parameters for the coin + * @param value the value to commit to + */ + Commitment(const IntegerGroupParams* p, const CBigNum& value); explicit Commitment(const IntegerGroupParams* p, const CBigNum& bnSerial, const CBigNum& bnRandomness); - const CBigNum& getCommitmentValue() const; - const CBigNum& getRandomness() const; - const CBigNum& getContents() const; + const CBigNum& getCommitmentValue() const; + const CBigNum& getRandomness() const; + const CBigNum& getContents() const; private: - const IntegerGroupParams *params; - CBigNum commitmentValue; - CBigNum randomness; - const CBigNum contents; - ADD_SERIALIZE_METHODS; + const IntegerGroupParams *params; + CBigNum commitmentValue; + CBigNum randomness; + const CBigNum contents; + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(commitmentValue); - READWRITE(randomness); - READWRITE(contents); - } + READWRITE(commitmentValue); + READWRITE(randomness); + READWRITE(contents); + } }; /**Proof that two commitments open to the same value. @@ -60,47 +60,47 @@ class Commitment { */ class CommitmentProofOfKnowledge { public: - CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp); - /** Generates a proof that two commitments, a and b, open to the same value. - * - * @param ap the IntegerGroup for commitment a - * @param bp the IntegerGroup for commitment b - * @param a the first commitment - * @param b the second commitment - */ - CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b); - //FIXME: is it best practice that this is here? - template - CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, - const IntegerGroupParams* bParams, Stream& strm): ap(aParams), bp(bParams) - { - strm >> *this; - } + CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp); + /** Generates a proof that two commitments, a and b, open to the same value. + * + * @param ap the IntegerGroup for commitment a + * @param bp the IntegerGroup for commitment b + * @param a the first commitment + * @param b the second commitment + */ + CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b); + //FIXME: is it best practice that this is here? + template + CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, + const IntegerGroupParams* bParams, Stream& strm): ap(aParams), bp(bParams) + { + strm >> *this; + } - const CBigNum calculateChallenge(const CBigNum& a, const CBigNum& b, const CBigNum &commitOne, const CBigNum &commitTwo) const; + const CBigNum calculateChallenge(const CBigNum& a, const CBigNum& b, const CBigNum &commitOne, const CBigNum &commitTwo) const; - /**Verifies the proof - * - * @return true if the proof is valid. - */ - /**Verifies the proof of equality of the two commitments - * - * @param A value of commitment one - * @param B value of commitment two - * @return - */ - bool Verify(const CBigNum& A, const CBigNum& B) const; - ADD_SERIALIZE_METHODS; + /**Verifies the proof + * + * @return true if the proof is valid. + */ + /**Verifies the proof of equality of the two commitments + * + * @param A value of commitment one + * @param B value of commitment two + * @return + */ + bool Verify(const CBigNum& A, const CBigNum& B) const; + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(S1); - READWRITE(S2); - READWRITE(S3); - READWRITE(challenge); - } + READWRITE(S1); + READWRITE(S2); + READWRITE(S3); + READWRITE(challenge); + } private: - const IntegerGroupParams *ap, *bp; + const IntegerGroupParams *ap, *bp; - CBigNum S1, S2, S3, challenge; + CBigNum S1, S2, S3, challenge; }; } /* namespace libzerocoin */ diff --git a/src/libzerocoin/Denominations.cpp b/src/libzerocoin/Denominations.cpp index 57e4aa39f83c..b48f58af621f 100644 --- a/src/libzerocoin/Denominations.cpp +++ b/src/libzerocoin/Denominations.cpp @@ -18,10 +18,10 @@ CoinDenomination IntToZerocoinDenomination(int64_t amount) { CoinDenomination denomination; switch (amount) { - case 1: denomination = CoinDenomination::ZQ_ONE; break; - case 5: denomination = CoinDenomination::ZQ_FIVE; break; - case 10: denomination = CoinDenomination::ZQ_TEN; break; - case 50: denomination = CoinDenomination::ZQ_FIFTY; break; + case 1: denomination = CoinDenomination::ZQ_ONE; break; + case 5: denomination = CoinDenomination::ZQ_FIVE; break; + case 10: denomination = CoinDenomination::ZQ_TEN; break; + case 50: denomination = CoinDenomination::ZQ_FIFTY; break; case 100: denomination = CoinDenomination::ZQ_ONE_HUNDRED; break; case 500: denomination = CoinDenomination::ZQ_FIVE_HUNDRED; break; case 1000: denomination = CoinDenomination::ZQ_ONE_THOUSAND; break; diff --git a/src/libzerocoin/ParamGeneration.cpp b/src/libzerocoin/ParamGeneration.cpp index b6000369d5ed..581e12679d14 100644 --- a/src/libzerocoin/ParamGeneration.cpp +++ b/src/libzerocoin/ParamGeneration.cpp @@ -15,8 +15,6 @@ #include "hash.h" #include "uint256.h" -using namespace std; - namespace libzerocoin { /// \brief Fill in a set of Zerocoin parameters from a modulus "N". @@ -38,80 +36,80 @@ namespace libzerocoin { /// void -CalculateParams(ZerocoinParams ¶ms, CBigNum N, string aux, uint32_t securityLevel) +CalculateParams(ZerocoinParams ¶ms, CBigNum N, std::string aux, uint32_t securityLevel) { - params.initialized = false; - params.accumulatorParams.initialized = false; - - // Verify that |N| is > 1023 bits. - uint32_t NLen = N.bitSize(); - if (NLen < 1023) { - throw std::runtime_error("Modulus must be at least 1023 bits"); - } - - // Verify that "securityLevel" is at least 80 bits (minimum). - if (securityLevel < 80) { - throw std::runtime_error("Security level must be at least 80 bits."); - } - - // Set the accumulator modulus to "N". - params.accumulatorParams.accumulatorModulus = N; - - // Calculate the required size of the field "F_p" into which - // we're embedding the coin commitment group. This may throw an - // exception if the securityLevel is too large to be supported - // by the current modulus. - uint32_t pLen = 0; - uint32_t qLen = 0; - calculateGroupParamLengths(NLen - 2, securityLevel, &pLen, &qLen); - - // Calculate candidate parameters ("p", "q") for the coin commitment group - // using a deterministic process based on "N", the "aux" string, and - // the dedicated string "COMMITMENTGROUP". - params.coinCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_COMMIT_GROUP), - pLen, qLen); - - // Next, we derive parameters for a second Accumulated Value commitment group. - // This is a Schnorr group with the specific property that the order of the group - // must be exactly equal to "q" from the commitment group. We set - // the modulus of the new group equal to "2q+1" and test to see if this is prime. - params.serialNumberSoKCommitmentGroup = deriveIntegerGroupFromOrder(params.coinCommitmentGroup.modulus); - - // Calculate the parameters for the internal commitment - // using the same process. - params.accumulatorParams.accumulatorPoKCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_AIC_GROUP), - qLen + 300, qLen + 1); - - // Calculate the parameters for the accumulator QRN commitment generators. This isn't really - // a whole group, just a pair of random generators in QR_N. - uint32_t resultCtr; - params.accumulatorParams.accumulatorQRNCommitmentGroup.g = generateIntegerFromSeed(NLen - 1, - calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPG), - &resultCtr).pow_mod(CBigNum(2),N); - params.accumulatorParams.accumulatorQRNCommitmentGroup.h = generateIntegerFromSeed(NLen - 1, - calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPH), - &resultCtr).pow_mod(CBigNum(2), N); - - // Calculate the accumulator base, which we calculate as "u = C**2 mod N" - // where C is an arbitrary value. In the unlikely case that "u = 1" we increment - // "C" and repeat. - CBigNum constant(ACCUMULATOR_BASE_CONSTANT); - params.accumulatorParams.accumulatorBase = CBigNum(1); - for (uint32_t count = 0; count < MAX_ACCUMGEN_ATTEMPTS && params.accumulatorParams.accumulatorBase.isOne(); count++) { - params.accumulatorParams.accumulatorBase = constant.pow_mod(CBigNum(2), params.accumulatorParams.accumulatorModulus); - } - - // Compute the accumulator range. The upper range is the largest possible coin commitment value. - // The lower range is sqrt(upper range) + 1. Since OpenSSL doesn't have - // a square root function we use a slightly higher approximation. - params.accumulatorParams.maxCoinValue = params.coinCommitmentGroup.modulus; - params.accumulatorParams.minCoinValue = CBigNum(2).pow((params.coinCommitmentGroup.modulus.bitSize() / 2) + 3); - - // If all went well, mark params as successfully initialized. - params.accumulatorParams.initialized = true; - - // If all went well, mark params as successfully initialized. - params.initialized = true; + params.initialized = false; + params.accumulatorParams.initialized = false; + + // Verify that |N| is > 1023 bits. + uint32_t NLen = N.bitSize(); + if (NLen < 1023) { + throw std::runtime_error("Modulus must be at least 1023 bits"); + } + + // Verify that "securityLevel" is at least 80 bits (minimum). + if (securityLevel < 80) { + throw std::runtime_error("Security level must be at least 80 bits."); + } + + // Set the accumulator modulus to "N". + params.accumulatorParams.accumulatorModulus = N; + + // Calculate the required size of the field "F_p" into which + // we're embedding the coin commitment group. This may throw an + // exception if the securityLevel is too large to be supported + // by the current modulus. + uint32_t pLen = 0; + uint32_t qLen = 0; + calculateGroupParamLengths(NLen - 2, securityLevel, &pLen, &qLen); + + // Calculate candidate parameters ("p", "q") for the coin commitment group + // using a deterministic process based on "N", the "aux" string, and + // the dedicated string "COMMITMENTGROUP". + params.coinCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_COMMIT_GROUP), + pLen, qLen); + + // Next, we derive parameters for a second Accumulated Value commitment group. + // This is a Schnorr group with the specific property that the order of the group + // must be exactly equal to "q" from the commitment group. We set + // the modulus of the new group equal to "2q+1" and test to see if this is prime. + params.serialNumberSoKCommitmentGroup = deriveIntegerGroupFromOrder(params.coinCommitmentGroup.modulus); + + // Calculate the parameters for the internal commitment + // using the same process. + params.accumulatorParams.accumulatorPoKCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_AIC_GROUP), + qLen + 300, qLen + 1); + + // Calculate the parameters for the accumulator QRN commitment generators. This isn't really + // a whole group, just a pair of random generators in QR_N. + uint32_t resultCtr; + params.accumulatorParams.accumulatorQRNCommitmentGroup.g = generateIntegerFromSeed(NLen - 1, + calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPG), + &resultCtr).pow_mod(CBigNum(2),N); + params.accumulatorParams.accumulatorQRNCommitmentGroup.h = generateIntegerFromSeed(NLen - 1, + calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPH), + &resultCtr).pow_mod(CBigNum(2), N); + + // Calculate the accumulator base, which we calculate as "u = C**2 mod N" + // where C is an arbitrary value. In the unlikely case that "u = 1" we increment + // "C" and repeat. + CBigNum constant(ACCUMULATOR_BASE_CONSTANT); + params.accumulatorParams.accumulatorBase = CBigNum(1); + for (uint32_t count = 0; count < MAX_ACCUMGEN_ATTEMPTS && params.accumulatorParams.accumulatorBase.isOne(); count++) { + params.accumulatorParams.accumulatorBase = constant.pow_mod(CBigNum(2), params.accumulatorParams.accumulatorModulus); + } + + // Compute the accumulator range. The upper range is the largest possible coin commitment value. + // The lower range is sqrt(upper range) + 1. Since OpenSSL doesn't have + // a square root function we use a slightly higher approximation. + params.accumulatorParams.maxCoinValue = params.coinCommitmentGroup.modulus; + params.accumulatorParams.minCoinValue = CBigNum(2).pow((params.coinCommitmentGroup.modulus.bitSize() / 2) + 3); + + // If all went well, mark params as successfully initialized. + params.accumulatorParams.initialized = true; + + // If all went well, mark params as successfully initialized. + params.initialized = true; } /// \brief Format a seed string by hashing several values. @@ -124,26 +122,26 @@ CalculateParams(ZerocoinParams ¶ms, CBigNum N, string aux, uint32_t security /// Returns the hash of the value. uint256 -calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, string label, uint32_t index, uint32_t count) +calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, std::string label, uint32_t index, uint32_t count) { - CHashWriter hasher(0,0); - uint256 hash; - - // Compute the hash of: - // ||||||groupName - hasher << seed; - hasher << string("||"); - hasher << pSeed; - hasher << string("||"); - hasher << qSeed; - hasher << string("||"); - hasher << label; - hasher << string("||"); - hasher << index; - hasher << string("||"); - hasher << count; - - return hasher.GetHash(); + CHashWriter hasher(0,0); + uint256 hash; + + // Compute the hash of: + // ||||||groupName + hasher << seed; + hasher << std::string("||"); + hasher << pSeed; + hasher << std::string("||"); + hasher << qSeed; + hasher << std::string("||"); + hasher << label; + hasher << std::string("||"); + hasher << index; + hasher << std::string("||"); + hasher << count; + + return hasher.GetHash(); } /// \brief Format a seed string by hashing several values. @@ -156,33 +154,33 @@ calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, string label, /// Returns the hash of the value. uint256 -calculateSeed(CBigNum modulus, string auxString, uint32_t securityLevel, string groupName) +calculateSeed(CBigNum modulus, std::string auxString, uint32_t securityLevel, std::string groupName) { - CHashWriter hasher(0,0); - uint256 hash; - - // Compute the hash of: - // ||||||groupName - hasher << modulus; - hasher << string("||"); - hasher << securityLevel; - hasher << string("||"); - hasher << auxString; - hasher << string("||"); - hasher << groupName; - - return hasher.GetHash(); + CHashWriter hasher(0,0); + uint256 hash; + + // Compute the hash of: + // ||||||groupName + hasher << modulus; + hasher << std::string("||"); + hasher << securityLevel; + hasher << std::string("||"); + hasher << auxString; + hasher << std::string("||"); + hasher << groupName; + + return hasher.GetHash(); } uint256 calculateHash(uint256 input) { - CHashWriter hasher(0,0); + CHashWriter hasher(0,0); - // Compute the hash of "input" - hasher << input; + // Compute the hash of "input" + hasher << input; - return hasher.GetHash(); + return hasher.GetHash(); } /// \brief Calculate field/group parameter sizes based on a security level. @@ -208,26 +206,26 @@ void calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel, uint32_t *pLen, uint32_t *qLen) { - *pLen = *qLen = 0; - - if (securityLevel < 80) { - throw std::runtime_error("Security level must be at least 80 bits."); - } else if (securityLevel == 80) { - *qLen = 256; - *pLen = 1024; - } else if (securityLevel <= 112) { - *qLen = 256; - *pLen = 2048; - } else if (securityLevel <= 128) { - *qLen = 320; - *pLen = 3072; - } else { - throw std::runtime_error("Security level not supported."); - } - - if (*pLen > maxPLen) { - throw std::runtime_error("Modulus size is too small for this security level."); - } + *pLen = *qLen = 0; + + if (securityLevel < 80) { + throw std::runtime_error("Security level must be at least 80 bits."); + } else if (securityLevel == 80) { + *qLen = 256; + *pLen = 1024; + } else if (securityLevel <= 112) { + *qLen = 256; + *pLen = 2048; + } else if (securityLevel <= 128) { + *qLen = 320; + *pLen = 3072; + } else { + throw std::runtime_error("Security level not supported."); + } + + if (*pLen > maxPLen) { + throw std::runtime_error("Modulus size is too small for this security level."); + } } /// \brief Deterministically compute a set of group parameters using NIST procedures. @@ -245,40 +243,40 @@ calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel, IntegerGroupParams deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen) { - IntegerGroupParams result; - CBigNum p; - CBigNum q; - uint256 pSeed, qSeed; - - // Calculate "p" and "q" and "domain_parameter_seed" from the - // "seed" buffer above, using the procedure described in NIST - // FIPS 186-3, Appendix A.1.2. - calculateGroupModulusAndOrder(seed, pLen, qLen, &(result.modulus), - &(result.groupOrder), &pSeed, &qSeed); - - // Calculate the generators "g", "h" using the process described in - // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q", - // "domain_parameter_seed", "index"). We use "index" value 1 - // to generate "g" and "index" value 2 to generate "h". - result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1); - result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2); - - // Perform some basic tests to make sure we have good parameters - if ((uint32_t)(result.modulus.bitSize()) < pLen || // modulus is pLen bits long - (uint32_t)(result.groupOrder.bitSize()) < qLen || // order is qLen bits long - !(result.modulus.isPrime()) || // modulus is prime - !(result.groupOrder.isPrime()) || // order is prime - !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1 - !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1 - ((result.g.pow_mod(CBigNum(100), result.modulus)).isOne()) || // g^100 mod modulus != 1 - ((result.h.pow_mod(CBigNum(100), result.modulus)).isOne()) || // h^100 mod modulus != 1 - result.g == result.h || // g != h - result.g.isOne()) { // g != 1 - // If any of the above tests fail, throw an exception - throw std::runtime_error("Group parameters are not valid"); - } - - return result; + IntegerGroupParams result; + CBigNum p; + CBigNum q; + uint256 pSeed, qSeed; + + // Calculate "p" and "q" and "domain_parameter_seed" from the + // "seed" buffer above, using the procedure described in NIST + // FIPS 186-3, Appendix A.1.2. + calculateGroupModulusAndOrder(seed, pLen, qLen, &(result.modulus), + &(result.groupOrder), &pSeed, &qSeed); + + // Calculate the generators "g", "h" using the process described in + // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q", + // "domain_parameter_seed", "index"). We use "index" value 1 + // to generate "g" and "index" value 2 to generate "h". + result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1); + result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2); + + // Perform some basic tests to make sure we have good parameters + if ((uint32_t)(result.modulus.bitSize()) < pLen || // modulus is pLen bits long + (uint32_t)(result.groupOrder.bitSize()) < qLen || // order is qLen bits long + !(result.modulus.isPrime()) || // modulus is prime + !(result.groupOrder.isPrime()) || // order is prime + !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1 + !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1 + ((result.g.pow_mod(CBigNum(100), result.modulus)).isOne()) || // g^100 mod modulus != 1 + ((result.h.pow_mod(CBigNum(100), result.modulus)).isOne()) || // h^100 mod modulus != 1 + result.g == result.h || // g != h + result.g.isOne()) { // g != 1 + // If any of the above tests fail, throw an exception + throw std::runtime_error("Group parameters are not valid"); + } + + return result; } /// \brief Deterministically compute a set of group parameters with a specified order. @@ -291,52 +289,52 @@ deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen) IntegerGroupParams deriveIntegerGroupFromOrder(CBigNum &groupOrder) { - IntegerGroupParams result; - - // Set the order to "groupOrder" - result.groupOrder = groupOrder; - - // Try possible values for "modulus" of the form "groupOrder * 2 * i" where - // "p" is prime and i is a counter starting at 1. - for (uint32_t i = 1; i < NUM_SCHNORRGEN_ATTEMPTS; i++) { - // Set modulus equal to "groupOrder * 2 * i" - result.modulus = (result.groupOrder * CBigNum(i*2)) + CBigNum(1); - - // Test the result for primality - // TODO: This is a probabilistic routine and thus not the right choice - if (result.modulus.isPrime(256)) { - - // Success. - // - // Calculate the generators "g", "h" using the process described in - // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q", - // "domain_parameter_seed", "index"). We use "index" value 1 - // to generate "g" and "index" value 2 to generate "h". - uint256 seed = calculateSeed(groupOrder, "", 128, ""); - uint256 pSeed = calculateHash(seed); - uint256 qSeed = calculateHash(pSeed); - result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1); - result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2); - - // Perform some basic tests to make sure we have good parameters - if (!(result.modulus.isPrime()) || // modulus is prime - !(result.groupOrder.isPrime()) || // order is prime - !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1 - !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1 - ((result.g.pow_mod(CBigNum(100), result.modulus)).isOne()) || // g^100 mod modulus != 1 - ((result.h.pow_mod(CBigNum(100), result.modulus)).isOne()) || // h^100 mod modulus != 1 - result.g == result.h || // g != h - result.g.isOne()) { // g != 1 - // If any of the above tests fail, throw an exception - throw std::runtime_error("Group parameters are not valid"); - } - - return result; - } - } - - // If we reached this point group generation has failed. Throw an exception. - throw std::runtime_error("Too many attempts to generate Schnorr group."); + IntegerGroupParams result; + + // Set the order to "groupOrder" + result.groupOrder = groupOrder; + + // Try possible values for "modulus" of the form "groupOrder * 2 * i" where + // "p" is prime and i is a counter starting at 1. + for (uint32_t i = 1; i < NUM_SCHNORRGEN_ATTEMPTS; i++) { + // Set modulus equal to "groupOrder * 2 * i" + result.modulus = (result.groupOrder * CBigNum(i*2)) + CBigNum(1); + + // Test the result for primality + // TODO: This is a probabilistic routine and thus not the right choice + if (result.modulus.isPrime(256)) { + + // Success. + // + // Calculate the generators "g", "h" using the process described in + // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q", + // "domain_parameter_seed", "index"). We use "index" value 1 + // to generate "g" and "index" value 2 to generate "h". + uint256 seed = calculateSeed(groupOrder, "", 128, ""); + uint256 pSeed = calculateHash(seed); + uint256 qSeed = calculateHash(pSeed); + result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1); + result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2); + + // Perform some basic tests to make sure we have good parameters + if (!(result.modulus.isPrime()) || // modulus is prime + !(result.groupOrder.isPrime()) || // order is prime + !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1 + !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1 + ((result.g.pow_mod(CBigNum(100), result.modulus)).isOne()) || // g^100 mod modulus != 1 + ((result.h.pow_mod(CBigNum(100), result.modulus)).isOne()) || // h^100 mod modulus != 1 + result.g == result.h || // g != h + result.g.isOne()) { // g != 1 + // If any of the above tests fail, throw an exception + throw std::runtime_error("Group parameters are not valid"); + } + + return result; + } + } + + // If we reached this point group generation has failed. Throw an exception. + throw std::runtime_error("Too many attempts to generate Schnorr group."); } /// \brief Deterministically compute a group description using NIST procedures. @@ -357,88 +355,88 @@ calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen, CBigNum *resultModulus, CBigNum *resultGroupOrder, uint256 *resultPseed, uint256 *resultQseed) { - // Verify that the seed length is >= qLen - if (qLen > (sizeof(seed)) * 8) { - // TODO: The use of 256-bit seeds limits us to 256-bit group orders. We should probably change this. - // throw std::runtime_error("Seed is too short to support the required security level."); - } + // Verify that the seed length is >= qLen + if (qLen > (sizeof(seed)) * 8) { + // TODO: The use of 256-bit seeds limits us to 256-bit group orders. We should probably change this. + // throw std::runtime_error("Seed is too short to support the required security level."); + } #ifdef ZEROCOIN_DEBUG - cout << "calculateGroupModulusAndOrder: pLen = " << pLen << endl; + cout << "calculateGroupModulusAndOrder: pLen = " << pLen << endl; #endif - // Generate a random prime for the group order. - // This may throw an exception, which we'll pass upwards. - // Result is the value "resultGroupOrder", "qseed" and "qgen_counter". - uint256 qseed; - uint32_t qgen_counter; - *resultGroupOrder = generateRandomPrime(qLen, seed, &qseed, &qgen_counter); - - // Using ⎡pLen / 2 + 1⎤ as the length and qseed as the input_seed, use the random prime - // routine to obtain p0 , pseed, and pgen_counter. We pass exceptions upward. - uint32_t p0len = ceil((pLen / 2.0) + 1); - uint256 pseed; - uint32_t pgen_counter; - CBigNum p0 = generateRandomPrime(p0len, qseed, &pseed, &pgen_counter); - - // Set x = 0, old_counter = pgen_counter - uint32_t old_counter = pgen_counter; - - // Generate a random integer "x" of pLen bits - uint32_t iterations; - CBigNum x = generateIntegerFromSeed(pLen, pseed, &iterations); - pseed += (iterations + 1); - - // Set x = 2^{pLen−1} + (x mod 2^{pLen–1}). - CBigNum powerOfTwo = CBigNum(2).pow(pLen-1); - x = powerOfTwo + (x % powerOfTwo); - - // t = ⎡x / (2 * resultGroupOrder * p0)⎤. - // TODO: we don't have a ceiling function - CBigNum t = x / (CBigNum(2) * (*resultGroupOrder) * p0); - - // Now loop until we find a valid prime "p" or we fail due to - // pgen_counter exceeding ((4*pLen) + old_counter). - for ( ; pgen_counter <= ((4*pLen) + old_counter) ; pgen_counter++) { - // If (2 * t * resultGroupOrder * p0 + 1) > 2^{pLen}, then - // t = ⎡2^{pLen−1} / (2 * resultGroupOrder * p0)⎤. - powerOfTwo = CBigNum(2).pow(pLen); - CBigNum prod = (CBigNum(2) * t * (*resultGroupOrder) * p0) + CBigNum(1); - if (prod > powerOfTwo) { - // TODO: implement a ceil function - t = CBigNum(2).pow(pLen-1) / (CBigNum(2) * (*resultGroupOrder) * p0); - } - - // Compute a candidate prime resultModulus = 2tqp0 + 1. - *resultModulus = (CBigNum(2) * t * (*resultGroupOrder) * p0) + CBigNum(1); - - // Verify that resultModulus is prime. First generate a pseudorandom integer "a". - CBigNum a = generateIntegerFromSeed(pLen, pseed, &iterations); - pseed += iterations + 1; - - // Set a = 2 + (a mod (resultModulus–3)). - a = CBigNum(2) + (a % ((*resultModulus) - CBigNum(3))); - - // Set z = a^{2 * t * resultGroupOrder} mod resultModulus - CBigNum z = a.pow_mod(CBigNum(2) * t * (*resultGroupOrder), (*resultModulus)); - - // If GCD(z–1, resultModulus) == 1 AND (z^{p0} mod resultModulus == 1) - // then we have found our result. Return. - if ((resultModulus->gcd(z - CBigNum(1))).isOne() && - (z.pow_mod(p0, (*resultModulus))).isOne()) { - // Success! Return the seeds and primes. - *resultPseed = pseed; - *resultQseed = qseed; - return; - } - - // This prime did not work out. Increment "t" and try again. - t = t + CBigNum(1); - } // loop continues until pgen_counter exceeds a limit - - // We reach this point only if we exceeded our maximum iteration count. - // Throw an exception. - throw std::runtime_error("Unable to generate a prime modulus for the group"); + // Generate a random prime for the group order. + // This may throw an exception, which we'll pass upwards. + // Result is the value "resultGroupOrder", "qseed" and "qgen_counter". + uint256 qseed; + uint32_t qgen_counter; + *resultGroupOrder = generateRandomPrime(qLen, seed, &qseed, &qgen_counter); + + // Using ⎡pLen / 2 + 1⎤ as the length and qseed as the input_seed, use the random prime + // routine to obtain p0 , pseed, and pgen_counter. We pass exceptions upward. + uint32_t p0len = ceil((pLen / 2.0) + 1); + uint256 pseed; + uint32_t pgen_counter; + CBigNum p0 = generateRandomPrime(p0len, qseed, &pseed, &pgen_counter); + + // Set x = 0, old_counter = pgen_counter + uint32_t old_counter = pgen_counter; + + // Generate a random integer "x" of pLen bits + uint32_t iterations; + CBigNum x = generateIntegerFromSeed(pLen, pseed, &iterations); + pseed += (iterations + 1); + + // Set x = 2^{pLen−1} + (x mod 2^{pLen–1}). + CBigNum powerOfTwo = CBigNum(2).pow(pLen-1); + x = powerOfTwo + (x % powerOfTwo); + + // t = ⎡x / (2 * resultGroupOrder * p0)⎤. + // TODO: we don't have a ceiling function + CBigNum t = x / (CBigNum(2) * (*resultGroupOrder) * p0); + + // Now loop until we find a valid prime "p" or we fail due to + // pgen_counter exceeding ((4*pLen) + old_counter). + for ( ; pgen_counter <= ((4*pLen) + old_counter) ; pgen_counter++) { + // If (2 * t * resultGroupOrder * p0 + 1) > 2^{pLen}, then + // t = ⎡2^{pLen−1} / (2 * resultGroupOrder * p0)⎤. + powerOfTwo = CBigNum(2).pow(pLen); + CBigNum prod = (CBigNum(2) * t * (*resultGroupOrder) * p0) + CBigNum(1); + if (prod > powerOfTwo) { + // TODO: implement a ceil function + t = CBigNum(2).pow(pLen-1) / (CBigNum(2) * (*resultGroupOrder) * p0); + } + + // Compute a candidate prime resultModulus = 2tqp0 + 1. + *resultModulus = (CBigNum(2) * t * (*resultGroupOrder) * p0) + CBigNum(1); + + // Verify that resultModulus is prime. First generate a pseudorandom integer "a". + CBigNum a = generateIntegerFromSeed(pLen, pseed, &iterations); + pseed += iterations + 1; + + // Set a = 2 + (a mod (resultModulus–3)). + a = CBigNum(2) + (a % ((*resultModulus) - CBigNum(3))); + + // Set z = a^{2 * t * resultGroupOrder} mod resultModulus + CBigNum z = a.pow_mod(CBigNum(2) * t * (*resultGroupOrder), (*resultModulus)); + + // If GCD(z–1, resultModulus) == 1 AND (z^{p0} mod resultModulus == 1) + // then we have found our result. Return. + if ((resultModulus->gcd(z - CBigNum(1))).isOne() && + (z.pow_mod(p0, (*resultModulus))).isOne()) { + // Success! Return the seeds and primes. + *resultPseed = pseed; + *resultQseed = qseed; + return; + } + + // This prime did not work out. Increment "t" and try again. + t = t + CBigNum(1); + } // loop continues until pgen_counter exceeds a limit + + // We reach this point only if we exceeded our maximum iteration count. + // Throw an exception. + throw std::runtime_error("Unable to generate a prime modulus for the group"); } /// \brief Deterministically compute a generator for a given group. @@ -457,33 +455,33 @@ calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen, CBigNum calculateGroupGenerator(uint256 seed, uint256 pSeed, uint256 qSeed, CBigNum modulus, CBigNum groupOrder, uint32_t index) { - CBigNum result; + CBigNum result; - // Verify that 0 <= index < 256 - if (index > 255) { - throw std::runtime_error("Invalid index for group generation"); - } + // Verify that 0 <= index < 256 + if (index > 255) { + throw std::runtime_error("Invalid index for group generation"); + } - // Compute e = (modulus - 1) / groupOrder - CBigNum e = (modulus - CBigNum(1)) / groupOrder; + // Compute e = (modulus - 1) / groupOrder + CBigNum e = (modulus - CBigNum(1)) / groupOrder; - // Loop until we find a generator - for (uint32_t count = 1; count < MAX_GENERATOR_ATTEMPTS; count++) { - // hash = Hash(seed || pSeed || qSeed || “ggen” || index || count - uint256 hash = calculateGeneratorSeed(seed, pSeed, qSeed, "ggen", index, count); - CBigNum W(hash); + // Loop until we find a generator + for (uint32_t count = 1; count < MAX_GENERATOR_ATTEMPTS; count++) { + // hash = Hash(seed || pSeed || qSeed || “ggen” || index || count + uint256 hash = calculateGeneratorSeed(seed, pSeed, qSeed, "ggen", index, count); + CBigNum W(hash); - // Compute result = W^e mod p - result = W.pow_mod(e, modulus); + // Compute result = W^e mod p + result = W.pow_mod(e, modulus); - // If result > 1, we have a generator - if (result > 1) { - return result; - } - } + // If result > 1, we have a generator + if (result > 1) { + return result; + } + } - // We only get here if we failed to find a generator - throw std::runtime_error("Unable to find a generator, too many attempts"); + // We only get here if we failed to find a generator + throw std::runtime_error("Unable to find a generator, too many attempts"); } /// \brief Deterministically compute a random prime number. @@ -502,141 +500,141 @@ CBigNum generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed, uint32_t *prime_gen_counter) { - // Verify that primeBitLen is not too small - if (primeBitLen < 2) { - throw std::runtime_error("Prime length is too short"); - } + // Verify that primeBitLen is not too small + if (primeBitLen < 2) { + throw std::runtime_error("Prime length is too short"); + } - // If primeBitLen < 33 bits, perform the base case. - if (primeBitLen < 33) { - CBigNum result(0); + // If primeBitLen < 33 bits, perform the base case. + if (primeBitLen < 33) { + CBigNum result(0); - // Set prime_seed = in_seed, prime_gen_counter = 0. - uint256 prime_seed = in_seed; - (*prime_gen_counter) = 0; + // Set prime_seed = in_seed, prime_gen_counter = 0. + uint256 prime_seed = in_seed; + (*prime_gen_counter) = 0; - // Loop up to "4 * primeBitLen" iterations. - while ((*prime_gen_counter) < (4 * primeBitLen)) { + // Loop up to "4 * primeBitLen" iterations. + while ((*prime_gen_counter) < (4 * primeBitLen)) { - // Generate a pseudorandom integer "c" of length primeBitLength bits - uint32_t iteration_count; - CBigNum c = generateIntegerFromSeed(primeBitLen, prime_seed, &iteration_count); + // Generate a pseudorandom integer "c" of length primeBitLength bits + uint32_t iteration_count; + CBigNum c = generateIntegerFromSeed(primeBitLen, prime_seed, &iteration_count); #ifdef ZEROCOIN_DEBUG - cout << "generateRandomPrime: primeBitLen = " << primeBitLen << endl; - cout << "Generated c = " << c << endl; + cout << "generateRandomPrime: primeBitLen = " << primeBitLen << endl; + cout << "Generated c = " << c << endl; #endif - prime_seed += (iteration_count + 1); - (*prime_gen_counter)++; + prime_seed += (iteration_count + 1); + (*prime_gen_counter)++; - // Set "intc" to be the least odd integer >= "c" we just generated - uint32_t intc = c.getulong(); - intc = (2 * floor(intc / 2.0)) + 1; + // Set "intc" to be the least odd integer >= "c" we just generated + uint32_t intc = c.getulong(); + intc = (2 * floor(intc / 2.0)) + 1; #ifdef ZEROCOIN_DEBUG - cout << "Should be odd. c = " << intc << endl; - cout << "The big num is: c = " << c << endl; + cout << "Should be odd. c = " << intc << endl; + cout << "The big num is: c = " << c << endl; #endif - // Perform trial division on this (relatively small) integer to determine if "intc" - // is prime. If so, return success. - if (primalityTestByTrialDivision(intc)) { - // Return "intc" converted back into a CBigNum and "prime_seed". We also updated - // the variable "prime_gen_counter" in previous statements. - result = intc; - *out_seed = prime_seed; - - // Success - return result; - } - } // while() - - // If we reached this point there was an error finding a candidate prime - // so throw an exception. - throw std::runtime_error("Unable to find prime in Shawe-Taylor algorithm"); - - // END OF BASE CASE - } - // If primeBitLen >= 33 bits, perform the recursive case. - else { - // Recurse to find a new random prime of roughly half the size - uint32_t newLength = ceil((double)primeBitLen / 2.0) + 1; - CBigNum c0 = generateRandomPrime(newLength, in_seed, out_seed, prime_gen_counter); - - // Generate a random integer "x" of primeBitLen bits using the output - // of the previous call. - uint32_t numIterations; - CBigNum x = generateIntegerFromSeed(primeBitLen, *out_seed, &numIterations); - (*out_seed) += numIterations + 1; - - // Compute "t" = ⎡x / (2 * c0⎤ - // TODO no Ceiling call - CBigNum t = x / (CBigNum(2) * c0); - - // Repeat the following procedure until we find a prime (or time out) - for (uint32_t testNum = 0; testNum < MAX_PRIMEGEN_ATTEMPTS; testNum++) { - - // If ((2 * t * c0) + 1 > 2^{primeBitLen}), - // then t = ⎡2^{primeBitLen} – 1 / (2 * c0)⎤. - if ((CBigNum(2) * t * c0) > (CBigNum(2).pow(CBigNum(primeBitLen)))) { - t = ((CBigNum(2).pow(CBigNum(primeBitLen))) - CBigNum(1)) / (CBigNum(2) * c0); - } - - // Set c = (2 * t * c0) + 1 - CBigNum c = (CBigNum(2) * t * c0) + CBigNum(1); - - // Increment prime_gen_counter - (*prime_gen_counter)++; - - // Test "c" for primality as follows: - // 1. First pick an integer "a" in between 2 and (c - 2) - CBigNum a = generateIntegerFromSeed(c.bitSize(), (*out_seed), &numIterations); - a = CBigNum(2) + (a % (c - CBigNum(3))); - (*out_seed) += (numIterations + 1); - - // 2. Compute "z" = a^{2*t} mod c - CBigNum z = a.pow_mod(CBigNum(2) * t, c); - - // 3. Check if "c" is prime. - // Specifically, verify that gcd((z-1), c) == 1 AND (z^c0 mod c) == 1 - // If so we return "c" as our result. - if (c.gcd(z - CBigNum(1)).isOne() && z.pow_mod(c0, c).isOne()) { - // Return "c", out_seed and prime_gen_counter - // (the latter two of which were already updated) - return c; - } - - // 4. If the test did not succeed, increment "t" and loop - t = t + CBigNum(1); - } // end of test loop - } - - // We only reach this point if the test loop has iterated MAX_PRIMEGEN_ATTEMPTS - // and failed to identify a valid prime. Throw an exception. - throw std::runtime_error("Unable to generate random prime (too many tests)"); + // Perform trial division on this (relatively small) integer to determine if "intc" + // is prime. If so, return success. + if (primalityTestByTrialDivision(intc)) { + // Return "intc" converted back into a CBigNum and "prime_seed". We also updated + // the variable "prime_gen_counter" in previous statements. + result = intc; + *out_seed = prime_seed; + + // Success + return result; + } + } // while() + + // If we reached this point there was an error finding a candidate prime + // so throw an exception. + throw std::runtime_error("Unable to find prime in Shawe-Taylor algorithm"); + + // END OF BASE CASE + } + // If primeBitLen >= 33 bits, perform the recursive case. + else { + // Recurse to find a new random prime of roughly half the size + uint32_t newLength = ceil((double)primeBitLen / 2.0) + 1; + CBigNum c0 = generateRandomPrime(newLength, in_seed, out_seed, prime_gen_counter); + + // Generate a random integer "x" of primeBitLen bits using the output + // of the previous call. + uint32_t numIterations; + CBigNum x = generateIntegerFromSeed(primeBitLen, *out_seed, &numIterations); + (*out_seed) += numIterations + 1; + + // Compute "t" = ⎡x / (2 * c0⎤ + // TODO no Ceiling call + CBigNum t = x / (CBigNum(2) * c0); + + // Repeat the following procedure until we find a prime (or time out) + for (uint32_t testNum = 0; testNum < MAX_PRIMEGEN_ATTEMPTS; testNum++) { + + // If ((2 * t * c0) + 1 > 2^{primeBitLen}), + // then t = ⎡2^{primeBitLen} – 1 / (2 * c0)⎤. + if ((CBigNum(2) * t * c0) > (CBigNum(2).pow(CBigNum(primeBitLen)))) { + t = ((CBigNum(2).pow(CBigNum(primeBitLen))) - CBigNum(1)) / (CBigNum(2) * c0); + } + + // Set c = (2 * t * c0) + 1 + CBigNum c = (CBigNum(2) * t * c0) + CBigNum(1); + + // Increment prime_gen_counter + (*prime_gen_counter)++; + + // Test "c" for primality as follows: + // 1. First pick an integer "a" in between 2 and (c - 2) + CBigNum a = generateIntegerFromSeed(c.bitSize(), (*out_seed), &numIterations); + a = CBigNum(2) + (a % (c - CBigNum(3))); + (*out_seed) += (numIterations + 1); + + // 2. Compute "z" = a^{2*t} mod c + CBigNum z = a.pow_mod(CBigNum(2) * t, c); + + // 3. Check if "c" is prime. + // Specifically, verify that gcd((z-1), c) == 1 AND (z^c0 mod c) == 1 + // If so we return "c" as our result. + if (c.gcd(z - CBigNum(1)).isOne() && z.pow_mod(c0, c).isOne()) { + // Return "c", out_seed and prime_gen_counter + // (the latter two of which were already updated) + return c; + } + + // 4. If the test did not succeed, increment "t" and loop + t = t + CBigNum(1); + } // end of test loop + } + + // We only reach this point if the test loop has iterated MAX_PRIMEGEN_ATTEMPTS + // and failed to identify a valid prime. Throw an exception. + throw std::runtime_error("Unable to generate random prime (too many tests)"); } CBigNum generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations) { - CBigNum result(0); - uint32_t iterations = ceil((double)numBits / (double)HASH_OUTPUT_BITS); + CBigNum result(0); + uint32_t iterations = ceil((double)numBits / (double)HASH_OUTPUT_BITS); #ifdef ZEROCOIN_DEBUG - cout << "numBits = " << numBits << endl; - cout << "iterations = " << iterations << endl; + cout << "numBits = " << numBits << endl; + cout << "iterations = " << iterations << endl; #endif - // Loop "iterations" times filling up the value "result" with random bits - for (uint32_t count = 0; count < iterations; count++) { - // result += ( H(pseed + count) * 2^{count * p0len} ) - result += CBigNum(calculateHash(seed + count)) * CBigNum(2).pow(count * HASH_OUTPUT_BITS); - } + // Loop "iterations" times filling up the value "result" with random bits + for (uint32_t count = 0; count < iterations; count++) { + // result += ( H(pseed + count) * 2^{count * p0len} ) + result += CBigNum(calculateHash(seed + count)) * CBigNum(2).pow(count * HASH_OUTPUT_BITS); + } - result = CBigNum(2).pow(numBits - 1) + (result % (CBigNum(2).pow(numBits - 1))); + result = CBigNum(2).pow(numBits - 1) + (result % (CBigNum(2).pow(numBits - 1))); - // Return the number of iterations and the result - *numIterations = iterations; - return result; + // Return the number of iterations and the result + *numIterations = iterations; + return result; } /// \brief Determines whether a uint32_t is a prime through trial division. @@ -648,10 +646,10 @@ generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations) bool primalityTestByTrialDivision(uint32_t candidate) { - // TODO: HACK HACK WRONG WRONG - CBigNum canBignum(candidate); + // TODO: HACK HACK WRONG WRONG + CBigNum canBignum(candidate); - return canBignum.isPrime(); + return canBignum.isPrime(); } } // namespace libzerocoin diff --git a/src/libzerocoin/ParamGeneration.h b/src/libzerocoin/ParamGeneration.h index cd224493a788..e8fa2d4a1fe6 100644 --- a/src/libzerocoin/ParamGeneration.h +++ b/src/libzerocoin/ParamGeneration.h @@ -49,7 +49,6 @@ CBigNum calculateGroupGenerator(uint256 seed, uint256 pSeed, uint25 CBigNum generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed, uint32_t *prime_gen_counter); CBigNum generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations); -bool primalityTestByTrialDivision(uint32_t candidate); }/* namespace libzerocoin */ diff --git a/src/libzerocoin/Params.cpp b/src/libzerocoin/Params.cpp index dccdbd150202..a010fbc17535 100644 --- a/src/libzerocoin/Params.cpp +++ b/src/libzerocoin/Params.cpp @@ -16,32 +16,32 @@ namespace libzerocoin { ZerocoinParams::ZerocoinParams(CBigNum N, uint32_t securityLevel) { - this->zkp_hash_len = securityLevel; - this->zkp_iterations = securityLevel; + this->zkp_hash_len = securityLevel; + this->zkp_iterations = securityLevel; - this->accumulatorParams.k_prime = ACCPROOF_KPRIME; - this->accumulatorParams.k_dprime = ACCPROOF_KDPRIME; + this->accumulatorParams.k_prime = ACCPROOF_KPRIME; + this->accumulatorParams.k_dprime = ACCPROOF_KDPRIME; - // Generate the parameters - CalculateParams(*this, N, ZEROCOIN_PROTOCOL_VERSION, securityLevel); + // Generate the parameters + CalculateParams(*this, N, ZEROCOIN_PROTOCOL_VERSION, securityLevel); - this->accumulatorParams.initialized = true; - this->initialized = true; + this->accumulatorParams.initialized = true; + this->initialized = true; } AccumulatorAndProofParams::AccumulatorAndProofParams() { - this->initialized = false; + this->initialized = false; } IntegerGroupParams::IntegerGroupParams() { - this->initialized = false; + this->initialized = false; } CBigNum IntegerGroupParams::randomElement() const { - // The generator of the group raised - // to a random number less than the order of the group - // provides us with a uniformly distributed random number. - return this->g.pow_mod(CBigNum::randBignum(this->groupOrder),this->modulus); + // The generator of the group raised + // to a random number less than the order of the group + // provides us with a uniformly distributed random number. + return this->g.pow_mod(CBigNum::randBignum(this->groupOrder),this->modulus); } } /* namespace libzerocoin */ diff --git a/src/libzerocoin/Params.h b/src/libzerocoin/Params.h index 6e51a9ba72ff..ff5f1b63ac7f 100644 --- a/src/libzerocoin/Params.h +++ b/src/libzerocoin/Params.h @@ -20,198 +20,198 @@ namespace libzerocoin { class IntegerGroupParams { public: - /** @brief Integer group class, default constructor - * - * Allocates an empty (uninitialized) set of parameters. - **/ - IntegerGroupParams(); - - /** - * Generates a random group element - * @return a random element in the group. - */ - CBigNum randomElement() const; - bool initialized; - - /** - * A generator for the group. - */ - CBigNum g; - - /** - * A second generator for the group. - * Note log_g(h) and log_h(g) must - * be unknown. - */ - CBigNum h; - - /** - * The modulus for the group. - */ - CBigNum modulus; - - /** - * The order of the group - */ - CBigNum groupOrder; - - ADD_SERIALIZE_METHODS; + /** @brief Integer group class, default constructor + * + * Allocates an empty (uninitialized) set of parameters. + **/ + IntegerGroupParams(); + + /** + * Generates a random group element + * @return a random element in the group. + */ + CBigNum randomElement() const; + bool initialized; + + /** + * A generator for the group. + */ + CBigNum g; + + /** + * A second generator for the group. + * Note log_g(h) and log_h(g) must + * be unknown. + */ + CBigNum h; + + /** + * The modulus for the group. + */ + CBigNum modulus; + + /** + * The order of the group + */ + CBigNum groupOrder; + + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(initialized); - READWRITE(g); - READWRITE(h); - READWRITE(modulus); - READWRITE(groupOrder); - } + READWRITE(initialized); + READWRITE(g); + READWRITE(h); + READWRITE(modulus); + READWRITE(groupOrder); + } }; class AccumulatorAndProofParams { public: - /** @brief Construct a set of Zerocoin parameters from a modulus "N". - * @param N A trusted RSA modulus - * @param securityLevel A security level expressed in symmetric bits (default 80) - * - * Allocates and derives a set of Zerocoin parameters from - * a trustworthy RSA modulus "N". This routine calculates all - * of the remaining parameters (group descriptions etc.) from N - * using a verifiable, deterministic procedure. - * - * Note: this constructor makes the fundamental assumption that "N" - * encodes a valid RSA-style modulus of the form "e1 * e2" where - * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT - * be known to any party, or the security of Zerocoin is - * compromised. The integer "N" must be a MINIMUM of 1024 - * in length. 3072 bits is strongly recommended. - **/ - AccumulatorAndProofParams(); - - //AccumulatorAndProofParams(CBigNum accumulatorModulus); - - bool initialized; - - /** - * Modulus used for the accumulator. - * Product of two safe primes who's factorization is unknown. - */ - CBigNum accumulatorModulus; - - /** - * The initial value for the accumulator - * A random Quadratic residue mod n thats not 1 - */ - CBigNum accumulatorBase; - - /** - * Lower bound on the value for committed coin. - * Required by the accumulator proof. - */ - CBigNum minCoinValue; - - /** - * Upper bound on the value for a comitted coin. - * Required by the accumulator proof. - */ - CBigNum maxCoinValue; - - /** - * The second of two groups used to form a commitment to - * a coin (which it self is a commitment to a serial number). - * This one differs from serialNumberSokCommitment due to - * restrictions from Camenisch and Lysyanskaya's paper. - */ - IntegerGroupParams accumulatorPoKCommitmentGroup; - - /** - * Hidden order quadratic residue group mod N. - * Used in the accumulator proof. - */ - IntegerGroupParams accumulatorQRNCommitmentGroup; - - /** - * Security parameter. - * Bit length of the challenges used in the accumulator proof. - */ - uint32_t k_prime; - - /** - * Security parameter. - * The statistical zero-knowledgeness of the accumulator proof. - */ - uint32_t k_dprime; - ADD_SERIALIZE_METHODS; + /** @brief Construct a set of Zerocoin parameters from a modulus "N". + * @param N A trusted RSA modulus + * @param securityLevel A security level expressed in symmetric bits (default 80) + * + * Allocates and derives a set of Zerocoin parameters from + * a trustworthy RSA modulus "N". This routine calculates all + * of the remaining parameters (group descriptions etc.) from N + * using a verifiable, deterministic procedure. + * + * Note: this constructor makes the fundamental assumption that "N" + * encodes a valid RSA-style modulus of the form "e1 * e2" where + * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT + * be known to any party, or the security of Zerocoin is + * compromised. The integer "N" must be a MINIMUM of 1024 + * in length. 3072 bits is strongly recommended. + **/ + AccumulatorAndProofParams(); + + //AccumulatorAndProofParams(CBigNum accumulatorModulus); + + bool initialized; + + /** + * Modulus used for the accumulator. + * Product of two safe primes who's factorization is unknown. + */ + CBigNum accumulatorModulus; + + /** + * The initial value for the accumulator + * A random Quadratic residue mod n thats not 1 + */ + CBigNum accumulatorBase; + + /** + * Lower bound on the value for committed coin. + * Required by the accumulator proof. + */ + CBigNum minCoinValue; + + /** + * Upper bound on the value for a comitted coin. + * Required by the accumulator proof. + */ + CBigNum maxCoinValue; + + /** + * The second of two groups used to form a commitment to + * a coin (which it self is a commitment to a serial number). + * This one differs from serialNumberSokCommitment due to + * restrictions from Camenisch and Lysyanskaya's paper. + */ + IntegerGroupParams accumulatorPoKCommitmentGroup; + + /** + * Hidden order quadratic residue group mod N. + * Used in the accumulator proof. + */ + IntegerGroupParams accumulatorQRNCommitmentGroup; + + /** + * Security parameter. + * Bit length of the challenges used in the accumulator proof. + */ + uint32_t k_prime; + + /** + * Security parameter. + * The statistical zero-knowledgeness of the accumulator proof. + */ + uint32_t k_dprime; + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(initialized); - READWRITE(accumulatorModulus); - READWRITE(accumulatorBase); - READWRITE(accumulatorPoKCommitmentGroup); - READWRITE(accumulatorQRNCommitmentGroup); - READWRITE(minCoinValue); - READWRITE(maxCoinValue); - READWRITE(k_prime); - READWRITE(k_dprime); + READWRITE(initialized); + READWRITE(accumulatorModulus); + READWRITE(accumulatorBase); + READWRITE(accumulatorPoKCommitmentGroup); + READWRITE(accumulatorQRNCommitmentGroup); + READWRITE(minCoinValue); + READWRITE(maxCoinValue); + READWRITE(k_prime); + READWRITE(k_dprime); } }; class ZerocoinParams { public: - /** @brief Construct a set of Zerocoin parameters from a modulus "N". - * @param N A trusted RSA modulus - * @param securityLevel A security level expressed in symmetric bits (default 80) - * - * Allocates and derives a set of Zerocoin parameters from - * a trustworthy RSA modulus "N". This routine calculates all - * of the remaining parameters (group descriptions etc.) from N - * using a verifiable, deterministic procedure. - * - * Note: this constructor makes the fundamental assumption that "N" - * encodes a valid RSA-style modulus of the form "e1 * e2" where - * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT - * be known to any party, or the security of Zerocoin is - * compromised. The integer "N" must be a MINIMUM of 1024 - * in length. 3072 bits is strongly recommended. - **/ - ZerocoinParams(CBigNum accumulatorModulus, - uint32_t securityLevel = ZEROCOIN_DEFAULT_SECURITYLEVEL); - - bool initialized; - - AccumulatorAndProofParams accumulatorParams; - - /** - * The Quadratic Residue group from which we form - * a coin as a commitment to a serial number. - */ - IntegerGroupParams coinCommitmentGroup; - - /** - * One of two groups used to form a commitment to - * a coin (which it self is a commitment to a serial number). - * This is the one used in the serial number poof. - * It's order must be equal to the modulus of coinCommitmentGroup. - */ - IntegerGroupParams serialNumberSoKCommitmentGroup; - - /** - * The number of iterations to use in the serial - * number proof. - */ - uint32_t zkp_iterations; - - /** - * The amount of the hash function we use for - * proofs. - */ - uint32_t zkp_hash_len; - - ADD_SERIALIZE_METHODS; + /** @brief Construct a set of Zerocoin parameters from a modulus "N". + * @param N A trusted RSA modulus + * @param securityLevel A security level expressed in symmetric bits (default 80) + * + * Allocates and derives a set of Zerocoin parameters from + * a trustworthy RSA modulus "N". This routine calculates all + * of the remaining parameters (group descriptions etc.) from N + * using a verifiable, deterministic procedure. + * + * Note: this constructor makes the fundamental assumption that "N" + * encodes a valid RSA-style modulus of the form "e1 * e2" where + * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT + * be known to any party, or the security of Zerocoin is + * compromised. The integer "N" must be a MINIMUM of 1024 + * in length. 3072 bits is strongly recommended. + **/ + ZerocoinParams(CBigNum accumulatorModulus, + uint32_t securityLevel = ZEROCOIN_DEFAULT_SECURITYLEVEL); + + bool initialized; + + AccumulatorAndProofParams accumulatorParams; + + /** + * The Quadratic Residue group from which we form + * a coin as a commitment to a serial number. + */ + IntegerGroupParams coinCommitmentGroup; + + /** + * One of two groups used to form a commitment to + * a coin (which it self is a commitment to a serial number). + * This is the one used in the serial number poof. + * It's order must be equal to the modulus of coinCommitmentGroup. + */ + IntegerGroupParams serialNumberSoKCommitmentGroup; + + /** + * The number of iterations to use in the serial + * number proof. + */ + uint32_t zkp_iterations; + + /** + * The amount of the hash function we use for + * proofs. + */ + uint32_t zkp_hash_len; + + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(initialized); - READWRITE(accumulatorParams); - READWRITE(coinCommitmentGroup); - READWRITE(serialNumberSoKCommitmentGroup); - READWRITE(zkp_iterations); - READWRITE(zkp_hash_len); - } + READWRITE(initialized); + READWRITE(accumulatorParams); + READWRITE(coinCommitmentGroup); + READWRITE(serialNumberSoKCommitmentGroup); + READWRITE(zkp_iterations); + READWRITE(zkp_hash_len); + } }; } /* namespace libzerocoin */ diff --git a/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp b/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp index 4fc204eb44cb..5de263f66343 100644 --- a/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp +++ b/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp @@ -22,9 +22,9 @@ CBigNum SeedTo1024(uint256 hashSeed) { CHashWriter hasher(0,0); hasher << hashSeed; - vector vResult; + std::vector vResult; for (int i = 0; i < 4; i ++) { - vector vHash = CBigNum(hasher.GetHash()).getvch(); + std::vector vHash = CBigNum(hasher.GetHash()).getvch(); vResult.insert(vResult.end(), vHash.begin(), vHash.end()); hasher << vResult; } @@ -37,31 +37,31 @@ CBigNum SeedTo1024(uint256 hashSeed) { SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const ZerocoinParams* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, uint256 msghash):params(p), - s_notprime(p->zkp_iterations), - sprime(p->zkp_iterations) { - - // Sanity check: verify that the order of the "accumulatedValueCommitmentGroup" is - // equal to the modulus of "coinCommitmentGroup". Otherwise we will produce invalid - // proofs. - if (params->coinCommitmentGroup.modulus != params->serialNumberSoKCommitmentGroup.groupOrder) { - throw std::runtime_error("Groups are not structured correctly."); - } + s_notprime(p->zkp_iterations), + sprime(p->zkp_iterations) { + + // Sanity check: verify that the order of the "accumulatedValueCommitmentGroup" is + // equal to the modulus of "coinCommitmentGroup". Otherwise we will produce invalid + // proofs. + if (params->coinCommitmentGroup.modulus != params->serialNumberSoKCommitmentGroup.groupOrder) { + throw std::runtime_error("Groups are not structured correctly."); + } - CBigNum a = params->coinCommitmentGroup.g; - CBigNum b = params->coinCommitmentGroup.h; - CBigNum g = params->serialNumberSoKCommitmentGroup.g; - CBigNum h = params->serialNumberSoKCommitmentGroup.h; + CBigNum a = params->coinCommitmentGroup.g; + CBigNum b = params->coinCommitmentGroup.h; + CBigNum g = params->serialNumberSoKCommitmentGroup.g; + CBigNum h = params->serialNumberSoKCommitmentGroup.h; - CHashWriter hasher(0,0); - hasher << *params << commitmentToCoin.getCommitmentValue() << coin.getSerialNumber() << msghash; + CHashWriter hasher(0,0); + hasher << *params << commitmentToCoin.getCommitmentValue() << coin.getSerialNumber() << msghash; - vector r(params->zkp_iterations); - vector v_seed(params->zkp_iterations); - vector v_expanded(params->zkp_iterations); - vector c(params->zkp_iterations); + std::vector r(params->zkp_iterations); + std::vector v_seed(params->zkp_iterations); + std::vector v_expanded(params->zkp_iterations); + std::vector c(params->zkp_iterations); - for(uint32_t i=0; i < params->zkp_iterations; i++) { - r[i] = CBigNum::randBignum(params->coinCommitmentGroup.groupOrder); + for(uint32_t i=0; i < params->zkp_iterations; i++) { + r[i] = CBigNum::randBignum(params->coinCommitmentGroup.groupOrder); //use a random 256 bit seed that expands to 1024 bit for v[i] while (true) { @@ -75,81 +75,81 @@ SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const v_expanded[i] = bnExpanded; break; } - } - - for(uint32_t i=0; i < params->zkp_iterations; i++) { - // compute g^{ {a^x b^r} h^v} mod p2 - c[i] = challengeCalculation(coin.getSerialNumber(), r[i], v_expanded[i]); - } - - // We can't hash data in parallel either - // because OPENMP cannot not guarantee loops - // execute in order. - for(uint32_t i=0; i < params->zkp_iterations; i++) { - hasher << c[i]; - } - this->hash = hasher.GetHash(); - unsigned char *hashbytes = (unsigned char*) &hash; - - for(uint32_t i = 0; i < params->zkp_iterations; i++) { - int bit = i % 8; - int byte = i / 8; - - bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); - if (challenge_bit) { - s_notprime[i] = r[i]; - sprime[i] = v_seed[i]; - } else { - s_notprime[i] = r[i] - coin.getRandomness(); - sprime[i] = v_expanded[i] - (commitmentToCoin.getRandomness() * - b.pow_mod(r[i] - coin.getRandomness(), params->serialNumberSoKCommitmentGroup.groupOrder)); - } - } + } + + for(uint32_t i=0; i < params->zkp_iterations; i++) { + // compute g^{ {a^x b^r} h^v} mod p2 + c[i] = challengeCalculation(coin.getSerialNumber(), r[i], v_expanded[i]); + } + + // We can't hash data in parallel either + // because OPENMP cannot not guarantee loops + // execute in order. + for(uint32_t i=0; i < params->zkp_iterations; i++) { + hasher << c[i]; + } + this->hash = hasher.GetHash(); + unsigned char *hashbytes = (unsigned char*) &hash; + + for(uint32_t i = 0; i < params->zkp_iterations; i++) { + int bit = i % 8; + int byte = i / 8; + + bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); + if (challenge_bit) { + s_notprime[i] = r[i]; + sprime[i] = v_seed[i]; + } else { + s_notprime[i] = r[i] - coin.getRandomness(); + sprime[i] = v_expanded[i] - (commitmentToCoin.getRandomness() * + b.pow_mod(r[i] - coin.getRandomness(), params->serialNumberSoKCommitmentGroup.groupOrder)); + } + } } inline CBigNum SerialNumberSignatureOfKnowledge::challengeCalculation(const CBigNum& a_exp,const CBigNum& b_exp, const CBigNum& h_exp) const { - CBigNum a = params->coinCommitmentGroup.g; - CBigNum b = params->coinCommitmentGroup.h; - CBigNum g = params->serialNumberSoKCommitmentGroup.g; - CBigNum h = params->serialNumberSoKCommitmentGroup.h; + CBigNum a = params->coinCommitmentGroup.g; + CBigNum b = params->coinCommitmentGroup.h; + CBigNum g = params->serialNumberSoKCommitmentGroup.g; + CBigNum h = params->serialNumberSoKCommitmentGroup.h; - CBigNum exponent = (a.pow_mod(a_exp, params->serialNumberSoKCommitmentGroup.groupOrder) - * b.pow_mod(b_exp, params->serialNumberSoKCommitmentGroup.groupOrder)) % params->serialNumberSoKCommitmentGroup.groupOrder; + CBigNum exponent = (a.pow_mod(a_exp, params->serialNumberSoKCommitmentGroup.groupOrder) + * b.pow_mod(b_exp, params->serialNumberSoKCommitmentGroup.groupOrder)) % params->serialNumberSoKCommitmentGroup.groupOrder; - return (g.pow_mod(exponent, params->serialNumberSoKCommitmentGroup.modulus) * h.pow_mod(h_exp, params->serialNumberSoKCommitmentGroup.modulus)) % params->serialNumberSoKCommitmentGroup.modulus; + return (g.pow_mod(exponent, params->serialNumberSoKCommitmentGroup.modulus) * h.pow_mod(h_exp, params->serialNumberSoKCommitmentGroup.modulus)) % params->serialNumberSoKCommitmentGroup.modulus; } bool SerialNumberSignatureOfKnowledge::Verify(const CBigNum& coinSerialNumber, const CBigNum& valueOfCommitmentToCoin, const uint256 msghash) const { - CBigNum a = params->coinCommitmentGroup.g; - CBigNum b = params->coinCommitmentGroup.h; - CBigNum g = params->serialNumberSoKCommitmentGroup.g; - CBigNum h = params->serialNumberSoKCommitmentGroup.h; - CHashWriter hasher(0,0); - hasher << *params << valueOfCommitmentToCoin << coinSerialNumber << msghash; - - vector tprime(params->zkp_iterations); - unsigned char *hashbytes = (unsigned char*) &this->hash; - - for(uint32_t i = 0; i < params->zkp_iterations; i++) { - int bit = i % 8; - int byte = i / 8; - bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); - if(challenge_bit) { - tprime[i] = challengeCalculation(coinSerialNumber, s_notprime[i], SeedTo1024(sprime[i].getuint256())); - } else { - CBigNum exp = b.pow_mod(s_notprime[i], params->serialNumberSoKCommitmentGroup.groupOrder); - tprime[i] = ((valueOfCommitmentToCoin.pow_mod(exp, params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus) * - (h.pow_mod(sprime[i], params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus)) % - params->serialNumberSoKCommitmentGroup.modulus; - } - } - for(uint32_t i = 0; i < params->zkp_iterations; i++) { - hasher << tprime[i]; - } - return hasher.GetHash() == hash; + CBigNum a = params->coinCommitmentGroup.g; + CBigNum b = params->coinCommitmentGroup.h; + CBigNum g = params->serialNumberSoKCommitmentGroup.g; + CBigNum h = params->serialNumberSoKCommitmentGroup.h; + CHashWriter hasher(0,0); + hasher << *params << valueOfCommitmentToCoin << coinSerialNumber << msghash; + + std::vector tprime(params->zkp_iterations); + unsigned char *hashbytes = (unsigned char*) &this->hash; + + for(uint32_t i = 0; i < params->zkp_iterations; i++) { + int bit = i % 8; + int byte = i / 8; + bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); + if(challenge_bit) { + tprime[i] = challengeCalculation(coinSerialNumber, s_notprime[i], SeedTo1024(sprime[i].getuint256())); + } else { + CBigNum exp = b.pow_mod(s_notprime[i], params->serialNumberSoKCommitmentGroup.groupOrder); + tprime[i] = ((valueOfCommitmentToCoin.pow_mod(exp, params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus) * + (h.pow_mod(sprime[i], params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus)) % + params->serialNumberSoKCommitmentGroup.modulus; + } + } + for(uint32_t i = 0; i < params->zkp_iterations; i++) { + hasher << tprime[i]; + } + return hasher.GetHash() == hash; } } /* namespace libzerocoin */ diff --git a/src/libzerocoin/SerialNumberSignatureOfKnowledge.h b/src/libzerocoin/SerialNumberSignatureOfKnowledge.h index 1e87ebe25366..915bfdd45255 100644 --- a/src/libzerocoin/SerialNumberSignatureOfKnowledge.h +++ b/src/libzerocoin/SerialNumberSignatureOfKnowledge.h @@ -25,7 +25,6 @@ #include "Accumulator.h" #include "hash.h" -using namespace std; namespace libzerocoin { /**A Signature of knowledge on the hash of metadata attesting that the signer knows the values @@ -34,41 +33,41 @@ namespace libzerocoin { */ class SerialNumberSignatureOfKnowledge { public: - SerialNumberSignatureOfKnowledge(const ZerocoinParams* p); - /** Creates a Signature of knowledge object that a commitment to a coin contains a coin with serial number x - * - * @param p params - * @param coin the coin we are going to prove the serial number of. - * @param commitmentToCoin the commitment to the coin - * @param msghash hash of meta data to create a signature of knowledge on. - */ - SerialNumberSignatureOfKnowledge(const ZerocoinParams* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, uint256 msghash); + SerialNumberSignatureOfKnowledge(const ZerocoinParams* p); + /** Creates a Signature of knowledge object that a commitment to a coin contains a coin with serial number x + * + * @param p params + * @param coin the coin we are going to prove the serial number of. + * @param commitmentToCoin the commitment to the coin + * @param msghash hash of meta data to create a signature of knowledge on. + */ + SerialNumberSignatureOfKnowledge(const ZerocoinParams* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, uint256 msghash); - /** Verifies the Signature of knowledge. - * - * @param msghash hash of meta data to create a signature of knowledge on. - * @return - */ - bool Verify(const CBigNum& coinSerialNumber, const CBigNum& valueOfCommitmentToCoin,const uint256 msghash) const; - ADD_SERIALIZE_METHODS; + /** Verifies the Signature of knowledge. + * + * @param msghash hash of meta data to create a signature of knowledge on. + * @return + */ + bool Verify(const CBigNum& coinSerialNumber, const CBigNum& valueOfCommitmentToCoin,const uint256 msghash) const; + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(s_notprime); - READWRITE(sprime); - READWRITE(hash); - } + READWRITE(s_notprime); + READWRITE(sprime); + READWRITE(hash); + } private: - const ZerocoinParams* params; - // challenge hash - uint256 hash; //TODO For efficiency, should this be a bitset where Templates define params? + const ZerocoinParams* params; + // challenge hash + uint256 hash; //TODO For efficiency, should this be a bitset where Templates define params? - // challenge response values - // this is s_notprime instead of s - // because the serialization macros - // define something named s and it conflicts - vector s_notprime; - vector sprime; - inline CBigNum challengeCalculation(const CBigNum& a_exp, const CBigNum& b_exp, - const CBigNum& h_exp) const; + // challenge response values + // this is s_notprime instead of s + // because the serialization macros + // define something named s and it conflicts + std::vector s_notprime; + std::vector sprime; + inline CBigNum challengeCalculation(const CBigNum& a_exp, const CBigNum& b_exp, + const CBigNum& h_exp) const; }; } /* namespace libzerocoin */ diff --git a/src/libzerocoin/SpendType.h b/src/libzerocoin/SpendType.h index 45285e16275e..06c8aee4f151 100644 --- a/src/libzerocoin/SpendType.h +++ b/src/libzerocoin/SpendType.h @@ -16,4 +16,4 @@ namespace libzerocoin { }; } -#endif //PIVX_SPENDTYPE_H +#endif //PHORE_SPENDTYPE_H diff --git a/src/libzerocoin/ZerocoinDefines.h b/src/libzerocoin/ZerocoinDefines.h index 9f19a461227c..e5cf00759b10 100644 --- a/src/libzerocoin/ZerocoinDefines.h +++ b/src/libzerocoin/ZerocoinDefines.h @@ -22,9 +22,9 @@ #define ACCPROOF_KPRIME 160 #define ACCPROOF_KDPRIME 128 #define MAX_COINMINT_ATTEMPTS 10000 -#define ZEROCOIN_MINT_PRIME_PARAM 20 +#define ZEROCOIN_MINT_PRIME_PARAM 20 #define ZEROCOIN_VERSION_STRING "0.11" -#define ZEROCOIN_VERSION_INT 11 +#define ZEROCOIN_VERSION_INT 11 #define ZEROCOIN_PROTOCOL_VERSION "1" #define HASH_OUTPUT_BITS 256 #define ZEROCOIN_COMMITMENT_EQUALITY_PROOF "COMMITMENT_EQUALITY_PROOF" @@ -36,6 +36,6 @@ // Uses a fast technique for coin generation. Could be more vulnerable // to timing attacks. Turn off if an attacker can measure coin minting time. -#define ZEROCOIN_FAST_MINT 1 +#define ZEROCOIN_FAST_MINT 1 #endif /* ZEROCOIN_H_ */ diff --git a/src/libzerocoin/bignum.h b/src/libzerocoin/bignum.h index 65edbd7d69c5..769bd890fcf4 100644 --- a/src/libzerocoin/bignum.h +++ b/src/libzerocoin/bignum.h @@ -94,7 +94,7 @@ class CBigNum CBigNum(short n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } CBigNum(int n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } CBigNum(long n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } -#ifdef __APPLE__ +#ifdef __APPLE__ CBigNum(int64_t n) { bn = BN_new(); setint64(n); } #endif CBigNum(unsigned char n) { bn = BN_new(); setulong(n); } @@ -306,7 +306,7 @@ class CBigNum std::vector vch(nSize); BN_bn2mpi(bn, &vch[0]); vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); + std::reverse(vch.begin(), vch.end()); return vch; } @@ -423,7 +423,7 @@ class CBigNum CAutoBN_CTX pctx; CBigNum bnBase = nBase; CBigNum bn0 = 0; - CBigNum locBn = *this; + CBigNum locBn = *this; std::string str; BN_set_negative(locBn.bn, false); CBigNum dv; @@ -440,7 +440,7 @@ class CBigNum } if (BN_is_negative(bn)) str += "-"; - reverse(str.begin(), str.end()); + std::reverse(str.begin(), str.end()); return str; } @@ -573,7 +573,7 @@ class CBigNum /** * Miller-Rabin primality test on this element * @param checks: optional, the number of Miller-Rabin tests to run - * default causes error rate of 2^-80. + * default causes error rate of 2^-80. * @return true if prime */ bool isPrime(const int checks=BN_prime_checks) const { @@ -606,7 +606,7 @@ class CBigNum CBigNum& operator-=(const CBigNum& b) { if (!BN_sub(bn, bn, b.bn)) - throw bignum_error("CBigNum::operator-= : BN_sub failed"); + throw bignum_error("CBigNum::operator-= : BN_sub failed"); return *this; } @@ -620,17 +620,17 @@ class CBigNum CBigNum& operator/=(const CBigNum& b) { - CAutoBN_CTX pctx; + CAutoBN_CTX pctx; if (!BN_div(bn, NULL, bn, b.bn, pctx)) - throw bignum_error("CBigNum::operator/= : BN_div failed"); + throw bignum_error("CBigNum::operator/= : BN_div failed"); return *this; } CBigNum& operator%=(const CBigNum& b) { - CAutoBN_CTX pctx; + CAutoBN_CTX pctx; if (!BN_mod(bn, b.bn, bn, pctx)) - throw bignum_error("CBigNum::operator%= : BN_mod failed"); + throw bignum_error("CBigNum::operator%= : BN_mod failed"); return *this; } diff --git a/src/libzerocoin/paramgen.cpp b/src/libzerocoin/paramgen.cpp index 9ac28a3987d9..2f4782850134 100644 --- a/src/libzerocoin/paramgen.cpp +++ b/src/libzerocoin/paramgen.cpp @@ -22,109 +22,106 @@ #define DEFAULT_MODULUS_SIZE 3072 #define MIN_MODULUS_SIZE 1026 -using namespace std; -using namespace libzerocoin; - void PrintWarning() { - cout << "Zerocoin parameter generation utility" << endl; - cout << "-------------------------------------" << endl << endl; - cout << "This utility generates an l-bit modulus N as the product of" << endl; - cout << "two safe primes p, q. The values p and q are not stored." << endl; - cout << "Call this program with no arguments to see usage options." << endl; - cout << endl; - cout << "SECURITY WARNING: ZEROCOIN PARAMETERS MUST BE GENERATED BY" << endl; - cout << "A TRUSTED PARTY WHO DOES NOT STORE THE FACTORS. WHILE WE MAKE" << endl; - cout << "A BEST EFFORT TO DESTROY THIS INFORMATION WE DO NOT TAKE" << endl; - cout << "SPECIAL PRECAUTIONS TO ENSURE THAT THEY ARE DESTROYED." << endl; - cout << endl; - cout << "USE THIS UTILITY AT YOUR OWN RISK" << endl << endl; + cout << "Zerocoin parameter generation utility" << endl; + cout << "-------------------------------------" << endl << endl; + cout << "This utility generates an l-bit modulus N as the product of" << endl; + cout << "two safe primes p, q. The values p and q are not stored." << endl; + cout << "Call this program with no arguments to see usage options." << endl; + cout << endl; + cout << "SECURITY WARNING: ZEROCOIN PARAMETERS MUST BE GENERATED BY" << endl; + cout << "A TRUSTED PARTY WHO DOES NOT STORE THE FACTORS. WHILE WE MAKE" << endl; + cout << "A BEST EFFORT TO DESTROY THIS INFORMATION WE DO NOT TAKE" << endl; + cout << "SPECIAL PRECAUTIONS TO ENSURE THAT THEY ARE DESTROYED." << endl; + cout << endl; + cout << "USE THIS UTILITY AT YOUR OWN RISK" << endl << endl; } void usage() { - printf("Usage:\n"); - printf(" -b \n"); - printf(" -o \n"); + printf("Usage:\n"); + printf(" -b \n"); + printf(" -o \n"); - exit (8); + exit (8); } int main(int argc, char **argv) { - static CBigNum resultModulus(0); - uint32_t numBits = DEFAULT_MODULUS_SIZE; - ofstream outfile; - char* outfileName; - bool writeToFile = false; - - while ((argc > 1) && (argv[1][0] == '-')) - { - switch (argv[1][1]) - { - case 'b': - numBits = atoi(argv[2]); - ++argv; - --argc; - break; - - case 'o': - outfileName = argv[2]; - writeToFile = true; - break; - - case 'h': - usage(); - break; - - default: - printf("Wrong Argument: %s\n", argv[1]); - usage(); - break; - } - - ++argv; - --argc; - } - - if (numBits < MIN_MODULUS_SIZE) { - cout << "Modulus is below minimum length (" << MIN_MODULUS_SIZE << ") bits" << endl; - return(0); - } - - PrintWarning(); - - cout << "Modulus size set to " << numBits << " bits." << endl; - cout << "Generating parameters. This may take a few minutes..." << endl; - - // Generate two safe primes "p" and "q" - CBigNum *p, *q; - p = new CBigNum(0); - q = new CBigNum(0); - *p = CBigNum::generatePrime(numBits / 2, true); - *q = CBigNum::generatePrime(numBits / 2, true); - - // Multiply to compute N - resultModulus = (*p) * (*q); - - // Wipe out the factors - delete p; - delete q; - - // Convert to a hexidecimal string - std::string resultHex = resultModulus.ToString(16); - - cout << endl << "N = " << endl << resultHex << endl; - - if (writeToFile) { - try { - outfile.open (outfileName); - outfile << resultHex; - outfile.close(); - cout << endl << "Result has been written to file '" << outfileName << "'." << endl; - } catch (std::runtime_error &e) { - cout << "Unable to write to file:" << e.what() << endl; - } - } + static CBigNum resultModulus(0); + uint32_t numBits = DEFAULT_MODULUS_SIZE; + ofstream outfile; + char* outfileName; + bool writeToFile = false; + + while ((argc > 1) && (argv[1][0] == '-')) + { + switch (argv[1][1]) + { + case 'b': + numBits = atoi(argv[2]); + ++argv; + --argc; + break; + + case 'o': + outfileName = argv[2]; + writeToFile = true; + break; + + case 'h': + usage(); + break; + + default: + printf("Wrong Argument: %s\n", argv[1]); + usage(); + break; + } + + ++argv; + --argc; + } + + if (numBits < MIN_MODULUS_SIZE) { + cout << "Modulus is below minimum length (" << MIN_MODULUS_SIZE << ") bits" << endl; + return(0); + } + + PrintWarning(); + + cout << "Modulus size set to " << numBits << " bits." << endl; + cout << "Generating parameters. This may take a few minutes..." << endl; + + // Generate two safe primes "p" and "q" + CBigNum *p, *q; + p = new CBigNum(0); + q = new CBigNum(0); + *p = CBigNum::generatePrime(numBits / 2, true); + *q = CBigNum::generatePrime(numBits / 2, true); + + // Multiply to compute N + resultModulus = (*p) * (*q); + + // Wipe out the factors + delete p; + delete q; + + // Convert to a hexidecimal string + std::string resultHex = resultModulus.ToString(16); + + cout << endl << "N = " << endl << resultHex << endl; + + if (writeToFile) { + try { + outfile.open (outfileName); + outfile << resultHex; + outfile.close(); + cout << endl << "Result has been written to file '" << outfileName << "'." << endl; + } catch (std::runtime_error &e) { + cout << "Unable to write to file:" << e.what() << endl; + } + } } diff --git a/src/limitedmap.h b/src/limitedmap.h index 03727d7c4256..dda9287f1695 100644 --- a/src/limitedmap.h +++ b/src/limitedmap.h @@ -42,7 +42,7 @@ class limitedmap map.erase(rmap.begin()->second); rmap.erase(rmap.begin()); } - rmap.insert(make_pair(x.second, ret.first)); + rmap.insert(std::make_pair(x.second, ret.first)); } return; } @@ -72,7 +72,7 @@ class limitedmap if (it->second == itTarget) { rmap.erase(it); itTarget->second = v; - rmap.insert(make_pair(v, itTarget)); + rmap.insert(std::make_pair(v, itTarget)); return; } // Shouldn't ever get here diff --git a/src/main.cpp b/src/main.cpp index 75cfe26af98e..c4521c6e1d96 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,11 +51,9 @@ #include #include #include +#include #include -using namespace boost; -using namespace std; -using namespace libzerocoin; #if defined(NDEBUG) #error "Phore cannot be compiled without assertions." @@ -72,8 +70,7 @@ using namespace libzerocoin; CCriticalSection cs_main; BlockMap mapBlockIndex; -map mapProofOfStake; -set > setStakeSeen; +std::map mapProofOfStake; // maps any spent outputs in the past maxreorgdepth blocks to the height it was spent // this means for incoming blocks, we can check that their stake output was not spent before @@ -81,8 +78,8 @@ set > setStakeSeen; // attacks because then we can check that either the staking input is available in the current // active chain, or the staking input was spent in the past 100 blocks after the height // of the incoming block. -map mapStakeSpent; -map mapHashedBlocks; +std::map mapStakeSpent; +std::map mapHashedBlocks; CChain chainActive; CBlockIndex* pindexBestHeader = NULL; int64_t nTimeBestReceived = 0; @@ -100,6 +97,9 @@ unsigned int nCoinCacheSize = 5000; unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; bool fAlerts = DEFAULT_ALERTS; +/* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; + unsigned int nStakeMinAge = 3 * 60 * 60; int64_t nReserveBalance = 0; @@ -115,10 +115,10 @@ struct COrphanTx { CTransaction tx; NodeId fromPeer; }; -map mapOrphanTransactions; -map > mapOrphanTransactionsByPrev; -map mapRejectedBlocks; -map mapZerocoinspends; //txid, time received +std::map mapOrphanTransactions; +std::map > mapOrphanTransactionsByPrev; +std::map mapRejectedBlocks; +std::map mapZerocoinspends; //txid, time received void EraseOrphansFor(NodeId peer); @@ -128,7 +128,7 @@ static void CheckBlockIndex(); /** Constant stuff for coinbase transactions we create: */ CScript COINBASE_FLAGS; -const string strMessageMagic = "DarkNet Signed Message:\n"; +const std::string strMessageMagic = "DarkNet Signed Message:\n"; // Internal stuff namespace @@ -160,11 +160,11 @@ CBlockIndex* pindexBestInvalid; * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and * as good as our current tip or better. Entries may be failed, though. */ -set setBlockIndexCandidates; +std::set setBlockIndexCandidates; /** Number of nodes with fSyncStarted. */ int nSyncStarted = 0; /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. */ -multimap mapBlocksUnlinked; +std::multimap mapBlocksUnlinked; CCriticalSection cs_LastBlockFile; std::vector vinfoBlockFile; @@ -182,7 +182,7 @@ uint32_t nBlockSequenceId = 1; * Sources of received blocks, to be able to send them reject messages or ban * them, if processing happens afterwards. Protected by cs_main. */ -map mapBlockSource; +std::map mapBlockSource; /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { @@ -192,7 +192,7 @@ struct QueuedBlock { int nValidatedQueuedBefore; //! Number of blocks queued with validated headers (globally) at the time this one is requested. bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. }; -map::iterator> > mapBlocksInFlight; +std::map::iterator> > mapBlocksInFlight; /** Number of blocks in flight with validated headers. */ int nQueuedValidatedHeaders = 0; @@ -201,10 +201,10 @@ int nQueuedValidatedHeaders = 0; int nPreferredDownload = 0; /** Dirty block index entries. */ -set setDirtyBlockIndex; +std::set setDirtyBlockIndex; /** Dirty block file entries. */ -set setDirtyFileInfo; +std::set setDirtyFileInfo; } // anon namespace ////////////////////////////////////////////////////////////////////////////// @@ -216,7 +216,7 @@ namespace { struct CBlockReject { unsigned int chRejectCode; - string strRejectReason; + std::string strRejectReason; uint256 hashBlock; }; @@ -249,7 +249,7 @@ struct CNodeState { bool fSyncStarted; //! Since when we're stalling block download progress (in microseconds), or 0. int64_t nStallingSince; - list vBlocksInFlight; + std::list vBlocksInFlight; int nBlocksInFlight; //! Whether we consider this a preferred download peer. bool fPreferredDownload; @@ -273,12 +273,12 @@ struct CNodeState { }; /** Map maintaining per-node state. Requires cs_main. */ -map mapNodeState; +std::map mapNodeState; // Requires cs_main. CNodeState* State(NodeId pnode) { - map::iterator it = mapNodeState.find(pnode); + std::map::iterator it = mapNodeState.find(pnode); if (it == mapNodeState.end()) return NULL; return &it->second; @@ -326,7 +326,7 @@ void FinalizeNode(NodeId nodeid) AddressCurrentlyConnected(state->address); } - BOOST_FOREACH (const QueuedBlock& entry, state->vBlocksInFlight) + for (const QueuedBlock& entry : state->vBlocksInFlight) mapBlocksInFlight.erase(entry.hash); EraseOrphansFor(nodeid); nPreferredDownload -= state->fPreferredDownload; @@ -337,7 +337,7 @@ void FinalizeNode(NodeId nodeid) // Requires cs_main. void MarkBlockAsReceived(const uint256& hash) { - map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); + std::map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); if (itInFlight != mapBlocksInFlight.end()) { CNodeState* state = State(itInFlight->second.first); nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; @@ -359,7 +359,7 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex* pindex QueuedBlock newentry = {hash, pindex, GetTimeMicros(), nQueuedValidatedHeaders, pindex != NULL}; nQueuedValidatedHeaders += newentry.fValidatedHeaders; - list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); + std::list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); state->nBlocksInFlight++; mapBlocksInFlight[hash] = std::make_pair(nodeid, it); } @@ -473,7 +473,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorIsValid(BLOCK_VALID_TREE)) { // We consider the chain that this peer is on invalid. return; @@ -514,7 +514,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) stats.nMisbehavior = state->nMisbehavior; stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1; - BOOST_FOREACH (const QueuedBlock& queue, state->vBlocksInFlight) { + for (const QueuedBlock& queue : state->vBlocksInFlight) { if (queue.pindex) stats.vHeightInFlight.push_back(queue.pindex->nHeight); } @@ -542,7 +542,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) { // Find the first block the caller has in the main chain - BOOST_FOREACH (const uint256& hash, locator.vHave) { + for (const uint256& hash : locator.vHave) { BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; @@ -587,7 +587,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) mapOrphanTransactions[hash].tx = tx; mapOrphanTransactions[hash].fromPeer = peer; - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), @@ -597,11 +597,11 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) void static EraseOrphanTx(uint256 hash) { - map::iterator it = mapOrphanTransactions.find(hash); + std::map::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return; - BOOST_FOREACH (const CTxIn& txin, it->second.tx.vin) { - map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); + for (const CTxIn& txin : it->second.tx.vin) { + std::map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); if (itPrev == mapOrphanTransactionsByPrev.end()) continue; itPrev->second.erase(hash); @@ -614,9 +614,9 @@ void static EraseOrphanTx(uint256 hash) void EraseOrphansFor(NodeId peer) { int nErased = 0; - map::iterator iter = mapOrphanTransactions.begin(); + std::map::iterator iter = mapOrphanTransactions.begin(); while (iter != mapOrphanTransactions.end()) { - map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid + std::map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid if (maybeErase->second.fromPeer == peer) { EraseOrphanTx(maybeErase->second.tx.GetHash()); ++nErased; @@ -632,7 +632,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) while (mapOrphanTransactions.size() > nMaxOrphans) { // Evict a random orphan: uint256 randomhash = GetRandHash(); - map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + std::map::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); @@ -641,7 +641,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) return nEvicted; } -bool IsStandardTx(const CTransaction& tx, string& reason) +bool IsStandardTx(const CTransaction& tx, std::string& reason) { AssertLockHeld(cs_main); if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { @@ -703,7 +703,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) unsigned int nDataOut = 0; txnouttype whichType; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { if (!::IsStandard(txout.scriptPubKey, whichType)) { reason = "scriptpubkey"; return false; @@ -741,7 +741,7 @@ bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime) nBlockTime = GetAdjustedTime(); if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) return true; - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) if (!txin.IsFinal()) return false; return true; @@ -802,10 +802,10 @@ int64_t GetVirtualTransactionSize(const CTransaction& tx) unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { nSigOps += txin.scriptSig.GetSigOpCount(false); } - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { nSigOps += txout.scriptPubKey.GetSigOpCount(false); } return nSigOps; @@ -897,57 +897,6 @@ int GetIXConfirmations(uint256 nTXHash) return 0; } -// ppcoin: total coin age spent in transaction, in the unit of coin-days. -// Only those coins meeting minimum age requirement counts. As those -// transactions not in main chain are not currently indexed so we -// might not find out about their coin age. Older transactions are -// guaranteed to be in main chain by sync-checkpoint. This rule is -// introduced to help nodes establish a consistent view of the coin -// age (trust score) of competing branches. -bool GetCoinAge(const CTransaction& tx, const unsigned int nTxTime, uint64_t& nCoinAge) -{ - uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds - nCoinAge = 0; - - CBlockIndex* pindex = NULL; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { - // First try finding the previous transaction in database - CTransaction txPrev; - uint256 hashBlockPrev; - if (!GetTransaction(txin.prevout.hash, txPrev, hashBlockPrev, true)) { - LogPrintf("GetCoinAge: failed to find vin transaction \n"); - continue; // previous transaction not in main chain - } - - BlockMap::iterator it = mapBlockIndex.find(hashBlockPrev); - if (it != mapBlockIndex.end()) - pindex = it->second; - else { - LogPrintf("GetCoinAge() failed to find block index \n"); - continue; - } - - // Read block header - CBlockHeader prevblock = pindex->GetBlockHeader(); - - if (prevblock.nTime + nStakeMinAge > nTxTime) - continue; // only count coins meeting min age requirement - - if (nTxTime < prevblock.nTime) { - LogPrintf("GetCoinAge: Timestamp Violation: txtime less than txPrev.nTime"); - return false; // Transaction timestamp violation - } - - int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue; - bnCentSecond += uint256(nValueIn) * (nTxTime - prevblock.nTime); - } - - uint256 bnCoinDay = bnCentSecond / COIN / (24 * 60 * 60); - LogPrintf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str()); - nCoinAge = bnCoinDay.GetCompact(); - return true; -} - bool MoneyRange(CAmount nValueOut) { return nValueOut >= 0 && nValueOut <= Params().MaxMoneyOut(); @@ -962,7 +911,7 @@ libzerocoin::ZerocoinParams* GetZerocoinParams(int nHeight) { return nHeight > Params().Zerocoin_LastOldParams() ? Params().Zerocoin_Params() : Params().OldZerocoin_Params(); } -void FindMints(vector vMintsToFind, vector& vMintsToUpdate, vector& vMissingMints) +void FindMints(std::vector vMintsToFind, std::vector& vMintsToUpdate, std::vector& vMissingMints) { // see which mints are in our public zerocoin database. The mint should be here if it exists, unless // something went wrong @@ -1017,7 +966,7 @@ void FindMints(vector vMintsToFind, vector& vMintsToUpdate for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; - PublicCoin pubcoin(meta.nVersion < libzerocoin::PrivateCoin::PUBKEY_VERSION ? Params().OldZerocoin_Params() : Params().Zerocoin_Params()); + libzerocoin::PublicCoin pubcoin(meta.nVersion < libzerocoin::PrivateCoin::PUBKEY_VERSION ? Params().OldZerocoin_Params() : Params().Zerocoin_Params()); CValidationState state; TxOutToPublicCoin(out, pubcoin, state); if (GetPubCoinHash(pubcoin.getValue()) == meta.hashPubcoin && pubcoin.getDenomination() != meta.denom) { @@ -1087,7 +1036,7 @@ bool RemoveSerialFromDB(const CBigNum& bnSerial) } /** zerocoin transaction checks */ -bool RecordMintToDB(PublicCoin publicZerocoin, const uint256& txHash) +bool RecordMintToDB(libzerocoin::PublicCoin publicZerocoin, const uint256& txHash) { //Check the pubCoinValue didn't already store in the zerocoin database. todo: pubcoin memory map? //write the zerocoinmint to db if we don't already have it @@ -1110,26 +1059,26 @@ bool RecordMintToDB(PublicCoin publicZerocoin, const uint256& txHash) return true; } -bool TxOutToPublicCoin(const CTxOut txout, PublicCoin& pubCoin, CValidationState& state) +bool TxOutToPublicCoin(const CTxOut txout, libzerocoin::PublicCoin& pubCoin, CValidationState& state) { CBigNum publicZerocoin; - vector vchZeroMint; + std::vector vchZeroMint; vchZeroMint.insert(vchZeroMint.end(), txout.scriptPubKey.begin() + SCRIPT_OFFSET, txout.scriptPubKey.begin() + txout.scriptPubKey.size()); publicZerocoin.setvch(vchZeroMint); - CoinDenomination denomination = AmountToZerocoinDenomination(txout.nValue); + libzerocoin::CoinDenomination denomination = libzerocoin::AmountToZerocoinDenomination(txout.nValue); LogPrint("zero", "%s ZCPRINT denomination %d pubcoin %s\n", __func__, denomination, publicZerocoin.GetHex()); - if (denomination == ZQ_ERROR) + if (denomination == libzerocoin::ZQ_ERROR) return state.DoS(100, error("TxOutToPublicCoin : txout.nValue is not correct")); - PublicCoin checkPubCoin(Params().Zerocoin_Params(), publicZerocoin, denomination); + libzerocoin::PublicCoin checkPubCoin(Params().Zerocoin_Params(), publicZerocoin, denomination); pubCoin = checkPubCoin; return true; } -bool BlockToPubcoinList(const CBlock& block, list& listPubcoins) +bool BlockToPubcoinList(const CBlock& block, std::list& listPubcoins) { for (const CTransaction& tx : block.vtx) { if(!tx.IsZerocoinMint()) @@ -1142,7 +1091,7 @@ bool BlockToPubcoinList(const CBlock& block, list& listPubcoins) continue; CValidationState state; - PublicCoin pubCoin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin pubCoin(Params().Zerocoin_Params()); if(!TxOutToPublicCoin(txOut, pubCoin, state)) return false; @@ -1166,7 +1115,7 @@ bool BlockToZerocoinMintList(const CBlock& block, std::list& vMin continue; CValidationState state; - PublicCoin pubCoin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin pubCoin(Params().Zerocoin_Params()); if(!TxOutToPublicCoin(txOut, pubCoin, state)) return false; @@ -1179,7 +1128,7 @@ bool BlockToZerocoinMintList(const CBlock& block, std::list& vMin return true; } -bool BlockToMintValueVector(const CBlock& block, const CoinDenomination denom, vector& vValues) +bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomination denom, std::vector& vValues) { for (const CTransaction& tx : block.vtx) { if(!tx.IsZerocoinMint()) @@ -1190,7 +1139,7 @@ bool BlockToMintValueVector(const CBlock& block, const CoinDenomination denom, v continue; CValidationState state; - PublicCoin coin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin coin(Params().Zerocoin_Params()); if(!TxOutToPublicCoin(txOut, coin, state)) return false; @@ -1225,7 +1174,7 @@ std::list ZerocoinSpendListFromBlock(const CBlock bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationState& state, bool fCheckOnly) { - PublicCoin pubCoin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin pubCoin(Params().Zerocoin_Params()); if(!TxOutToPublicCoin(txout, pubCoin, state)) return state.DoS(100, error("CheckZerocoinMint(): TxOutToPublicCoin() failed")); @@ -1235,21 +1184,22 @@ bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationSt return true; } -CoinSpend TxInToZerocoinSpend(const CTxIn& txin) +libzerocoin::CoinSpend TxInToZerocoinSpend(const CTxIn& txin) { // extract the spend from the txin std::vector > dataTxIn; dataTxIn.insert(dataTxIn.end(), txin.scriptSig.begin() + BIGNUM_SIZE, txin.scriptSig.end()); CDataStream serializedCoinSpend(dataTxIn, SER_NETWORK, PROTOCOL_VERSION); - return CoinSpend(Params().Zerocoin_Params(), GetZerocoinParams(chainActive.Height()), serializedCoinSpend); + return libzerocoin::CoinSpend(Params().Zerocoin_Params(), GetZerocoinParams(chainActive.Height()), serializedCoinSpend); } -bool ContextualCheckZerocoinMint(const CTransaction& tx, const PublicCoin& coin, const CBlockIndex* pindex) { +bool ContextualCheckZerocoinMint(const CTransaction& tx, const libzerocoin::PublicCoin& coin, const CBlockIndex* pindex) { if (pindex->nHeight > Params().Zerocoin_LastOldParams() && Params().NetworkID() != CBaseChainParams::TESTNET) { //See if this coin has already been added to the blockchain uint256 txid; - if(zerocoinDB->ReadCoinMint(coin.getValue(), txid)) + int nHeight; + if (zerocoinDB->ReadCoinMint(coin.getValue(), txid) && IsTransactionInChain(txid, nHeight)) return error("%s: pubcoin %s was already accumulated in tx %s", __func__, coin.getValue().GetHex().substr(0, 10), txid.GetHex()); @@ -1257,7 +1207,7 @@ bool ContextualCheckZerocoinMint(const CTransaction& tx, const PublicCoin& coin, return true; } -bool ContextualCheckZerocoinSpend(const CTransaction& tx, const CoinSpend& spend, CBlockIndex* pindex, const uint256& hashBlock) { +bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend& spend, CBlockIndex* pindex, const uint256& hashBlock) { //Check to see if the zPHR is properly signed if (pindex->nHeight > Params().Zerocoin_LastOldParams()) { if (!spend.HasValidSignature()) @@ -1309,8 +1259,8 @@ bool CheckZerocoinSpend(const CTransaction tx, bool fVerifySignature, CValidatio uint256 hashTxOut = txTemp.GetHash(); bool fValidated = false; - set serials; - list vSpends; + std::set serials; + std::list vSpends; CAmount nTotalRedeemed = 0; for (const CTxIn& txin : tx.vin) { @@ -1318,11 +1268,11 @@ bool CheckZerocoinSpend(const CTransaction tx, bool fVerifySignature, CValidatio if (!txin.scriptSig.IsZerocoinSpend()) continue; - CoinSpend newSpend = TxInToZerocoinSpend(txin); + libzerocoin::CoinSpend newSpend = TxInToZerocoinSpend(txin); vSpends.push_back(newSpend); //check that the denomination is valid - if (newSpend.getDenomination() == ZQ_ERROR) + if (newSpend.getDenomination() == libzerocoin::ZQ_ERROR) return state.DoS(100, error("Zerocoinspend does not have the correct denomination")); //check that denomination is what it claims to be in nSequence @@ -1342,7 +1292,7 @@ bool CheckZerocoinSpend(const CTransaction tx, bool fVerifySignature, CValidatio return state.DoS(100, error("%s: Zerocoinspend could not find accumulator associated with checksum %s", __func__, HexStr(BEGIN(nChecksum), END(nChecksum)))); } - Accumulator accumulator(GetZerocoinParams(nHeight), newSpend.getDenomination(), bnAccumulatorValue); + libzerocoin::Accumulator accumulator(GetZerocoinParams(nHeight), newSpend.getDenomination(), bnAccumulatorValue); //Check that the coin has been accumulated if(!newSpend.Verify(accumulator)) @@ -1383,7 +1333,7 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject // Check for negative or overflow output values CAmount nValueOut = 0; int nZCSpendCount = 0; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { if (txout.nValue < 0) return state.DoS(100, error("CheckTransaction() : txout.nValue negative"), REJECT_INVALID, "bad-txns-vout-negative"); @@ -1422,8 +1372,8 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject } // Check for duplicate inputs - set vInOutPoints; - set vZerocoinSpendSerials; + std::set vInOutPoints; + std::set vZerocoinSpendSerials; for (const CTxIn& txin : tx.vin) { if (vInOutPoints.count(txin.prevout)) return state.DoS(100, error("CheckTransaction() : duplicate inputs"), @@ -1442,7 +1392,7 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject if(tx.vin.size() < 1 || static_cast(tx.vin.size()) > Params().Zerocoin_MaxSpendsPerTransaction()) return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend"); } else { - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) if (txin.prevout.IsNull() && (fZerocoinActive && !txin.scriptSig.IsZerocoinSpend())) return state.DoS(10, error("CheckTransaction() : prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); @@ -1542,8 +1492,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa } // ----------- swiftTX transaction scanning ----------- - string reason; - BOOST_FOREACH (const CTxIn& in, tx.vin) { + std::string reason; + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { return state.DoS(0, @@ -1594,7 +1544,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa for (const CTxIn& txIn : tx.vin) { if (!txIn.scriptSig.IsZerocoinSpend()) continue; - CoinSpend spend = TxInToZerocoinSpend(txIn); + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); if (!ContextualCheckZerocoinSpend(tx, spend, chainActive.Tip(), 0)) return state.Invalid(error("%s: ContextualCheckZerocoinSpend failed for tx %s", __func__, tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-zphr"); @@ -1625,7 +1575,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa if (!out.IsZerocoinMint()) continue; - PublicCoin coin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin coin(Params().Zerocoin_Params()); if (!TxOutToPublicCoin(out, coin, state)) return state.Invalid(error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); @@ -1824,7 +1774,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact REJECT_INVALID, "coinbase"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) - string reason; + std::string reason; // for any real tx this will be checked on AcceptToMemoryPool anyway // if (Params().RequireStandard() && !IsStandardTx(tx, reason)) // return state.DoS(0, @@ -1838,7 +1788,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // ----------- swiftTX transaction scanning ----------- - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { return state.DoS(0, @@ -1892,7 +1842,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact if (!out.IsZerocoinMint()) continue; - PublicCoin coin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin coin(Params().Zerocoin_Params()); if (!TxOutToPublicCoin(out, coin, state)) return state.Invalid(error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); @@ -2067,7 +2017,7 @@ bool GetTransaction(const uint256& hash, CTransaction& txOut, uint256& hashBlock if (pindexSlow) { CBlock block; if (ReadBlockFromDisk(block, pindexSlow)) { - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (tx.GetHash() == hash) { txOut = tx; hashBlock = pindexSlow->GetBlockHash(); @@ -2195,7 +2145,7 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - 6 * 60 * 60); // ~144 blocks behind -> 2 x fork detection time + pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) lockIBDState = true; return state; @@ -2333,7 +2283,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState& state, CCoinsViewCach // mark inputs spent if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { txundo.vprevout.reserve(tx.vin.size()); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { txundo.vprevout.push_back(CTxInUndo()); bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back()); assert(ret); @@ -2488,7 +2438,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex //erase all zerocoinspends in this transaction for (const CTxIn txin : tx.vin) { if (txin.scriptSig.IsZerocoinSpend()) { - CoinSpend spend = TxInToZerocoinSpend(txin); + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); if (!zerocoinDB->EraseCoinSpend(spend.getCoinSerialNumber())) return error("failed to erase spent zerocoin in block"); } @@ -2501,7 +2451,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex continue; - PublicCoin pubCoin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin pubCoin(Params().Zerocoin_Params()); if (!TxOutToPublicCoin(txout, pubCoin, state)) return error("DisconnectBlock(): TxOutToPublicCoin() failed"); @@ -2626,8 +2576,11 @@ void RecalculateZPHRMinted() CBlockIndex *pindex = chainActive[Params().Zerocoin_StartHeight()]; int nHeightEnd = chainActive.Height(); while (true) { - if (pindex->nHeight % 1000 == 0) + if (pindex->nHeight % 1000 == 0) { LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); + int percent = std::max(1, std::min(99, (int)((double)(pindex->nHeight - Params().Zerocoin_StartHeight()) * 100 / (chainActive.Height() - Params().Zerocoin_StartHeight())))); + uiInterface.ShowProgress(_("Recalculating minted ZPHR..."), percent); + } //overwrite possibly wrong vMintsInBlock data CBlock block; @@ -2636,7 +2589,7 @@ void RecalculateZPHRMinted() std::list listMints; BlockToZerocoinMintList(block, listMints); - vector vDenomsBefore = pindex->vMintDenominationsInBlock; + std::vector vDenomsBefore = pindex->vMintDenominationsInBlock; pindex->vMintDenominationsInBlock.clear(); for (auto mint : listMints) pindex->vMintDenominationsInBlock.emplace_back(mint.GetDenomination()); @@ -2646,20 +2599,25 @@ void RecalculateZPHRMinted() else break; } + uiInterface.ShowProgress("", 100); } void RecalculateZPHRSpent() { CBlockIndex* pindex = chainActive[Params().Zerocoin_StartHeight()]; + uiInterface.ShowProgress(_("Recalculating spent ZPHR..."), 0); while (true) { - if (pindex->nHeight % 1000 == 0) + if (pindex->nHeight % 1000 == 0) { LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); + int percent = std::max(1, std::min(99, (int)((double)(pindex->nHeight - Params().Zerocoin_StartHeight()) * 100 / (chainActive.Height() - Params().Zerocoin_StartHeight())))); + uiInterface.ShowProgress(_("Recalculating spent ZPHR..."), percent); + } //Rewrite zPHR supply CBlock block; assert(ReadBlockFromDisk(block, pindex)); - list listDenomsSpent = ZerocoinSpendListFromBlock(block); + std::list listDenomsSpent = ZerocoinSpendListFromBlock(block); //Reset the supply to previous block pindex->mapZerocoinSupply = pindex->pprev->mapZerocoinSupply; @@ -2694,9 +2652,13 @@ bool RecalculatePHRSupply(int nHeightStart) if (nHeightStart == Params().Zerocoin_StartHeight()) nSupplyPrev = CAmount(1880313101204990); + uiInterface.ShowProgress(_("Recalculating PHR supply..."), 0); while (true) { - if (pindex->nHeight % 1000 == 0) + if (pindex->nHeight % 1000 == 0) { LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); + int percent = std::max(1, std::min(99, (int)((double)((pindex->nHeight - nHeightStart) * 100) / (chainActive.Height() - nHeightStart)))); + uiInterface.ShowProgress(_("Recalculating PHR supply..."), percent); + } CBlock block; assert(ReadBlockFromDisk(block, pindex)); @@ -2742,7 +2704,7 @@ bool RecalculatePHRSupply(int nHeightStart) return true; } -bool ReindexAccumulators(list& listMissingCheckpoints, string& strError) +bool ReindexAccumulators(std::list& listMissingCheckpoints, std::string& strError) { // Phore: recalculate Accumulator Checkpoints that failed to database properly if (!listMissingCheckpoints.empty() && chainActive.Height() >= Params().Zerocoin_StartHeight()) { @@ -2799,7 +2761,7 @@ bool UpdateZPHRSupply(const CBlock& block, CBlockIndex* pindex) // Initialize zerocoin supply to the supply from previous block if (pindex->pprev && pindex->pprev->GetBlockHeader().nVersion > 3) { - for (auto& denom : zerocoinDenomList) { + for (auto& denom : libzerocoin::zerocoinDenomList) { pindex->mapZerocoinSupply.at(denom) = pindex->pprev->mapZerocoinSupply.at(denom); } } @@ -2846,7 +2808,7 @@ bool UpdateZPHRSupply(const CBlock& block, CBlockIndex* pindex) } } - for (auto& denom : zerocoinDenomList) + for (auto& denom : libzerocoin::zerocoinDenomList) LogPrint("zero", "%s coins for denomination %d pubcoin %s\n", __func__, denom, pindex->mapZerocoinSupply.at(denom)); return true; @@ -2931,7 +2893,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin !((pindex->nHeight == 91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight == 91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); if (fEnforceBIP30) { - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { const CCoins* coins = view.AccessCoins(tx.GetHash()); if (coins && !coins->IsPruned()) return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), @@ -2948,8 +2910,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CExtDiskTxPos pos(CDiskTxPos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())), pindex->nHeight); std::vector > vPosTxid; std::vector > vPosAddrid; - std::vector > vSpends; - vector > vMints; + std::vector > vSpends; + std::vector > vMints; if (fTxIndex) vPosTxid.reserve(block.vtx.size()); if (fAddrIndex) @@ -2959,7 +2921,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin blockundo.vtxundo.reserve(block.vtx.size() - 1); CAmount nValueOut = 0; CAmount nValueIn = 0; - vector vSpendsInBlock; + std::vector vSpendsInBlock; uint256 hashBlock = block.GetHash(); unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG; @@ -2990,15 +2952,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } //Check for double spending of serial #'s - set setSerials; + std::set setSerials; for (const CTxIn& txIn : tx.vin) { if (!txIn.scriptSig.IsZerocoinSpend()) continue; - CoinSpend spend = TxInToZerocoinSpend(txIn); + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); nValueIn += spend.getDenomination() * COIN; //queue for db write after the 'justcheck' section has concluded - vSpends.emplace_back(make_pair(spend, tx.GetHash())); + vSpends.emplace_back(std::make_pair(spend, tx.GetHash())); if (!ContextualCheckZerocoinSpend(tx, spend, pindex, hashBlock)) return state.DoS(100, error("%s: failed to add block %s with invalid zerocoinspend", __func__, tx.GetHash().GetHex()), REJECT_INVALID); @@ -3010,14 +2972,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!out.IsZerocoinMint()) continue; - PublicCoin coin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin coin(Params().Zerocoin_Params()); if (!TxOutToPublicCoin(out, coin, state)) return state.DoS(100, error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); if (!ContextualCheckZerocoinMint(tx, coin, pindex)) return state.DoS(100, error("%s: zerocoin mint failed contextual check", __func__)); - vMints.emplace_back(make_pair(coin, tx.GetHash())); + vMints.emplace_back(std::make_pair(coin, tx.GetHash())); } } } else if (!tx.IsCoinBase()) { @@ -3031,14 +2993,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!out.IsZerocoinMint()) continue; - PublicCoin coin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin coin(Params().Zerocoin_Params()); if (!TxOutToPublicCoin(out, coin, state)) return state.DoS(100, error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); if (!ContextualCheckZerocoinMint(tx, coin, pindex)) return state.DoS(100, error("%s: zerocoin mint failed contextual check", __func__)); - vMints.emplace_back(make_pair(coin, tx.GetHash())); + vMints.emplace_back(std::make_pair(coin, tx.GetHash())); } } @@ -3071,7 +3033,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin vPosTxid.push_back(std::make_pair(tx.GetHash(), pos)); if (fAddrIndex) { if (!tx.IsCoinBase()) { - BOOST_FOREACH(const CTxIn &txin, tx.vin) { + for (const CTxIn &txin : tx.vin) { CCoins coins; view.GetCoins(txin.prevout.hash, coins); if (coins.IsAvailable(txin.prevout.n)) { @@ -3079,7 +3041,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } } - BOOST_FOREACH(const CTxOut &txout, tx.vout) + for (const CTxOut &txout : tx.vout) BuildAddrIndex(txout.scriptPubKey, pos, vPosAddrid); } @@ -3115,9 +3077,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Ensure that accumulator checkpoints are valid and in the same state as this instance of the chain AccumulatorMap mapAccumulators(GetZerocoinParams(pindex->nHeight)); - if (!ValidateAccumulatorCheckpoint(block, pindex, mapAccumulators)) - return state.DoS(100, error("%s: Failed to validate accumulator checkpoint for block=%s height=%d", __func__, - block.GetHash().GetHex(), pindex->nHeight), REJECT_INVALID, "bad-acc-checkpoint"); + if (!ValidateAccumulatorCheckpoint(block, pindex, mapAccumulators)) { + if (!ShutdownRequested()) { + return state.DoS(100, error("%s: Failed to validate accumulator checkpoint for block=%s height=%d", __func__, + block.GetHash().GetHex(), pindex->nHeight), REJECT_INVALID, "bad-acc-checkpoint"); + } + return error("%s: Failed to validate accumulator checkpoint for block=%s height=%d because wallet is shutting down", __func__, + block.GetHash().GetHex(), pindex->nHeight); + } if (!control.Wait()) return state.DoS(100, false); @@ -3148,8 +3115,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } //Record zPHR serials - set setAddedTx; - for (pair pSpend : vSpends) { + std::set setAddedTx; + for (std::pair pSpend : vSpends) { //record spend to database if (!zerocoinDB->WriteCoinSpend(pSpend.first.getCoinSerialNumber(), pSpend.second)) return state.Error(("Failed to record coin serial to database")); @@ -3179,7 +3146,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } //Record mints to db - for (pair pMint : vMints) { + for (std::pair pMint : vMints) { if (!zerocoinDB->WriteCoinMint(pMint.first, pMint.second)) return state.Error(("Failed to record new mint to database")); } @@ -3267,7 +3234,7 @@ bool static FlushStateToDisk(CValidationState& state, FlushStateMode mode) FlushBlockFile(); // Then update all block file information (which may refer to block and undo files). bool fileschanged = false; - for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end();) { + for (std::set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end();) { if (!pblocktree->WriteBlockFileInfo(*it, vinfoBlockFile[*it])) { return state.Error("Failed to write to block index"); } @@ -3277,7 +3244,7 @@ bool static FlushStateToDisk(CValidationState& state, FlushStateMode mode) if (fileschanged && !pblocktree->WriteLastBlockFile(nLastBlockFile)) { return state.Error("Failed to write to block index"); } - for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end();) { + for (std::set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end();) { if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(*it))) { return state.Error("Failed to write to block index"); } @@ -3371,9 +3338,9 @@ bool static DisconnectTip(CValidationState& state, bool fBare) if (!fBare) { // Resurrect mempool transactions from the disconnected block. - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { // ignore validation errors in resurrected transactions - list removed; + std::list removed; CValidationState stateDummy; if (tx.IsCoinBase() || tx.IsCoinStake() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) mempool.remove(tx, removed, true); @@ -3386,7 +3353,7 @@ bool static DisconnectTip(CValidationState& state, bool fBare) UpdateTip(pindexDelete->pprev); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { SyncWithWallets(tx, NULL); } return true; @@ -3454,18 +3421,18 @@ bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool. - list txConflicted; + std::list txConflicted; mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted); mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); // Tell wallet about transactions that went from mempool // to conflicted: - BOOST_FOREACH (const CTransaction& tx, txConflicted) { + for (const CTransaction& tx : txConflicted) { SyncWithWallets(tx, NULL); } // ... and about transactions that got confirmed: - BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { + for (const CTransaction& tx : pblock->vtx) { SyncWithWallets(tx, pblock); } @@ -3509,12 +3476,12 @@ bool DisconnectBlockAndInputs(CValidationState& state, CTransaction txLock) bool foundConflictingTx = false; //remove anything conflicting in the memory pool - list txConflicted; + std::list txConflicted; mempool.removeConflicts(txLock, txConflicted); // List of what to disconnect (typically nothing) - vector vDisconnect; + std::vector vDisconnect; for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0 && !foundConflictingTx && i < 6; i++) { vDisconnect.push_back(BlockReading); @@ -3527,10 +3494,10 @@ bool DisconnectBlockAndInputs(CValidationState& state, CTransaction txLock) // Queue memory transactions to resurrect. // We only do this for blocks after the last checkpoint (reorganisation before that // point should only happen with -reindex/-loadblock, or a misbehaving peer. - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (!tx.IsCoinBase()) { - BOOST_FOREACH (const CTxIn& in1, txLock.vin) { - BOOST_FOREACH (const CTxIn& in2, tx.vin) { + for (const CTxIn& in1 : txLock.vin) { + for (const CTxIn& in2 : tx.vin) { if (in1.prevout == in2.prevout) foundConflictingTx = true; } } @@ -3551,7 +3518,7 @@ bool DisconnectBlockAndInputs(CValidationState& state, CTransaction txLock) if (vDisconnect.size() > 0) { LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString()); - BOOST_FOREACH (CBlockIndex* pindex, vDisconnect) { + for (CBlockIndex* pindex : vDisconnect) { LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString()); DisconnectTip(state, false); } @@ -3746,7 +3713,7 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); } @@ -3859,11 +3826,7 @@ CBlockIndex* AddToBlockIndex(const CBlock& block) // to avoid miners withholding blocks but broadcasting headers, to get a // competitive advantage. pindexNew->nSequenceId = 0; - BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - - //mark as PoS seen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); + BlockMap::iterator mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); @@ -3929,7 +3892,7 @@ bool ReceivedBlockTransactions(const CBlock& block, CValidationState& state, CBl if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS. - deque queue; + std::deque queue; queue.push_back(pindexNew); // Recursively process any descendant blocks that now may be eligible to be connected. @@ -4132,13 +4095,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // ----------- swiftTX transaction scanning ----------- if (IsSporkActive(SPORK_3_SWIFTTX_BLOCK_FILTERING)) { - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (!tx.IsCoinBase()) { //only reject blocks when it's based on complete consensus - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { - mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); + mapRejectedBlocks.insert(std::make_pair(block.GetHash(), GetTime())); LogPrintf("CheckBlock() : found conflicting transaction with transaction lock %s %s\n", mapLockedInputs[in.prevout].ToString(), tx.GetHash().ToString()); return state.DoS(0, error("CheckBlock() : found conflicting transaction with transaction lock"), REJECT_INVALID, "conflicting-tx-ix"); @@ -4171,7 +4134,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // that this block is invalid, so don't issue an outright ban. if (nHeight != 0 && !IsInitialBlockDownload()) { if (!IsBlockPayeeValid(block, nHeight)) { - mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); + mapRejectedBlocks.insert(std::make_pair(block.GetHash(), GetTime())); return state.DoS(0, error("CheckBlock() : Couldn't find masternode/budget payment"), REJECT_INVALID, "bad-cb-payee"); } @@ -4183,7 +4146,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo unsigned int nSigOps = 0; - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { nSigOps += GetLegacySigOpCount(tx); } if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST) @@ -4217,7 +4180,7 @@ bool CheckWork(const CBlock block, CBlockIndex* const pindexPrev) return false; } if(!mapProofOfStake.count(hash)) // add to mapProofOfStake - mapProofOfStake.insert(make_pair(hash, hashProofOfStake)); + mapProofOfStake.insert(std::make_pair(hash, hashProofOfStake)); } return true; } @@ -4366,7 +4329,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return state.DoS(50, error("CheckBlockHeader() : block version must be above 4 after ZerocoinStartHeight"), REJECT_INVALID, "block-version"); - vector vBlockSerials; + std::vector vBlockSerials; for (const CTransaction& tx : block.vtx) { if (!CheckTransaction(tx, true, chainActive.Height() + 1 >= Params().Zerocoin_StartHeight(), state, GetSporkValue(SPORK_17_SEGWIT_ACTIVATION) < block.nTime)) return error("CheckBlock() : CheckTransaction failed"); @@ -4391,7 +4354,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn } // Check that all transactions are finalized - BOOST_FOREACH (const CTransaction& tx, block.vtx) + for (const CTransaction& tx : block.vtx) if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { return state.DoS(10, error("%s : contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } @@ -4798,7 +4761,11 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex* const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { AssertLockHeld(cs_main); - assert(pindexPrev && pindexPrev == chainActive.Tip()); + assert(pindexPrev); + if (pindexPrev != chainActive.Tip()) { + LogPrintf("%s : No longer working on chain tip\n", __func__); + return false; + } CCoinsViewCache viewNew(pcoinsTip); CBlockIndex indexDummy(block); @@ -4833,7 +4800,7 @@ bool AbortNode(const std::string& strMessage, const std::string& userMessage) bool CheckDiskSpace(uint64_t nAdditionalBytes) { - uint64_t nFreeBytesAvailable = filesystem::space(GetDataDir()).available; + uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available; // Check for nMinDiskSpace bytes (currently 50MB) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) @@ -4893,19 +4860,15 @@ CBlockIndex* InsertBlockIndex(uint256 hash) // Create new CBlockIndex* pindexNew = new CBlockIndex(); if (!pindexNew) - throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); - mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - - //mark as PoS seen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); + throw std::runtime_error("LoadBlockIndex() : new CBlockIndex failed"); + mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); return pindexNew; } -bool static LoadBlockIndexDB(string& strError) +bool static LoadBlockIndexDB(std::string& strError) { if (!pblocktree->LoadBlockIndexGuts()) return false; @@ -4913,14 +4876,14 @@ bool static LoadBlockIndexDB(string& strError) boost::this_thread::interruption_point(); // Calculate nChainWork - vector > vSortedByHeight; + std::vector > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); for (const std::pair& item : mapBlockIndex) { CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); + vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH (const PAIRTYPE(int, CBlockIndex*) & item, vSortedByHeight) { + std::sort(vSortedByHeight.begin(), vSortedByHeight.end()); + for (const PAIRTYPE(int, CBlockIndex*) & item : vSortedByHeight) { CBlockIndex* pindex = item.second; pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); if (pindex->nStatus & BLOCK_HAVE_DATA) { @@ -4964,7 +4927,7 @@ bool static LoadBlockIndexDB(string& strError) // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); - set setBlkDataFiles; + std::set setBlkDataFiles; for (const std::pair& item : mapBlockIndex) { CBlockIndex* pindex = item.second; if (pindex->nStatus & BLOCK_HAVE_DATA) { @@ -5173,13 +5136,34 @@ bool RewindBlockIndex(const CChainParams& params) void UnloadBlockIndex() { - mapBlockIndex.clear(); + LOCK(cs_main); setBlockIndexCandidates.clear(); chainActive.SetTip(NULL); pindexBestInvalid = NULL; + pindexBestHeader = NULL; + mempool.clear(); + mapOrphanTransactions.clear(); + mapOrphanTransactionsByPrev.clear(); + nSyncStarted = 0; + mapBlocksUnlinked.clear(); + vinfoBlockFile.clear(); + nLastBlockFile = 0; + nBlockSequenceId = 1; + mapBlockSource.clear(); + mapBlocksInFlight.clear(); + nQueuedValidatedHeaders = 0; + nPreferredDownload = 0; + setDirtyBlockIndex.clear(); + setDirtyFileInfo.clear(); + mapNodeState.clear(); + + for (BlockMap::value_type& entry : mapBlockIndex) { + delete entry.second; + } + mapBlockIndex.clear(); } -bool LoadBlockIndex(string& strError) +bool LoadBlockIndex(std::string& strError) { // Load block index from databases if (!fReindex && !LoadBlockIndexDB(strError)) @@ -5297,7 +5281,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) } // Recursively process earlier encountered successors of this block - deque queue; + std::deque queue; queue.push_back(hash); while (!queue.empty()) { uint256 head = queue.front(); @@ -5478,11 +5462,11 @@ void static CheckBlockIndex() // CAlert // -string GetWarnings(string strFor) +std::string GetWarnings(std::string strFor) { int nPriority = 0; - string strStatusBar; - string strRPC; + std::string strStatusBar; + std::string strRPC; if (!CLIENT_VERSION_IS_RELEASE) strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for staking or merchant applications!"); @@ -5507,7 +5491,7 @@ string GetWarnings(string strFor) // Alerts { LOCK(cs_mapAlerts); - BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) { + for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) { const CAlert& alert = item.second; if (alert.AppliesToMe() && alert.nPriority > nPriority) { nPriority = alert.nPriority; @@ -5599,7 +5583,7 @@ void static ProcessGetData(CNode* pfrom) { std::deque::iterator it = pfrom->vRecvGetData.begin(); - vector vNotFound; + std::vector vNotFound; LOCK(cs_main); @@ -5654,7 +5638,7 @@ void static ProcessGetData(CNode* pfrom) // Thus, the protocol spec specified allows for us to provide duplicate txn here, // however we MUST always provide at least what the remote peer needs typedef std::pair PairType; - BOOST_FOREACH (PairType& pair, merkleBlock.vMatchedTxn) + for (PairType& pair : merkleBlock.vMatchedTxn) if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second))) pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]); } @@ -5667,7 +5651,7 @@ void static ProcessGetData(CNode* pfrom) // Bypass PushInventory, this must send even if redundant, // and we want it right after the last block so they don't // wait for other stuff first. - vector vInv; + std::vector vInv; vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); pfrom->PushMessage(NetMsgType::INV, vInv); pfrom->hashContinue = 0; @@ -5678,7 +5662,7 @@ void static ProcessGetData(CNode* pfrom) bool pushed = false; { LOCK(cs_mapRelay); - map::iterator mi = mapRelay.find(inv); + std::map::iterator mi = mapRelay.find(inv); if (mi != mapRelay.end()) { pfrom->PushMessageWithFlag(inv.type == MSG_WITNESS_TX ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, inv.GetCommand(), (*mi).second); pushed = true; @@ -5828,7 +5812,7 @@ void static ProcessGetData(CNode* pfrom) } bool fRequestedSporksIDB = false; -bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) +bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { if (fDebug) LogPrintf("received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); @@ -5840,7 +5824,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (strCommand == NetMsgType::VERSION) { // Each connection can only send one version message if (pfrom->nVersion != 0) { - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message")); LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; @@ -5869,7 +5853,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; if (!vRecv.empty()) { - vRecv >> LIMITED_STRING(pfrom->strSubVer, 256); + vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } // broken releases with wrong blockchain data @@ -5916,7 +5900,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Change version pfrom->PushMessage(NetMsgType::VERACK); - pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + pfrom->ssSend.SetVersion(std::min(pfrom->nVersion, PROTOCOL_VERSION)); // Phore: We use certain sporks during IBD, so check to see if they are // available. If not, ask the first peer connected for them. @@ -5958,13 +5942,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Relay alerts { LOCK(cs_mapAlerts); - BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) + for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) item.second.RelayTo(pfrom); } pfrom->fSuccessfullyConnected = true; - string remoteAddr; + std::string remoteAddr; if (fLogIPs) remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); @@ -5988,7 +5972,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::VERACK) { - pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + pfrom->SetRecvVersion(std::min(pfrom->nVersion, PROTOCOL_VERSION)); // Mark this node as currently connected, so we update its timestamp later. if (pfrom->fNetworkNode) { @@ -5999,7 +5983,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::ADDR) { - vector vAddr; + std::vector vAddr; vRecv >> vAddr; // Don't want addr from older versions unless seeding @@ -6012,10 +5996,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Store the new addresses - vector vAddrOk; + std::vector vAddrOk; int64_t nNow = GetAdjustedTime(); int64_t nSince = nNow - 10 * 60; - BOOST_FOREACH (CAddress& addr, vAddr) { + for (CAddress& addr : vAddr) { boost::this_thread::interruption_point(); if (!(addr.nServices & NODE_NETWORK)) @@ -6037,18 +6021,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint64_t hashAddr = addr.GetHash(); uint256 hashRand = hashSalt ^ (hashAddr << 32) ^ ((GetTime() + hashAddr) / (24 * 60 * 60)); hashRand = Hash(BEGIN(hashRand), END(hashRand)); - multimap mapMix; - BOOST_FOREACH (CNode* pnode, vNodes) { + std::multimap mapMix; + for (CNode* pnode : vNodes) { if (pnode->nVersion < CADDR_TIME_VERSION) continue; unsigned int nPointer; memcpy(&nPointer, &pnode, sizeof(nPointer)); uint256 hashKey = hashRand ^ nPointer; hashKey = Hash(BEGIN(hashKey), END(hashKey)); - mapMix.insert(make_pair(hashKey, pnode)); + mapMix.insert(std::make_pair(hashKey, pnode)); } int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) - for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) + for (std::multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) ((*mi).second)->PushAddress(addr); } } @@ -6065,7 +6049,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::INV) { - vector vInv; + std::vector vInv; vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) { LOCK(cs_main); @@ -6129,7 +6113,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::GETDATA) { - vector vInv; + std::vector vInv; vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) { LOCK(cs_main); @@ -6205,7 +6189,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end - vector vHeaders; + std::vector vHeaders; int nLimit = MAX_HEADERS_RESULTS; if (fDebug) LogPrintf("getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); @@ -6219,14 +6203,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::TX || strCommand == NetMsgType::DSTX) { - vector vWorkQueue; - vector vEraseQueue; + std::vector vWorkQueue; + std::vector vEraseQueue; CTransaction tx; //masternode signed transaction bool ignoreFees = false; CTxIn vin; - vector vchSig; + std::vector vchSig; int64_t sigTime; if (strCommand == NetMsgType::TX) { @@ -6264,7 +6248,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, dstx.vchSig = vchSig; dstx.sigTime = sigTime; - mapObfuscationBroadcastTxes.insert(make_pair(tx.GetHash(), dstx)); + mapObfuscationBroadcastTxes.insert(std::make_pair(tx.GetHash(), dstx)); } } } @@ -6293,12 +6277,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uiInterface.NotifyTransaction(tx.GetHash()); // Recursively process any orphan transactions that depended on this one - set setMisbehaving; + std::set setMisbehaving; for(unsigned int i = 0; i < vWorkQueue.size(); i++) { - map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); + std::map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); if(itByPrev == mapOrphanTransactionsByPrev.end()) continue; - for(set::iterator mi = itByPrev->second.begin(); + for(std::set::iterator mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { const uint256 &orphanHash = *mi; @@ -6336,7 +6320,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - BOOST_FOREACH (uint256 hash, vEraseQueue)EraseOrphanTx(hash); + for (uint256 hash : vEraseQueue)EraseOrphanTx(hash); } else if (tx.IsZerocoinSpend() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingZerocoinInputs, false, ignoreFees)) { //Presstab: ZCoin has a bunch of code commented out here. Is this something that should have more going on? //Also there is nothing that handles fMissingZerocoinInputs. Does there need to be? @@ -6416,7 +6400,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } CBlockIndex* pindexLast = NULL; - BOOST_FOREACH (const CBlockHeader& header, headers) { + for (const CBlockHeader& header : headers) { CValidationState state; if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) { LOCK(cs_main); @@ -6502,8 +6486,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // getaddr message mitigates the attack. else if ((strCommand == NetMsgType::GETADDR) && (pfrom->fInbound)) { pfrom->vAddrToSend.clear(); - vector vAddr = addrman.GetAddr(); - BOOST_FOREACH (const CAddress& addr, vAddr) + std::vector vAddr = addrman.GetAddr(); + for (const CAddress& addr : vAddr) pfrom->PushAddress(addr); } @@ -6513,8 +6497,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, std::vector vtxid; mempool.queryHashes(vtxid); - vector vInv; - BOOST_FOREACH (uint256& hash, vtxid) { + std::vector vInv; + for (uint256& hash : vtxid) { CInv inv(MSG_TX, hash); CTransaction tx; bool fInMemPool = mempool.lookup(hash, tx); @@ -6618,7 +6602,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->setKnown.insert(alertHash); { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) alert.RelayTo(pnode); } } else { @@ -6662,7 +6646,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::FILTERADD) { - vector vData; + std::vector vData; vRecv >> vData; // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object, @@ -6693,12 +6677,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::REJECT) { if (fDebug) { try { - string strMsg; + std::string strMsg; unsigned char ccode; - string strReason; + std::string strReason; vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); - ostringstream ss; + std::ostringstream ss; ss << strMsg << " code " << itostr(ccode) << ": " << strReason; if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX) { @@ -6714,7 +6698,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } else { //probably one the extensions - obfuScationPool.ProcessMessageObfuscation(pfrom, strCommand, vRecv); mnodeman.ProcessMessage(pfrom, strCommand, vRecv); budget.ProcessMessage(pfrom, strCommand, vRecv); masternodePayments.ProcessMessageMasternodePayments(pfrom, strCommand, vRecv); @@ -6794,7 +6777,7 @@ bool ProcessMessages(CNode* pfrom) LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); continue; } - string strCommand = hdr.GetCommand(); + std::string strCommand = hdr.GetCommand(); // Message size unsigned int nMessageSize = hdr.nMessageSize; @@ -6816,7 +6799,7 @@ bool ProcessMessages(CNode* pfrom) fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); boost::this_thread::interruption_point(); } catch (std::ios_base::failure& e) { - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", SanitizeString(strCommand), nMessageSize, e.what()); @@ -6892,7 +6875,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) static int64_t nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { // Periodically clear setAddrKnown to allow refresh broadcasts if (nLastRebroadcast) pnode->setAddrKnown.clear(); @@ -6908,9 +6891,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Message: addr // if (fSendTrickle) { - vector vAddr; + std::vector vAddr; vAddr.reserve(pto->vAddrToSend.size()); - BOOST_FOREACH (const CAddress& addr, pto->vAddrToSend) { + for (const CAddress& addr : pto->vAddrToSend) { // returns true if wasn't already contained in the set if (pto->setAddrKnown.insert(addr).second) { vAddr.push_back(addr); @@ -6941,8 +6924,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle) state.fShouldBan = false; } - BOOST_FOREACH (const CBlockReject& reject, state.rejects) - pto->PushMessage(NetMsgType::REJECT, (string) "block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); + for (const CBlockReject& reject : state.rejects) + pto->PushMessage(NetMsgType::REJECT, (std::string) "block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); state.rejects.clear(); // Start block sync @@ -6971,13 +6954,13 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // // Message: inventory // - vector vInv; - vector vInvWait; + std::vector vInv; + std::vector vInvWait; { LOCK(pto->cs_inventory); vInv.reserve(pto->vInventoryToSend.size()); vInvWait.reserve(pto->vInventoryToSend.size()); - BOOST_FOREACH (const CInv& inv, pto->vInventoryToSend) { + for (const CInv& inv : pto->vInventoryToSend) { if ((inv.type == MSG_TX || inv.type == MSG_WITNESS_TX) && pto->setInventoryKnown.count(inv)) continue; @@ -7033,12 +7016,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // // Message: getdata (blocks) // - vector vGetData; + std::vector vGetData; if (!pto->fDisconnect && !pto->fClient && fFetch && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - vector vToDownload; + std::vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); - BOOST_FOREACH(CBlockIndex *pindex, vToDownload) { + for (CBlockIndex *pindex : vToDownload) { if (State(pto->GetId())->fHaveWitness || GetSporkValue(SPORK_17_SEGWIT_ACTIVATION) > pindex->pprev->nTime) { vGetData.push_back(CInv(State(staller)->fHaveWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK, pindex->GetBlockHash())); MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), pindex); diff --git a/src/main.h b/src/main.h index 4a6d769f0a82..3a887efc52a9 100644 --- a/src/main.h +++ b/src/main.h @@ -125,6 +125,9 @@ static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600; /** Enable bloom filter */ static const bool DEFAULT_PEERBLOOMFILTERS = true; +/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; + struct BlockHasher { size_t operator()(const uint256& hash) const { return hash.GetLow64(); } }; @@ -150,6 +153,7 @@ extern bool fCheckBlockIndex; extern unsigned int nCoinCacheSize; extern CFeeRate minRelayTxFee; extern bool fAlerts; +extern int64_t nMaxTipAge; extern bool fVerifyingBlocks; extern bool fLargeWorkForkFound; @@ -162,7 +166,6 @@ extern int64_t nReserveBalance; extern std::map mapRejectedBlocks; extern std::map mapHashedBlocks; -extern std::set > setStakeSeen; extern std::map mapZerocoinspends; //txid, time received /** Best header we've seen so far (used for getheaders queries' starting points). */ @@ -177,8 +180,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); -/** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); @@ -227,19 +228,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); -// ***TODO*** probably not the right place for these 2 -/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckProofOfWork(uint256 hash, unsigned int nBits); - /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(std::string strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256& hash, CTransaction& tx, uint256& hashBlock, bool fAllowSlow = false); -/** Find the best known block, and make it the tip of the block chain */ - -bool DisconnectBlocksAndReprocess(int blocks); // ***TODO*** double ConvertBitsToDouble(unsigned int nBits); @@ -268,7 +262,6 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact int GetInputAge(CTxIn& vin); int GetInputAgeIX(uint256 nTXHash, CTxIn& vin); -bool GetCoinAge(const CTransaction& tx, unsigned int nTxTime, uint64_t& nCoinAge); int GetIXConfirmations(uint256 nTXHash); struct CNodeStateStats { @@ -415,11 +408,11 @@ bool CheckZerocoinSpend(const CTransaction& tx, bool fVerifySignature, CValidati bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend& spend, CBlockIndex* pindex); libzerocoin::CoinSpend TxInToZerocoinSpend(const CTxIn& txin); bool TxOutToPublicCoin(const CTxOut txout, libzerocoin::PublicCoin& pubCoin, CValidationState& state); -bool BlockToPubcoinList(const CBlock& block, list& listPubcoins); +bool BlockToPubcoinList(const CBlock& block, std::list& listPubcoins); bool BlockToZerocoinMintList(const CBlock& block, std::list& vMints); bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomination denom, std::vector& vValues); std::list ZerocoinSpendListFromBlock(const CBlock& block); -void FindMints(vector vMintsToFind, vector& vMintsToUpdate, vector& vMissingMints); +void FindMints(std::vector vMintsToFind, std::vector& vMintsToUpdate, std::vector& vMissingMints); bool GetZerocoinMint(const CBigNum& bnPubcoin, uint256& txHash); bool IsSerialKnown(const CBigNum& bnSerial); bool IsSerialInBlockchain(const CBigNum& bnSerial, int& nHeightTx); @@ -435,7 +428,7 @@ bool IsBlockHashInChain(const uint256& hashBlock); void RecalculateZPHRSpent(); void RecalculateZPHRMinted(); bool RecalculatePHRSupply(int nHeightStart); -bool ReindexAccumulators(list& listMissingCheckpoints, string& strError); +bool ReindexAccumulators(std::list& listMissingCheckpoints, std::string& strError); /** diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 5e7fd4f62a76..6d152aee6541 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -8,6 +8,7 @@ #include "main.h" #include "addrman.h" +#include "chainparams.h" #include "masternode-budget.h" #include "masternode-sync.h" #include "masternode.h" @@ -33,15 +34,6 @@ CAmount GetBudgetSystemCollateralAmount(int nHeight) { } } -int GetBudgetPaymentCycleBlocks() -{ - // Amount of blocks in a months period of time (using 1 minutes per) = (60*24*30) - if (Params().NetworkID() == CBaseChainParams::MAIN) return 43200; - //for testing purposes - - return 864; //ten times per day -} - bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, std::string& strError, int64_t& nTime, int& nConf, bool fBudgetFinalization) { CTransaction txCollateral; @@ -59,7 +51,7 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s findScript << OP_RETURN << ToByteVector(nExpectedHash); bool foundOpReturn = false; - BOOST_FOREACH (const CTxOut o, txCollateral.vout) { + for (const CTxOut o : txCollateral.vout) { if (!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()) { strError = strprintf("Invalid Script %s", txCollateral.ToString()); LogPrint("mnbudget","CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); @@ -163,14 +155,14 @@ void CBudgetManager::SubmitFinalBudget() nCurrentHeight = chainActive.Height(); } - int nBlockStart = nCurrentHeight - nCurrentHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + int nBlockStart = nCurrentHeight - nCurrentHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); if (nSubmittedHeight >= nBlockStart){ LogPrint("mnbudget","CBudgetManager::SubmitFinalBudget - nSubmittedHeight(=%ld) < nBlockStart(=%ld) condition not fulfilled.\n", nSubmittedHeight, nBlockStart); return; } - - // Submit final budget during the last 2 days (2880 blocks) before payment for Mainnet, about 9 minutes (9 blocks) for Testnet - int finalizationWindow = ((GetBudgetPaymentCycleBlocks() / 30) * 2); + + // Submit final budget during the last 2 days (2880 blocks) before payment for Mainnet, about 9 minutes (9 blocks) for Testnet + int finalizationWindow = ((Params().GetBudgetCycleBlocks() / 30) * 2); if (Params().NetworkID() == CBaseChainParams::TESTNET || Params().NetworkID() == CBaseChainParams::REGTEST) { @@ -231,7 +223,7 @@ void CBudgetManager::SubmitFinalBudget() pwalletMain->CommitTransaction(wtx, reservekey, "NO-ix"); tx = (CTransaction)wtx; txidCollateral = tx.GetHash(); - mapCollateralTxids.insert(make_pair(tempBudget.GetHash(), txidCollateral)); + mapCollateralTxids.insert(std::make_pair(tempBudget.GetHash(), txidCollateral)); } else { txidCollateral = mapCollateralTxids[tempBudget.GetHash()]; } @@ -274,7 +266,7 @@ void CBudgetManager::SubmitFinalBudget() } LOCK(cs); - mapSeenFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); + mapSeenFinalizedBudgets.insert(std::make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); finalizedBudgetBroadcast.Relay(); budget.AddFinalizedBudget(finalizedBudgetBroadcast); nSubmittedHeight = nCurrentHeight; @@ -343,7 +335,7 @@ CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& objToLoad, bool fDryRun) // Don't try to resize to a negative number if file is small if (dataSize < 0) dataSize = 0; - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -445,7 +437,7 @@ bool CBudgetManager::AddFinalizedBudget(CFinalizedBudget& finalizedBudget) return false; } - mapFinalizedBudgets.insert(make_pair(finalizedBudget.GetHash(), finalizedBudget)); + mapFinalizedBudgets.insert(std::make_pair(finalizedBudget.GetHash(), finalizedBudget)); return true; } @@ -462,7 +454,7 @@ bool CBudgetManager::AddProposal(CBudgetProposal& budgetProposal) return false; } - mapProposals.insert(make_pair(budgetProposal.GetHash(), budgetProposal)); + mapProposals.insert(std::make_pair(budgetProposal.GetHash(), budgetProposal)); LogPrint("mnbudget","CBudgetManager::AddProposal - proposal %s added\n", budgetProposal.GetName ().c_str ()); return true; } @@ -484,8 +476,8 @@ void CBudgetManager::CheckAndRemove() LogPrint("mnbudget", "CBudgetManager::CheckAndRemove at Height=%d\n", nHeight); - map tmpMapFinalizedBudgets; - map tmpMapProposals; + std::map tmpMapFinalizedBudgets; + std::map tmpMapProposals; std::string strError = ""; @@ -505,7 +497,7 @@ void CBudgetManager::CheckAndRemove() if (pfinalizedBudget->fValid) { pfinalizedBudget->CheckAndVote(); - tmpMapFinalizedBudgets.insert(make_pair(pfinalizedBudget->GetHash(), *pfinalizedBudget)); + tmpMapFinalizedBudgets.insert(std::make_pair(pfinalizedBudget->GetHash(), *pfinalizedBudget)); } ++it; @@ -525,7 +517,7 @@ void CBudgetManager::CheckAndRemove() pbudgetProposal->strProposalName.c_str(), pbudgetProposal->nFeeTXHash.ToString().c_str()); } if (pbudgetProposal->fValid) { - tmpMapProposals.insert(make_pair(pbudgetProposal->GetHash(), *pbudgetProposal)); + tmpMapProposals.insert(std::make_pair(pbudgetProposal->GetHash(), *pbudgetProposal)); } ++it2; @@ -657,7 +649,7 @@ bool CBudgetManager::IsBudgetPaymentBlock(int nBlockHeight) ++it; } - LogPrint("mnbudget","CBudgetManager::IsBudgetPaymentBlock() - nHighestCount: %lli, 5%% of Masternodes: %lli. Number of budgets: %lli\n", + LogPrint("mnbudget","CBudgetManager::IsBudgetPaymentBlock() - nHighestCount: %lli, 5%% of Masternodes: %lli. Number of finalized budgets: %lli\n", nHighestCount, nFivePercent, mapFinalizedBudgets.size()); // If budget doesn't have 5% of the network votes, then we should pay a masternode instead @@ -691,7 +683,7 @@ TrxValidationStatus CBudgetManager::IsTransactionValid(const CTransaction& txNew ++it; } - LogPrint("mnbudget","CBudgetManager::IsTransactionValid() - nHighestCount: %lli, 5%% of Masternodes: %lli mapFinalizedBudgets.size(): %ld\n", + LogPrint("mnbudget","CBudgetManager::IsTransactionValid() - nHighestCount: %lli, 5%% of Masternodes: %lli mapFinalizedBudgets.size(): %ld\n", nHighestCount, nFivePercent, mapFinalizedBudgets.size()); /* If budget doesn't have 5% of the network votes, then we should pay a masternode instead @@ -709,7 +701,7 @@ TrxValidationStatus CBudgetManager::IsTransactionValid(const CTransaction& txNew strProposals = pfinalizedBudget->GetProposals(); LogPrint("mnbudget","CBudgetManager::IsTransactionValid - checking budget (%s) with blockstart %lli, blockend %lli, nBlockHeight %lli, votes %lli, nCountThreshold %lli\n", - strProposals.c_str(), pfinalizedBudget->GetBlockStart(), pfinalizedBudget->GetBlockEnd(), + strProposals.c_str(), pfinalizedBudget->GetBlockStart(), pfinalizedBudget->GetBlockEnd(), nBlockHeight, pfinalizedBudget->GetVoteCount(), nCountThreshold); if (pfinalizedBudget->GetVoteCount() > nCountThreshold) { @@ -734,7 +726,7 @@ TrxValidationStatus CBudgetManager::IsTransactionValid(const CTransaction& txNew if (!fThreshold) { transactionStatus = TrxValidationStatus::VoteThreshold; } - + // We looked through all of the known budgets return transactionStatus; } @@ -782,7 +774,7 @@ std::vector CBudgetManager::GetBudget() std::map::iterator it = mapProposals.begin(); while (it != mapProposals.end()) { (*it).second.CleanAndRemove(false); - vBudgetPorposalsSort.push_back(make_pair(&((*it).second), (*it).second.GetYeas() - (*it).second.GetNays())); + vBudgetPorposalsSort.push_back(std::make_pair(&((*it).second), (*it).second.GetYeas() - (*it).second.GetNays())); ++it; } @@ -796,8 +788,8 @@ std::vector CBudgetManager::GetBudget() CBlockIndex* pindexPrev = chainActive.Tip(); if (pindexPrev == NULL) return vBudgetProposalsRet; - int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); - int nBlockEnd = nBlockStart + GetBudgetPaymentCycleBlocks() - 1; + int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); + int nBlockEnd = nBlockStart + Params().GetBudgetCycleBlocks() - 1; CAmount nTotalBudget = GetTotalBudget(nBlockStart); @@ -862,7 +854,7 @@ std::vector CBudgetManager::GetFinalizedBudgets() while (it != mapFinalizedBudgets.end()) { CFinalizedBudget* pfinalizedBudget = &((*it).second); - vFinalizedBudgetsSort.push_back(make_pair(pfinalizedBudget, pfinalizedBudget->GetVoteCount())); + vFinalizedBudgetsSort.push_back(std::make_pair(pfinalizedBudget, pfinalizedBudget->GetVoteCount())); ++it; } std::sort(vFinalizedBudgetsSort.begin(), vFinalizedBudgetsSort.end(), sortFinalizedBudgetsByVotes()); @@ -950,7 +942,7 @@ void CBudgetManager::NewBlock() } LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= ActiveProtocol()) Sync(pnode, 0, true); @@ -1083,7 +1075,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData return; } - mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); + mapSeenMasternodeBudgetProposals.insert(std::make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); if (!budgetProposalBroadcast.IsValid(strError)) { LogPrint("mnbudget","mprop - invalid budget proposal - %s\n", strError); @@ -1120,7 +1112,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } - mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + mapSeenMasternodeBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); if (!vote.SignatureValid(true)) { if (masternodeSync.IsSynced()) { LogPrintf("CBudgetManager::ProcessMessage() : mvote - signature invalid\n"); @@ -1158,7 +1150,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData return; } - mapSeenFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); + mapSeenFinalizedBudgets.insert(std::make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); if (!finalizedBudgetBroadcast.IsValid(strError)) { LogPrint("mnbudget","fbs - invalid finalized budget - %s\n", strError); @@ -1194,7 +1186,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData return; } - mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + mapSeenFinalizedBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); if (!vote.SignatureValid(true)) { if (masternodeSync.IsSynced()) { LogPrintf("CBudgetManager::ProcessMessage() : fbvote - signature from masternode %s invalid\n", HexStr(pmn->pubKeyMasternode)); @@ -1523,7 +1515,7 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) } // Calculate maximum block this proposal will be valid, which is start of proposal + (number of payments * cycle) - int nProposalEnd = GetBlockStart() + (GetBudgetPaymentCycleBlocks() * GetTotalPaymentCount()); + int nProposalEnd = GetBlockStart() + (Params().GetBudgetCycleBlocks() * GetTotalPaymentCount()); // if (GetBlockEnd() < pindexPrev->nHeight - GetBudgetPaymentCycleBlocks() / 2) { if(nProposalEnd < pindexPrev->nHeight){ @@ -1639,7 +1631,7 @@ int CBudgetProposal::GetBlockStartCycle() { //end block is half way through the next cycle (so the proposal will be removed much after the payment is sent) - return nBlockStart - nBlockStart % GetBudgetPaymentCycleBlocks(); + return nBlockStart - nBlockStart % Params().GetBudgetCycleBlocks(); } int CBudgetProposal::GetBlockCurrentCycle() @@ -1649,7 +1641,7 @@ int CBudgetProposal::GetBlockCurrentCycle() if (pindexPrev->nHeight >= GetBlockEndCycle()) return -1; - return pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks(); + return pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks(); } int CBudgetProposal::GetBlockEndCycle() @@ -1666,13 +1658,13 @@ int CBudgetProposal::GetBlockEndCycle() int CBudgetProposal::GetTotalPaymentCount() { - return (GetBlockEndCycle() - GetBlockStartCycle()) / GetBudgetPaymentCycleBlocks(); + return (GetBlockEndCycle() - GetBlockStartCycle()) / Params().GetBudgetCycleBlocks(); } int CBudgetProposal::GetRemainingPaymentCount() { // If this budget starts in the future, this value will be wrong - int nPayments = (GetBlockEndCycle() - GetBlockCurrentCycle()) / GetBudgetPaymentCycleBlocks() - 1; + int nPayments = (GetBlockEndCycle() - GetBlockCurrentCycle()) / Params().GetBudgetCycleBlocks() - 1; // Take the lowest value return std::min(nPayments, GetTotalPaymentCount()); } @@ -1684,7 +1676,7 @@ CBudgetProposalBroadcast::CBudgetProposalBroadcast(std::string strProposalNameIn nBlockStart = nBlockStartIn; - int nCycleStart = nBlockStart - nBlockStart % GetBudgetPaymentCycleBlocks(); + int nCycleStart = nBlockStart - nBlockStart % Params().GetBudgetCycleBlocks(); // Right now single payment proposals have nBlockEnd have a cycle too early! // switch back if it break something else @@ -1692,7 +1684,7 @@ CBudgetProposalBroadcast::CBudgetProposalBroadcast(std::string strProposalNameIn // nBlockEnd = nCycleStart + GetBudgetPaymentCycleBlocks() * nPaymentCount + GetBudgetPaymentCycleBlocks() / 2; // Calculate the end of the cycle for this vote, vote will be deleted after next cycle - nBlockEnd = nCycleStart + (GetBudgetPaymentCycleBlocks() + 1) * nPaymentCount; + nBlockEnd = nCycleStart + (Params().GetBudgetCycleBlocks() + 1) * nPaymentCount; address = addressIn; nAmount = nAmountIn; @@ -1968,7 +1960,7 @@ std::string CFinalizedBudget::GetProposals() LOCK(cs); std::string ret = ""; - BOOST_FOREACH (CTxBudgetPayment& budgetPayment, vecBudgetPayments) { + for (CTxBudgetPayment& budgetPayment : vecBudgetPayments) { CBudgetProposal* pbudgetProposal = budget.FindProposal(budgetPayment.nProposalHash); std::string token = budgetPayment.nProposalHash.ToString(); @@ -2024,7 +2016,7 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) std::string strProposals = GetProposals(); // Must be the correct block for payment to happen (once a month) - if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) { + if (nBlockStart % Params().GetBudgetCycleBlocks() != 0) { strError = "Invalid BlockStart"; return false; } @@ -2075,11 +2067,11 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) // Get start of current budget-cycle int nCurrentHeight = chainActive.Height(); - int nBlockStart = nCurrentHeight - nCurrentHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + int nBlockStart = nCurrentHeight - nCurrentHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); // Remove budgets where the last payment (from max. 100) ends before 2 budget-cycles before the current one - int nMaxAge = nBlockStart - (2 * GetBudgetPaymentCycleBlocks()); - + int nMaxAge = nBlockStart - (2 * Params().GetBudgetCycleBlocks()); + if (GetBlockEnd() < nMaxAge) { strError = strprintf("Budget " + strBudgetName + " (" + strProposals + ") (ends at block %ld) too old and obsolete", GetBlockEnd()); return false; @@ -2091,7 +2083,7 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) bool CFinalizedBudget::IsPaidAlready(uint256 nProposalHash, int nBlockHeight) { // Remove budget-payments from former/future payment cycles - map::iterator it = mapPayment_History.begin(); + std::map::iterator it = mapPayment_History.begin(); int nPaidBlockHeight = 0; uint256 nOldProposalHash; @@ -2099,7 +2091,7 @@ bool CFinalizedBudget::IsPaidAlready(uint256 nProposalHash, int nBlockHeight) nPaidBlockHeight = (*it).second; if((nPaidBlockHeight < GetBlockStart()) || (nPaidBlockHeight > GetBlockEnd())) { nOldProposalHash = (*it).first; - LogPrint("mnbudget", "CFinalizedBudget::IsPaidAlready - Budget Proposal %s, Block %d from old cycle deleted\n", + LogPrint("mnbudget", "CFinalizedBudget::IsPaidAlready - Budget Proposal %s, Block %d from old cycle deleted\n", nOldProposalHash.ToString().c_str(), nPaidBlockHeight); mapPayment_History.erase(it++); } @@ -2112,7 +2104,7 @@ bool CFinalizedBudget::IsPaidAlready(uint256 nProposalHash, int nBlockHeight) if(mapPayment_History.count(nProposalHash) == 0) { // New proposal payment, insert into map for checks with later blocks from this cycle mapPayment_History.insert(std::pair(nProposalHash, nBlockHeight)); - LogPrint("mnbudget", "CFinalizedBudget::IsPaidAlready - Budget Proposal %s, Block %d added to payment history\n", + LogPrint("mnbudget", "CFinalizedBudget::IsPaidAlready - Budget Proposal %s, Block %d added to payment history\n", nProposalHash.ToString().c_str(), nBlockHeight); return false; } @@ -2135,8 +2127,8 @@ TrxValidationStatus CFinalizedBudget::IsTransactionValid(const CTransaction& txN } bool paid = false; - BOOST_FOREACH (CTxOut out, txNew.vout) { - LogPrint("mnbudget","CFinalizedBudget::IsTransactionValid - nCurrentBudgetPayment=%d, payee=%s == out.scriptPubKey=%s, amount=%ld == out.nValue=%ld\n", + for (CTxOut out : txNew.vout) { + LogPrint("mnbudget","CFinalizedBudget::IsTransactionValid - nCurrentBudgetPayment=%d, payee=%s == out.scriptPubKey=%s, amount=%ld == out.nValue=%ld\n", nCurrentBudgetPayment, vecBudgetPayments[nCurrentBudgetPayment].payee.ToString().c_str(), out.scriptPubKey.ToString().c_str(), vecBudgetPayments[nCurrentBudgetPayment].nAmount, out.nValue); @@ -2191,7 +2183,7 @@ void CFinalizedBudget::SubmitVote() if (budget.UpdateFinalizedBudget(vote, NULL, strError)) { LogPrint("mnbudget","CFinalizedBudget::SubmitVote - new finalized budget vote - %s\n", vote.GetHash().ToString()); - budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenFinalizedBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); } else { LogPrint("mnbudget","CFinalizedBudget::SubmitVote : Error submitting vote - %s\n", strError); @@ -2212,7 +2204,7 @@ CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(const CFinalizedBudget& oth { strBudgetName = other.strBudgetName; nBlockStart = other.nBlockStart; - BOOST_FOREACH (CTxBudgetPayment out, other.vecBudgetPayments) + for (CTxBudgetPayment out : other.vecBudgetPayments) vecBudgetPayments.push_back(out); mapVotes = other.mapVotes; nFeeTXHash = other.nFeeTXHash; @@ -2222,7 +2214,7 @@ CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(std::string strBudgetNameIn { strBudgetName = strBudgetNameIn; nBlockStart = nBlockStartIn; - BOOST_FOREACH (CTxBudgetPayment out, vecBudgetPaymentsIn) + for (CTxBudgetPayment out : vecBudgetPaymentsIn) vecBudgetPayments.push_back(out); mapVotes.clear(); nFeeTXHash = nFeeTXHashIn; diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 3bfd30987d0b..9f3a353d48ab 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -15,8 +15,6 @@ #include "sync.h" #include "util.h" -using namespace std; - extern CCriticalSection cs_budget; class CBudgetManager; @@ -42,14 +40,11 @@ static const int64_t BUDGET_VOTE_UPDATE_MIN = 60 * 60; extern std::vector vecImmatureBudgetProposals; extern std::vector vecImmatureFinalizedBudgets; -static map mapPayment_History; +static std::map mapPayment_History; extern CBudgetManager budget; void DumpBudgets(); -// Define amount of blocks in budget payment cycle -int GetBudgetPaymentCycleBlocks(); - //Check the collateral transaction for the budget proposal/finalized budget bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, std::string& strError, int64_t& nTime, int& nConf, bool fBudgetFinalization = false); @@ -184,15 +179,15 @@ class CBudgetManager private: //hold txes until they mature enough to use // XX42 map mapCollateral; - map mapCollateralTxids; + std::map mapCollateralTxids; public: // critical section to protect the inner data structures mutable CCriticalSection cs; // keep track of the scanning errors I've seen - map mapProposals; - map mapFinalizedBudgets; + std::map mapProposals; + std::map mapFinalizedBudgets; std::map mapSeenMasternodeBudgetProposals; std::map mapSeenMasternodeBudgetVotes; @@ -326,7 +321,7 @@ class CFinalizedBudget std::string strBudgetName; int nBlockStart; std::vector vecBudgetPayments; - map mapVotes; + std::map mapVotes; uint256 nFeeTXHash; int64_t nTime; @@ -377,7 +372,7 @@ class CFinalizedBudget void SubmitVote(); //checks the hashes to make sure we know about them - string GetStatus(); + std::string GetStatus(); uint256 GetHash() { @@ -483,7 +478,7 @@ class CBudgetProposal int64_t nTime; uint256 nFeeTXHash; - map mapVotes; + std::map mapVotes; //cache object CBudgetProposal(); diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 270a46367287..ab1110452494 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -5,6 +5,7 @@ #include "masternode-payments.h" #include "addrman.h" +#include "chainparams.h" #include "masternode-budget.h" #include "masternode-sync.h" #include "masternodeman.h" @@ -81,7 +82,7 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& // Don't try to resize to a negative number if file is small if (dataSize < 0) dataSize = 0; - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -195,7 +196,7 @@ bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMin if (!masternodeSync.IsSynced()) { //there is no budget data to use to check anything //super blocks will always be on these blocks, max 100 per budgeting - if (nHeight % GetBudgetPaymentCycleBlocks() < 100) { + if (nHeight % Params().GetBudgetCycleBlocks() < 100) { return true; } else { if (nMinted > nExpectedValue) { @@ -539,16 +540,16 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count); //require at least 6 signatures - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) + for (CMasternodePayee& payee : vecPayments) if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) nMaxSignatures = payee.nVotes; // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) { + for (CMasternodePayee& payee : vecPayments) { bool found = false; - BOOST_FOREACH (CTxOut out, txNew.vout) { + for (CTxOut out : txNew.vout) { if (payee.scriptPubKey == out.scriptPubKey) { if(out.nValue >= requiredMasternodePayment) found = true; @@ -581,7 +582,7 @@ std::string CMasternodeBlockPayees::GetRequiredPaymentsString() std::string ret = "Unknown"; - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) { + for (CMasternodePayee& payee : vecPayments) { CTxDestination address; ExtractDestination(payee.scriptPubKey, address); diff --git a/src/masternode-payments.h b/src/masternode-payments.h index c053f289b27a..cf1fb3023c00 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -10,7 +10,6 @@ #include "main.h" #include "masternode.h" -using namespace std; extern CCriticalSection cs_vecPayments; extern CCriticalSection cs_mapMasternodeBlocks; @@ -107,7 +106,7 @@ class CMasternodeBlockPayees { LOCK(cs_vecPayments); - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) { + for (CMasternodePayee& payee : vecPayments) { if (payee.scriptPubKey == payeeIn) { payee.nVotes += nIncrement; return; @@ -123,7 +122,7 @@ class CMasternodeBlockPayees LOCK(cs_vecPayments); int nVotes = -1; - BOOST_FOREACH (CMasternodePayee& p, vecPayments) { + for (CMasternodePayee& p : vecPayments) { if (p.nVotes > nVotes) { payee = p.scriptPubKey; nVotes = p.nVotes; @@ -137,7 +136,7 @@ class CMasternodeBlockPayees { LOCK(cs_vecPayments); - BOOST_FOREACH (CMasternodePayee& p, vecPayments) { + for (CMasternodePayee& p : vecPayments) { if (p.nVotes >= nVotesReq && p.scriptPubKey == payee) return true; } diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index 9002cf746469..ee46c99f4bce 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -92,7 +92,7 @@ void CMasternodeSync::AddedMasternodeList(uint256 hash) } } else { lastMasternodeList = GetTime(); - mapSeenSyncMNB.insert(make_pair(hash, 1)); + mapSeenSyncMNB.insert(std::make_pair(hash, 1)); } } @@ -105,7 +105,7 @@ void CMasternodeSync::AddedMasternodeWinner(uint256 hash) } } else { lastMasternodeWinner = GetTime(); - mapSeenSyncMNW.insert(make_pair(hash, 1)); + mapSeenSyncMNW.insert(std::make_pair(hash, 1)); } } @@ -119,7 +119,7 @@ void CMasternodeSync::AddedBudgetItem(uint256 hash) } } else { lastBudgetItem = GetTime(); - mapSeenSyncBudget.insert(make_pair(hash, 1)); + mapSeenSyncBudget.insert(std::make_pair(hash, 1)); } } @@ -222,7 +222,7 @@ void CMasternodeSync::ClearFulfilledRequest() TRY_LOCK(cs_vNodes, lockRecv); if (!lockRecv) return; - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { pnode->ClearFulfilledRequest(NetMsgType::GETSPORK); pnode->ClearFulfilledRequest("mnsync"); pnode->ClearFulfilledRequest("mnwsync"); @@ -264,7 +264,7 @@ void CMasternodeSync::Process() TRY_LOCK(cs_vNodes, lockRecv); if (!lockRecv) return; - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (Params().NetworkID() == CBaseChainParams::REGTEST) { if (RequestedMasternodeAttempt <= 2) { pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks diff --git a/src/masternode.cpp b/src/masternode.cpp index a229f196038b..a9262d42e586 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -12,7 +12,7 @@ #include "util.h" // keep track of the scanning errors I've seen -map mapSeenMasternodeScanningErrors; +std::map mapSeenMasternodeScanningErrors; // cache block hashes as we calculate them std::map mapCacheBlockHashes; @@ -148,7 +148,7 @@ bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb) int nDoS = 0; if (mnb.lastPing == CMasternodePing() || (mnb.lastPing != CMasternodePing() && mnb.lastPing.CheckAndUpdate(nDoS, false))) { lastPing = mnb.lastPing; - mnodeman.mapSeenMasternodePing.insert(make_pair(lastPing.GetHash(), lastPing)); + mnodeman.mapSeenMasternodePing.insert(std::make_pair(lastPing.GetHash(), lastPing)); } return true; } @@ -209,8 +209,8 @@ void CMasternode::Check(bool forceCheck) } if(lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS){ - activeState = MASTERNODE_PRE_ENABLED; - return; + activeState = MASTERNODE_PRE_ENABLED; + return; } if (!unitTest) { @@ -523,7 +523,7 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) std::string errorMessage = ""; if (!obfuScationSigner.VerifyMessage(pubKeyCollateralAddress, sig, GetNewStrMessage(), errorMessage) - && !obfuScationSigner.VerifyMessage(pubKeyCollateralAddress, sig, GetOldStrMessage(), errorMessage)) + && !obfuScationSigner.VerifyMessage(pubKeyCollateralAddress, sig, GetOldStrMessage(), errorMessage)) { // don't ban for old masternodes, their sigs could be broken because of the bug nDos = protocolVersion < MIN_PEER_MNANNOUNCE ? 0 : 100; @@ -542,11 +542,11 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) if (pmn == NULL) return true; // this broadcast is older or equal than the one that we already have - it's bad and should never happen - // unless someone is doing something fishy - // (mapSeenMasternodeBroadcast in CMasternodeMan::ProcessMessage should filter legit duplicates) - if(pmn->sigTime >= sigTime) { - return error("CMasternodeBroadcast::CheckAndUpdate - Bad sigTime %d for Masternode %20s %105s (existing broadcast is at %d)", - sigTime, addr.ToString(), vin.ToString(), pmn->sigTime); + // unless someone is doing something fishy + // (mapSeenMasternodeBroadcast in CMasternodeMan::ProcessMessage should filter legit duplicates) + if(pmn->sigTime >= sigTime) { + return error("CMasternodeBroadcast::CheckAndUpdate - Bad sigTime %d for Masternode %20s %105s (existing broadcast is at %d)", + sigTime, addr.ToString(), vin.ToString(), pmn->sigTime); } // masternode is not enabled yet/already, nothing to update @@ -666,16 +666,16 @@ bool CMasternodeBroadcast::Sign(CKey& keyCollateralAddress) std::string strMessage; if(chainActive.Height() <= Params().Zerocoin_LastOldParams()) - strMessage = GetOldStrMessage(); + strMessage = GetOldStrMessage(); else - strMessage = GetNewStrMessage(); + strMessage = GetNewStrMessage(); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, sig, keyCollateralAddress)) - return error("CMasternodeBroadcast::Sign() - Error: %s", errorMessage); + return error("CMasternodeBroadcast::Sign() - Error: %s", errorMessage); if (!obfuScationSigner.VerifyMessage(pubKeyCollateralAddress, sig, strMessage, errorMessage)) - return error("CMasternodeBroadcast::Sign() - Error: %s", errorMessage); + return error("CMasternodeBroadcast::Sign() - Error: %s", errorMessage); return true; } @@ -702,7 +702,7 @@ std::string CMasternodeBroadcast::GetOldStrMessage() return strMessage; } -std:: string CMasternodeBroadcast::GetNewStrMessage() +std::string CMasternodeBroadcast::GetNewStrMessage() { std::string strMessage; @@ -749,15 +749,16 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) return true; } -bool CMasternodePing::VerifySignature(CPubKey& pubKeyMasternode, int &nDos) { - std::string strMessage = vin.ToString() + blockHash.ToString() + std::to_string(sigTime); - std::string errorMessage = ""; +bool CMasternodePing::VerifySignature(CPubKey& pubKeyMasternode, int &nDos) +{ + std::string strMessage = vin.ToString() + blockHash.ToString() + std::to_string(sigTime); + std::string errorMessage = ""; - if(!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)){ - nDos = 33; - return error("CMasternodePing::VerifySignature - Got bad Masternode ping signature %s Error: %s", vin.ToString(), errorMessage); - } - return true; + if(!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)){ + nDos = 33; + return error("CMasternodePing::VerifySignature - Got bad Masternode ping signature %s Error: %s", vin.ToString(), errorMessage); + } + return true; } bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fCheckSigTimeOnly) @@ -771,9 +772,9 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fChec if(fCheckSigTimeOnly) { - CMasternode* pmn = mnodeman.Find(vin); - if(pmn) return VerifySignature(pmn->pubKeyMasternode, nDos); - return true; + CMasternode* pmn = mnodeman.Find(vin); + if(pmn) return VerifySignature(pmn->pubKeyMasternode, nDos); + return true; } LogPrint("masternode", "CMasternodePing::CheckAndUpdate - New Ping - %s - %s - %lli\n", GetHash().ToString(), blockHash.ToString(), sigTime); @@ -787,7 +788,7 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fChec // update only if there is no known ping for this masternode or // last ping was more then MASTERNODE_MIN_MNP_SECONDS-60 ago comparing to this one if (!pmn->IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS - 60, sigTime)) { - if (!VerifySignature(pmn->pubKeyMasternode, nDos)) + if (!VerifySignature(pmn->pubKeyMasternode, nDos)) return false; BlockMap::iterator mi = mapBlockIndex.find(blockHash); diff --git a/src/masternode.h b/src/masternode.h index 99b83087aea1..8831197f93fc 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -22,12 +22,10 @@ #define MASTERNODE_REMOVAL_SECONDS (130 * 60) #define MASTERNODE_CHECK_SECONDS 5 -using namespace std; - class CMasternode; class CMasternodeBroadcast; class CMasternodePing; -extern map mapCacheBlockHashes; +extern std::map mapCacheBlockHashes; bool GetBlockHash(uint256& hash, int nBlockHeight); diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index 08337c0b7c5a..1a78d32d0f64 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -3,13 +3,11 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -// clang-format off -#include "net.h" +#include "netbase.h" #include "masternodeconfig.h" #include "util.h" #include "ui_interface.h" #include "base58.h" -// clang-format on CMasternodeConfig masternodeConfig; @@ -60,15 +58,25 @@ bool CMasternodeConfig::read(std::string& strErr) } } + int port = 0; + std::string hostname = ""; + SplitHostPort(ip, port, hostname); + if(port == 0 || hostname == "") { + strErr = _("Failed to parse host:port string") + "\n"+ + strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\""; + streamConfig.close(); + return false; + } + if (Params().NetworkID() == CBaseChainParams::MAIN) { - if (CService(ip).GetPort() != 11771) { + if (port != 11771) { strErr = _("Invalid port detected in masternode.conf") + "\n" + strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\"" + "\n" + _("(must be 11771 for mainnet)"); streamConfig.close(); return false; } - } else if (CService(ip).GetPort() == 11771) { + } else if (port == 11771) { strErr = _("Invalid port detected in masternode.conf") + "\n" + strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\"" + "\n" + _("(11771 could be used only on mainnet)"); @@ -98,13 +106,13 @@ bool CMasternodeConfig::CMasternodeEntry::castOutputIndex(int &n) void CMasternodeConfig::clear() { - entries.clear(); + entries.clear(); } void CMasternodeConfig::deleteAlias(int count) { - count = count - 1; - entries.erase(entries.begin()+count); + count = count - 1; + entries.erase(entries.begin()+count); } void CMasternodeConfig::writeToMasternodeConf() @@ -114,24 +122,24 @@ void CMasternodeConfig::writeToMasternodeConf() FILE* configFile = fopen(pathMasternodeConfigFile.string().c_str(), "w"); - // Add file header back as each time this runs it restarts the file + // Add file header back as each time this runs it restarts the file std::string strHeader = "# Masternode config file\n" "# Format: alias IP:port masternodeprivkey collateral_output_txid collateral_output_index\n" "# Example: mn1 127.0.0.2:11771 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0\n"; fwrite(strHeader.c_str(), std::strlen(strHeader.c_str()), 1, configFile); - - std::string masternodeAliasBase = ""; - - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { - // Orders configs in proper strings - std::string masternodeAliasLine = mne.getAlias() + " " + mne.getIp() + " " + mne.getPrivKey() + " " + mne.getTxHash() + " " + mne.getOutputIndex() + "\n"; - masternodeAliasBase = masternodeAliasBase + masternodeAliasLine; - } - //Writes it to the string - fwrite(masternodeAliasBase.c_str(), std::strlen(masternodeAliasBase.c_str()), 1, configFile); - // When done adding all the masternodes to the config close the file + + std::string masternodeAliasBase = ""; + + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + // Orders configs in proper strings + std::string masternodeAliasLine = mne.getAlias() + " " + mne.getIp() + " " + mne.getPrivKey() + " " + mne.getTxHash() + " " + mne.getOutputIndex() + "\n"; + masternodeAliasBase = masternodeAliasBase + masternodeAliasLine; + } + //Writes it to the string + fwrite(masternodeAliasBase.c_str(), std::strlen(masternodeAliasBase.c_str()), 1, configFile); + // When done adding all the masternodes to the config close the file fclose(configFile); - clear(); - std::string strErr; - read(strErr); + clear(); + std::string strErr; + read(strErr); } \ No newline at end of file diff --git a/src/masternodeconfig.h b/src/masternodeconfig.h index 06fb2f23bbff..ac32cfd6e95c 100644 --- a/src/masternodeconfig.h +++ b/src/masternodeconfig.h @@ -97,9 +97,9 @@ class CMasternodeConfig void clear(); bool read(std::string& strErr); - void writeToMasternodeConf(); + void writeToMasternodeConf(); void add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex); - void deleteAlias(int count); + void deleteAlias(int count); std::vector& getEntries() { @@ -109,7 +109,7 @@ class CMasternodeConfig int getCount() { int c = -1; - BOOST_FOREACH (CMasternodeEntry e, entries) { + for (CMasternodeEntry e : entries) { if (e.getAlias() != "") c++; } return c; diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 6e40637fe069..25fbd81cc0f0 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -19,24 +19,24 @@ CMasternodeMan mnodeman; struct CompareLastPaid { - bool operator()(const pair& t1, - const pair& t2) const + bool operator()(const std::pair& t1, + const std::pair& t2) const { return t1.first < t2.first; } }; struct CompareScoreTxIn { - bool operator()(const pair& t1, - const pair& t2) const + bool operator()(const std::pair& t1, + const std::pair& t2) const { return t1.first < t2.first; } }; struct CompareScoreMN { - bool operator()(const pair& t1, - const pair& t2) const + bool operator()(const std::pair& t1, + const std::pair& t2) const { return t1.first < t2.first; } @@ -102,7 +102,7 @@ CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad, bo // Don't try to resize to a negative number if file is small if (dataSize < 0) dataSize = 0; - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -235,7 +235,7 @@ void CMasternodeMan::Check() { LOCK(cs); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); } } @@ -247,7 +247,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) LOCK(cs); //remove inactive and outdated - vector::iterator it = vMasternodes.begin(); + std::vector::iterator it = vMasternodes.begin(); while (it != vMasternodes.end()) { if ((*it).activeState == CMasternode::MASTERNODE_REMOVE || (*it).activeState == CMasternode::MASTERNODE_VIN_SPENT || @@ -258,7 +258,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) //erase all of the broadcasts we've seen from this vin // -- if we missed a few pings and the node was removed, this will allow is to get it back without them // sending a brand new mnb - map::iterator it3 = mapSeenMasternodeBroadcast.begin(); + std::map::iterator it3 = mapSeenMasternodeBroadcast.begin(); while (it3 != mapSeenMasternodeBroadcast.end()) { if ((*it3).second.vin == (*it).vin) { masternodeSync.mapSeenSyncMNB.erase((*it3).first); @@ -269,7 +269,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) } // allow us to ask for this masternode again if we see another ping - map::iterator it2 = mWeAskedForMasternodeListEntry.begin(); + std::map::iterator it2 = mWeAskedForMasternodeListEntry.begin(); while (it2 != mWeAskedForMasternodeListEntry.end()) { if ((*it2).first == (*it).vin.prevout) { mWeAskedForMasternodeListEntry.erase(it2++); @@ -285,7 +285,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) } // check who's asked for the Masternode list - map::iterator it1 = mAskedUsForMasternodeList.begin(); + std::map::iterator it1 = mAskedUsForMasternodeList.begin(); while (it1 != mAskedUsForMasternodeList.end()) { if ((*it1).second < GetTime()) { mAskedUsForMasternodeList.erase(it1++); @@ -305,7 +305,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) } // check which Masternodes we've asked for - map::iterator it2 = mWeAskedForMasternodeListEntry.begin(); + std::map::iterator it2 = mWeAskedForMasternodeListEntry.begin(); while (it2 != mWeAskedForMasternodeListEntry.end()) { if ((*it2).second < GetTime()) { mWeAskedForMasternodeListEntry.erase(it2++); @@ -315,7 +315,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) } // remove expired mapSeenMasternodeBroadcast - map::iterator it3 = mapSeenMasternodeBroadcast.begin(); + std::map::iterator it3 = mapSeenMasternodeBroadcast.begin(); while (it3 != mapSeenMasternodeBroadcast.end()) { if ((*it3).second.lastPing.sigTime < GetTime() - (MASTERNODE_REMOVAL_SECONDS * 2)) { mapSeenMasternodeBroadcast.erase(it3++); @@ -326,7 +326,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) } // remove expired mapSeenMasternodePing - map::iterator it4 = mapSeenMasternodePing.begin(); + std::map::iterator it4 = mapSeenMasternodePing.begin(); while (it4 != mapSeenMasternodePing.end()) { if ((*it4).second.sigTime < GetTime() - (MASTERNODE_REMOVAL_SECONDS * 2)) { mapSeenMasternodePing.erase(it4++); @@ -355,7 +355,7 @@ int CMasternodeMan::stable_size () int64_t nMasternode_Min_Age = MN_WINNER_MINIMUM_AGE; int64_t nMasternode_Age = 0; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < nMinProtocol) { continue; // Skip obsolete versions } @@ -380,7 +380,7 @@ int CMasternodeMan::CountEnabled(int protocolVersion) int i = 0; protocolVersion = protocolVersion == -1 ? masternodePayments.GetMinMasternodePaymentsProto() : protocolVersion; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (mn.protocolVersion < protocolVersion || !mn.IsEnabled()) continue; i++; @@ -393,7 +393,7 @@ void CMasternodeMan::CountNetworks(int protocolVersion, int& ipv4, int& ipv6, in { protocolVersion = protocolVersion == -1 ? masternodePayments.GetMinMasternodePaymentsProto() : protocolVersion; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); std::string strHost; int port; @@ -440,7 +440,7 @@ CMasternode* CMasternodeMan::Find(const CScript& payee) LOCK(cs); CScript payee2; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { payee2 = GetScriptForDestination(mn.pubKeyCollateralAddress.GetID()); if (payee2 == payee) return &mn; @@ -452,7 +452,7 @@ CMasternode* CMasternodeMan::Find(const CTxIn& vin) { LOCK(cs); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.vin.prevout == vin.prevout) return &mn; } @@ -464,7 +464,7 @@ CMasternode* CMasternodeMan::Find(const CPubKey& pubKeyMasternode) { LOCK(cs); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.pubKeyMasternode == pubKeyMasternode) return &mn; } @@ -479,14 +479,14 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight LOCK(cs); CMasternode* pBestMasternode = NULL; - std::vector > vecMasternodeLastPaid; + std::vector > vecMasternodeLastPaid; /* Make a vector with all of the last paid times */ int nMnCount = CountEnabled(); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (!mn.IsEnabled()) continue; @@ -502,7 +502,7 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight //make sure it has as many confirmations as there are masternodes if (mn.GetMasternodeInputAge() < nMnCount) continue; - vecMasternodeLastPaid.push_back(make_pair(mn.SecondsSincePayment(), mn.vin)); + vecMasternodeLastPaid.push_back(std::make_pair(mn.SecondsSincePayment(), mn.vin)); } nCount = (int)vecMasternodeLastPaid.size(); @@ -511,7 +511,7 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight if (fFilterSigTime && nCount < nMnCount / 3) return GetNextMasternodeInQueueForPayment(nBlockHeight, false, nCount); // Sort them high to low - sort(vecMasternodeLastPaid.rbegin(), vecMasternodeLastPaid.rend(), CompareLastPaid()); + std::sort(vecMasternodeLastPaid.rbegin(), vecMasternodeLastPaid.rend(), CompareLastPaid()); // Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one // -- This doesn't look at who is being paid in the +8-10 blocks, allowing for double payments very rarely @@ -520,7 +520,7 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight int nTenthNetwork = CountEnabled() / 10; int nCountTenth = 0; uint256 nHigh = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn) & s, vecMasternodeLastPaid) { + for (PAIRTYPE(int64_t, CTxIn) & s : vecMasternodeLastPaid) { CMasternode* pmn = Find(s.second); if (!pmn) break; @@ -549,10 +549,10 @@ CMasternode* CMasternodeMan::FindRandomNotInVec(std::vector& vecToExclude LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec - rand %d\n", rand); bool found; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < protocolVersion || !mn.IsEnabled()) continue; found = false; - BOOST_FOREACH (CTxIn& usedVin, vecToExclude) { + for (CTxIn& usedVin : vecToExclude) { if (mn.vin.prevout == usedVin.prevout) { found = true; break; @@ -573,7 +573,7 @@ CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight, CMasternode* winner = NULL; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (mn.protocolVersion < minProtocol || !mn.IsEnabled()) continue; @@ -593,7 +593,7 @@ CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight, int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, int minProtocol, bool fOnlyActive) { - std::vector > vecMasternodeScores; + std::vector > vecMasternodeScores; int64_t nMasternode_Min_Age = MN_WINNER_MINIMUM_AGE; int64_t nMasternode_Age = 0; @@ -602,7 +602,7 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in if (!GetBlockHash(hash, nBlockHeight)) return -1; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < minProtocol) { LogPrint("masternode","Skipping Masternode with obsolete version %d\n", mn.protocolVersion); continue; // Skip obsolete versions @@ -622,13 +622,13 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in uint256 n = mn.CalculateScore(1, nBlockHeight); int64_t n2 = n.GetCompact(false); - vecMasternodeScores.push_back(make_pair(n2, mn.vin)); + vecMasternodeScores.push_back(std::make_pair(n2, mn.vin)); } - sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn()); + std::sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn()); int rank = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn) & s, vecMasternodeScores) { + for (PAIRTYPE(int64_t, CTxIn) & s : vecMasternodeScores) { rank++; if (s.second.prevout == vin.prevout) { return rank; @@ -638,38 +638,38 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in return -1; } -std::vector > CMasternodeMan::GetMasternodeRanks(int64_t nBlockHeight, int minProtocol) +std::vector > CMasternodeMan::GetMasternodeRanks(int64_t nBlockHeight, int minProtocol) { - std::vector > vecMasternodeScores; - std::vector > vecMasternodeRanks; + std::vector > vecMasternodeScores; + std::vector > vecMasternodeRanks; //make sure we know about this block uint256 hash = 0; if (!GetBlockHash(hash, nBlockHeight)) return vecMasternodeRanks; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (mn.protocolVersion < minProtocol) continue; if (!mn.IsEnabled()) { - vecMasternodeScores.push_back(make_pair(9999, mn)); + vecMasternodeScores.push_back(std::make_pair(9999, mn)); continue; } uint256 n = mn.CalculateScore(1, nBlockHeight); int64_t n2 = n.GetCompact(false); - vecMasternodeScores.push_back(make_pair(n2, mn)); + vecMasternodeScores.push_back(std::make_pair(n2, mn)); } - sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN()); + std::sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN()); int rank = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CMasternode) & s, vecMasternodeScores) { + for (PAIRTYPE(int64_t, CMasternode) & s : vecMasternodeScores) { rank++; - vecMasternodeRanks.push_back(make_pair(rank, s.second)); + vecMasternodeRanks.push_back(std::make_pair(rank, s.second)); } return vecMasternodeRanks; @@ -677,10 +677,10 @@ std::vector > CMasternodeMan::GetMasternodeRanks(int64_t CMasternode* CMasternodeMan::GetMasternodeByRank(int nRank, int64_t nBlockHeight, int minProtocol, bool fOnlyActive) { - std::vector > vecMasternodeScores; + std::vector > vecMasternodeScores; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < minProtocol) continue; if (fOnlyActive) { mn.Check(); @@ -690,13 +690,13 @@ CMasternode* CMasternodeMan::GetMasternodeByRank(int nRank, int64_t nBlockHeight uint256 n = mn.CalculateScore(1, nBlockHeight); int64_t n2 = n.GetCompact(false); - vecMasternodeScores.push_back(make_pair(n2, mn.vin)); + vecMasternodeScores.push_back(std::make_pair(n2, mn.vin)); } - sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn()); + std::sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn()); int rank = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn) & s, vecMasternodeScores) { + for (PAIRTYPE(int64_t, CTxIn) & s : vecMasternodeScores) { rank++; if (rank == nRank) { return Find(s.second); @@ -712,7 +712,7 @@ void CMasternodeMan::ProcessMasternodeConnections() if (Params().NetworkID() == CBaseChainParams::REGTEST) return; LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (pnode->fObfuScationMaster) { if (obfuScationPool.pSubmittedToMasternode != NULL && pnode->addr == obfuScationPool.pSubmittedToMasternode->addr) continue; LogPrint("masternode","Closing Masternode connection peer=%i \n", pnode->GetId()); @@ -737,7 +737,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData masternodeSync.AddedMasternodeList(mnb.GetHash()); return; } - mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb)); + mapSeenMasternodeBroadcast.insert(std::make_pair(mnb.GetHash(), mnb)); int nDoS = 0; if (!mnb.CheckAndUpdate(nDoS)) { @@ -777,7 +777,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData LogPrint("masternode", "mnp - Masternode ping, vin: %s\n", mnp.vin.prevout.hash.ToString()); if (mapSeenMasternodePing.count(mnp.GetHash())) return; //seen - mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp)); + mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp)); int nDoS = 0; if (mnp.CheckAndUpdate(nDoS)) return; @@ -823,7 +823,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData int nInvCount = 0; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.addr.IsRFC1918()) continue; //local network if (mn.IsEnabled()) { @@ -834,7 +834,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pfrom->PushInventory(CInv(MSG_MASTERNODE_ANNOUNCE, hash)); nInvCount++; - if (!mapSeenMasternodeBroadcast.count(hash)) mapSeenMasternodeBroadcast.insert(make_pair(hash, mnb)); + if (!mapSeenMasternodeBroadcast.count(hash)) mapSeenMasternodeBroadcast.insert(std::make_pair(hash, mnb)); if (vin == mn.vin) { LogPrint("masternode", "dseg - Sent 1 Masternode entry to peer %i\n", pfrom->GetId()); @@ -863,7 +863,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CService addr; CPubKey pubkey; CPubKey pubkey2; - vector vchSig; + std::vector vchSig; int64_t sigTime; int count; int current; @@ -956,7 +956,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (pmn->IsEnabled()) { TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage(NetMsgType::DSEE, vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion, donationAddress, donationPercentage); } @@ -971,7 +971,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData LogPrint("masternode", "dsee - already seen this vin %s\n", vin.prevout.ToString()); return; } - mapSeenDsee.insert(make_pair(vin.prevout, pubkey)); + mapSeenDsee.insert(std::make_pair(vin.prevout, pubkey)); // make sure the vout that was signed is related to the transaction that spawned the Masternode // - this is expensive, so it's only done once per Masternode if (!obfuScationSigner.IsVinAssociatedWithPubkey(vin, pubkey)) { @@ -1045,7 +1045,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (mn.IsEnabled()) { TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage(NetMsgType::DSEE, vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion, donationAddress, donationPercentage); } @@ -1067,7 +1067,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) return; CTxIn vin; - vector vchSig; + std::vector vchSig; int64_t sigTime; bool stop; vRecv >> vin >> vchSig >> sigTime >> stop; @@ -1115,7 +1115,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; LogPrint("masternode", "dseep - relaying %s \n", vin.prevout.hash.ToString()); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage(NetMsgType::DSEEP, vin, vchSig, sigTime, stop); } @@ -1137,7 +1137,7 @@ void CMasternodeMan::Remove(CTxIn vin) { LOCK(cs); - vector::iterator it = vMasternodes.begin(); + std::vector::iterator it = vMasternodes.begin(); while (it != vMasternodes.end()) { if ((*it).vin == vin) { LogPrint("masternode", "CMasternodeMan: Removing Masternode %s - %i now\n", (*it).vin.prevout.hash.ToString(), size() - 1); @@ -1150,8 +1150,8 @@ void CMasternodeMan::Remove(CTxIn vin) void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb) { - mapSeenMasternodePing.insert(make_pair(mnb.lastPing.GetHash(), mnb.lastPing)); - mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb)); + mapSeenMasternodePing.insert(std::make_pair(mnb.lastPing.GetHash(), mnb.lastPing)); + mapSeenMasternodeBroadcast.insert(std::make_pair(mnb.GetHash(), mnb)); masternodeSync.AddedMasternodeList(mnb.GetHash()); LogPrint("masternode","CMasternodeMan::UpdateMasternodeList -- masternode=%s\n", mnb.vin.prevout.ToStringShort()); @@ -1161,7 +1161,7 @@ void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb) CMasternode mn(mnb); Add(mn); } else { - pmn->UpdateFromNewBroadcast(mnb); + pmn->UpdateFromNewBroadcast(mnb); } } diff --git a/src/masternodeman.h b/src/masternodeman.h index a197cfe1d8ca..be9b77c26b67 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -19,7 +19,6 @@ #define MINIMUM_PROTOCOL_VERSION_OLD_PING 70003 -using namespace std; class CMasternodeMan; @@ -70,9 +69,9 @@ class CMasternodeMan public: // Keep track of all broadcasts I've seen - map mapSeenMasternodeBroadcast; + std::map mapSeenMasternodeBroadcast; // Keep track of all pings I've seen - map mapSeenMasternodePing; + std::map mapSeenMasternodePing; // keep track of dsq count to prevent masternodes from gaming obfuscation queue int64_t nDsqCount; @@ -137,7 +136,7 @@ class CMasternodeMan return vMasternodes; } - std::vector > GetMasternodeRanks(int64_t nBlockHeight, int minProtocol = 0); + std::vector > GetMasternodeRanks(int64_t nBlockHeight, int minProtocol = 0); int GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, int minProtocol = 0, bool fOnlyActive = true); CMasternode* GetMasternodeByRank(int nRank, int64_t nBlockHeight, int minProtocol = 0, bool fOnlyActive = true); diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index cb843c59b78e..048b269138fd 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -10,14 +10,13 @@ #include "primitives/block.h" // for MAX_BLOCK_SIZE #include "utilstrencodings.h" -using namespace std; CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) { header = block.GetBlockHeader(); - vector vMatch; - vector vHashes; + std::vector vMatch; + std::vector vHashes; vMatch.reserve(block.vtx.size()); vHashes.reserve(block.vtx.size()); @@ -26,7 +25,7 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) const uint256& hash = block.vtx[i].GetHash(); if (filter.IsRelevantAndUpdate(block.vtx[i])) { vMatch.push_back(true); - vMatchedTxn.push_back(make_pair(i, hash)); + vMatchedTxn.push_back(std::make_pair(i, hash)); } else vMatch.push_back(false); vHashes.push_back(hash); diff --git a/src/merkleblock.h b/src/merkleblock.h index fa483b366f22..836bfeadc44d 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -119,7 +119,7 @@ class CPartialMerkleTree /** - * Used to relay blocks as header + vector + * Used to relay blocks as header + std::vector * to filtered nodes. */ class CMerkleBlock diff --git a/src/miner.cpp b/src/miner.cpp index ad97fac4527f..3623b3d9ecd0 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -32,7 +32,6 @@ #include #include -using namespace std; ////////////////////////////////////////////////////////////////////////////// // @@ -51,7 +50,7 @@ class COrphan { public: const CTransaction* ptx; - set setDependsOn; + std::set setDependsOn; CFeeRate feeRate; double dPriority; @@ -102,7 +101,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, CReserveKey reservekey(pwallet); // Create new block - unique_ptr pblocktemplate(new CBlockTemplate()); + std::unique_ptr pblocktemplate(new CBlockTemplate()); if (!pblocktemplate.get()) return NULL; CBlock* pblock = &pblocktemplate->block; // pointer for convenience @@ -211,16 +210,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, CCoinsViewCache view(pcoinsTip); // Priority order to process transactions - list vOrphan; // list memory doesn't move - map > mapDependers; + std::list vOrphan; // list memory doesn't move + std::map > mapDependers; bool fPrintPriority = GetBoolArg("-printpriority", false); int64_t nBlockSigOpsCost = 400; // This vector will be sorted into a priority queue: - vector vecPriority; + std::vector vecPriority; vecPriority.reserve(mempool.mapTx.size()); - for (map::iterator mi = mempool.mapTx.begin(); + for (std::map::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { const CTransaction& tx = mi->second.GetTx(); if (tx.IsCoinBase() || tx.IsCoinStake() || !IsFinalTx(tx, nHeight)){ @@ -338,8 +337,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, TxPriorityCompare comparer(fSortedByFee); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); - vector vBlockSerials; - vector vTxSerials; + std::vector vBlockSerials; + std::vector vTxSerials; while (!vecPriority.empty()) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); @@ -436,7 +435,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, // Add transactions that depend on this one to the priority queue if (mapDependers.count(hash)) { - BOOST_FOREACH (COrphan* porphan, mapDependers[hash]) { + for (COrphan* porphan : mapDependers[hash]) { if (!porphan->setDependsOn.empty()) { porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) { @@ -654,7 +653,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake) if (mapHashedBlocks.count(chainActive.Tip()->nHeight)) //search our map of hashed blocks, see if bestblock has been hashed yet { - if (GetTime() - mapHashedBlocks[chainActive.Tip()->nHeight] < max(pwallet->nHashInterval, (unsigned int)1)) // wait half of the nHashDrift with max wait of 3 minutes + if (GetTime() - mapHashedBlocks[chainActive.Tip()->nHeight] < std::max(pwallet->nHashInterval, (unsigned int)1)) // wait half of the nHashDrift with max wait of 3 minutes { MilliSleep(5000); continue; @@ -672,7 +671,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake) if (!pindexPrev) continue; - unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwallet, fProofOfStake)); + std::unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwallet, fProofOfStake)); if (!pblocktemplate.get()) continue; diff --git a/src/mintpool.cpp b/src/mintpool.cpp index bf12f42976bf..a1899167d8cc 100644 --- a/src/mintpool.cpp +++ b/src/mintpool.cpp @@ -5,7 +5,6 @@ #include "mintpool.h" #include "util.h" -using namespace std; CMintPool::CMintPool() { @@ -22,11 +21,11 @@ CMintPool::CMintPool(uint32_t nCount) void CMintPool::Add(const CBigNum& bnValue, const uint32_t& nCount) { uint256 hash = GetPubCoinHash(bnValue); - Add(make_pair(hash, nCount)); + Add(std::make_pair(hash, nCount)); LogPrintf("%s : add %s to mint pool, nCountLastGenerated=%d\n", __func__, bnValue.GetHex().substr(0, 6), nCountLastGenerated); } -void CMintPool::Add(const pair& pMint, bool fVerbose) +void CMintPool::Add(const std::pair& pMint, bool fVerbose) { insert(pMint); if (pMint.second > nCountLastGenerated) @@ -47,14 +46,14 @@ std::pair CMintPool::Get(const CBigNum& bnValue) return *it; } -bool SortSmallest(const pair& a, const pair& b) +bool SortSmallest(const std::pair& a, const std::pair& b) { return a.second < b.second; } -std::list > CMintPool::List() +std::list > CMintPool::List() { - list > listMints; + std::list > listMints; for (auto pMint : *(this)) { listMints.emplace_back(pMint); } @@ -79,7 +78,7 @@ bool CMintPool::Front(std::pair& pMint) return true; } -bool CMintPool::Next(pair& pMint) +bool CMintPool::Next(std::pair& pMint) { auto it = find(pMint.first); if (it == end() || ++it == end()) diff --git a/src/net.cpp b/src/net.cpp index b79accd76c8d..3ad5fd55fd57 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -58,8 +58,6 @@ #endif #endif -using namespace boost; -using namespace std; namespace { @@ -83,7 +81,7 @@ bool fDiscover = true; bool fListen = true; uint64_t nLocalServices = NODE_NETWORK | NODE_WITNESS; CCriticalSection cs_mapLocalHost; -map mapLocalHost; +std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; @@ -91,21 +89,22 @@ static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = 125; bool fAddressesInitialized = false; +std::string strSubVersion; -vector vNodes; +std::vector vNodes; CCriticalSection cs_vNodes; -map mapRelay; -deque > vRelayExpiration; +std::map mapRelay; +std::deque > vRelayExpiration; CCriticalSection cs_mapRelay; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -static deque vOneShots; +static std::deque vOneShots; CCriticalSection cs_vOneShots; -set setservAddNodeAddresses; +std::set setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses; -vector vAddedNodes; +std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; NodeId nLastNodeId = 0; @@ -118,7 +117,7 @@ boost::condition_variable messageHandlerCondition; static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } -void AddOneShot(string strDest) +void AddOneShot(std::string strDest) { LOCK(cs_vOneShots); vOneShots.push_back(strDest); @@ -139,7 +138,7 @@ bool GetLocal(CService& addr, const CNetAddr* paddrPeer) int nBestReachability = -1; { LOCK(cs_mapLocalHost); - for (map::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) { + for (std::map::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) { int nScore = (*it).second.nScore; int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) { @@ -168,7 +167,7 @@ CAddress GetLocalAddress(const CNetAddr* paddrPeer) return ret; } -bool RecvLine(SOCKET hSocket, string& strLine) +bool RecvLine(SOCKET hSocket, std::string& strLine) { strLine = ""; while (true) { @@ -464,7 +463,7 @@ void CNode::CloseSocketDisconnect() vRecvMsg.clear(); } -bool CNode::DisconnectOldProtocol(int nVersionRequired, string strLastCommand) +bool CNode::DisconnectOldProtocol(int nVersionRequired, std::string strLastCommand) { fDisconnect = false; if (nVersion < nVersionRequired) { @@ -490,7 +489,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), nBestHeight, true); + nLocalHostNonce, strSubVersion, nBestHeight, true); } @@ -570,7 +569,7 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti uiInterface.BannedListChanged(); { LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (subNet.Match((CNetAddr)pnode->addr)) pnode->fDisconnect = true; } @@ -659,7 +658,7 @@ CCriticalSection CNode::cs_vWhitelistedRange; bool CNode::IsWhitelistedRange(const CNetAddr& addr) { LOCK(cs_vWhitelistedRange); - BOOST_FOREACH (const CSubNet& subnet, vWhitelistedRange) { + for (const CSubNet& subnet : vWhitelistedRange) { if (subnet.Match(addr)) return true; } @@ -839,7 +838,7 @@ void SocketSendData(CNode* pnode) pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); } -static list vNodesDisconnected; +static std::list vNodesDisconnected; void ThreadSocketHandler() { @@ -851,8 +850,8 @@ void ThreadSocketHandler() { LOCK(cs_vNodes); // Disconnect unused nodes - vector vNodesCopy = vNodes; - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + std::vector vNodesCopy = vNodes; + for (CNode* pnode : vNodesCopy) { if (pnode->fDisconnect || (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty())) { // remove from vNodes @@ -873,8 +872,8 @@ void ThreadSocketHandler() } { // Delete disconnected nodes - list vNodesDisconnectedCopy = vNodesDisconnected; - BOOST_FOREACH (CNode* pnode, vNodesDisconnectedCopy) { + std::list vNodesDisconnectedCopy = vNodesDisconnected; + for (CNode* pnode : vNodesDisconnectedCopy) { // wait until threads are done using it if (pnode->GetRefCount() <= 0) { bool fDelete = false; @@ -922,19 +921,19 @@ void ThreadSocketHandler() SOCKET hSocketMax = 0; bool have_fds = false; - BOOST_FOREACH (const ListenSocket& hListenSocket, vhListenSocket) { + for (const ListenSocket& hListenSocket : vhListenSocket) { FD_SET(hListenSocket.socket, &fdsetRecv); - hSocketMax = max(hSocketMax, hListenSocket.socket); + hSocketMax = std::max(hSocketMax, hListenSocket.socket); have_fds = true; } { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (pnode->hSocket == INVALID_SOCKET) continue; FD_SET(pnode->hSocket, &fdsetError); - hSocketMax = max(hSocketMax, pnode->hSocket); + hSocketMax = std::max(hSocketMax, pnode->hSocket); have_fds = true; // Implement the following logic: @@ -987,7 +986,7 @@ void ThreadSocketHandler() // // Accept new connections // - BOOST_FOREACH (const ListenSocket& hListenSocket, vhListenSocket) { + for (const ListenSocket& hListenSocket : vhListenSocket) { if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); @@ -1002,7 +1001,7 @@ void ThreadSocketHandler() bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->fInbound) nInbound++; } @@ -1036,14 +1035,14 @@ void ThreadSocketHandler() // // Service each socket // - vector vNodesCopy; + std::vector vNodesCopy; { LOCK(cs_vNodes); vNodesCopy = vNodes; - BOOST_FOREACH (CNode* pnode, vNodesCopy) + for (CNode* pnode : vNodesCopy) pnode->AddRef(); } - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { boost::this_thread::interruption_point(); // @@ -1115,7 +1114,7 @@ void ThreadSocketHandler() } { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodesCopy) + for (CNode* pnode : vNodesCopy) pnode->Release(); } } @@ -1164,7 +1163,7 @@ void ThreadMapPort() } } - string strDesc = "Phore " + FormatFullVersion(); + std::string strDesc = "Phore " + FormatFullVersion(); try { while (true) { @@ -1245,19 +1244,19 @@ void ThreadDNSAddressSeed() } } - const vector& vSeeds = Params().DNSSeeds(); + const std::vector& vSeeds = Params().DNSSeeds(); int found = 0; LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); - BOOST_FOREACH (const CDNSSeedData& seed, vSeeds) { + for (const CDNSSeedData& seed : vSeeds) { if (HaveNameProxy()) { AddOneShot(seed.host); } else { - vector vIPs; - vector vAdd; + std::vector vIPs; + std::vector vAdd; if (LookupHost(seed.host.c_str(), vIPs, 256, true)) { - BOOST_FOREACH (CNetAddr& ip, vIPs) { + for (CNetAddr& ip : vIPs) { int nOneDay = 24 * 3600; CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); addr.nTime = GetTime() - 3 * nOneDay - GetRand(4 * nOneDay); // use a random age between 3 and 7 days old @@ -1292,7 +1291,7 @@ void DumpData() void static ProcessOneShot() { - string strDest; + std::string strDest; { LOCK(cs_vOneShots); if (vOneShots.empty()) @@ -1314,7 +1313,7 @@ void ThreadOpenConnections() if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - BOOST_FOREACH (string strAddr, mapMultiArgs["-connect"]) { + for (std::string strAddr : mapMultiArgs["-connect"]) { CAddress addr; OpenNetworkConnection(addr, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { @@ -1353,10 +1352,10 @@ void ThreadOpenConnections() // Only connect out to one peer per network group (/16 for IPv4). // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. int nOutbound = 0; - set > setConnected; + std::set > setConnected; { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (!pnode->fInbound) { setConnected.insert(pnode->addr.GetGroup()); nOutbound++; @@ -1368,7 +1367,7 @@ void ThreadOpenConnections() int nTries = 0; while (true) { - CAddress addr = addrman.Select(); + CAddrInfo addr = addrman.Select(); // if we selected an invalid address, restart if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) @@ -1418,13 +1417,13 @@ void ThreadOpenAddedConnections() if (HaveNameProxy()) { while (true) { - list lAddresses(0); + std::list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (std::string& strAddNode : vAddedNodes) lAddresses.push_back(strAddNode); } - BOOST_FOREACH (string& strAddNode, lAddresses) { + for (std::string& strAddNode : lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(addr, &grant, strAddNode.c_str()); @@ -1435,21 +1434,21 @@ void ThreadOpenAddedConnections() } for (unsigned int i = 0; true; i++) { - list lAddresses(0); + std::list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (std::string& strAddNode : vAddedNodes) lAddresses.push_back(strAddNode); } - list > lservAddressesToAdd(0); - BOOST_FOREACH (string& strAddNode, lAddresses) { - vector vservNode(0); + std::list > lservAddressesToAdd(0); + for (std::string& strAddNode : lAddresses) { + std::vector vservNode(0); if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); { LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH (CService& serv, vservNode) + for (CService& serv : vservNode) setservAddNodeAddresses.insert(serv); } } @@ -1458,16 +1457,16 @@ void ThreadOpenAddedConnections() // (keeping in mind that addnode entries can have many IPs if fNameLookup) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) - for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) - BOOST_FOREACH (CService& addrNode, *(it)) + for (CNode* pnode : vNodes) + for (std::list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) + for (CService& addrNode : *(it)) if (pnode->addr == addrNode) { it = lservAddressesToAdd.erase(it); it--; break; } } - BOOST_FOREACH (vector& vserv, lservAddressesToAdd) { + for (std::vector& vserv : lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); MilliSleep(500); @@ -1513,11 +1512,11 @@ void ThreadMessageHandler() SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); while (true) { - vector vNodesCopy; + std::vector vNodesCopy; { LOCK(cs_vNodes); vNodesCopy = vNodes; - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { pnode->AddRef(); } } @@ -1529,7 +1528,7 @@ void ThreadMessageHandler() bool fSleep = true; - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { if (pnode->fDisconnect) continue; @@ -1561,7 +1560,7 @@ void ThreadMessageHandler() { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodesCopy) + for (CNode* pnode : vNodesCopy) pnode->Release(); } @@ -1570,7 +1569,7 @@ void ThreadMessageHandler() } } -bool BindListenPort(const CService& addrBind, string& strError, bool fWhitelisted) +bool BindListenPort(const CService& addrBind, std::string& strError, bool fWhitelisted) { strError = ""; int nOne = 1; @@ -1667,9 +1666,9 @@ void static Discover(boost::thread_group& threadGroup) // Get local host IP char pszHostName[256] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { - vector vaddr; + std::vector vaddr; if (LookupHost(pszHostName, vaddr, 0, false)) { - BOOST_FOREACH (const CNetAddr& addr, vaddr) { + for (const CNetAddr& addr : vaddr) { if (AddLocal(addr, LOCAL_IF)) LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString()); } @@ -1722,13 +1721,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data CNode::SweepBanned(); //sweap out unused entries + // Initialize random numbers. Even when rand() is only usable for trivial use-cases most nodes should have a different + // seed after all the file-IO done at this point. Should be good enough even when nodes are started via scripts. + srand(time(NULL)); + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); + int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } @@ -1789,18 +1792,18 @@ class CNetCleanup ~CNetCleanup() { // Close sockets - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->hSocket != INVALID_SOCKET) CloseSocket(pnode->hSocket); - BOOST_FOREACH (ListenSocket& hListenSocket, vhListenSocket) + for (ListenSocket& hListenSocket : vhListenSocket) if (hListenSocket.socket != INVALID_SOCKET) if (!CloseSocket(hListenSocket.socket)) LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) delete pnode; - BOOST_FOREACH (CNode* pnode, vNodesDisconnected) + for (CNode* pnode : vNodesDisconnected) delete pnode; vNodes.clear(); vNodesDisconnected.clear(); @@ -1849,7 +1852,7 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss) vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); } LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (!pnode->fRelayTxes) continue; LOCK(pnode->cs_filter); @@ -1867,7 +1870,7 @@ void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll) //broadcast the new lock LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (!relayToAll && !pnode->fRelayTxes) continue; @@ -1878,7 +1881,7 @@ void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll) void RelayInv(CInv& inv) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes){ + for (CNode* pnode : vNodes){ if((pnode->nServices==NODE_BLOOM_WITHOUT_MN) && inv.IsMasterNodeType())continue; if (pnode->nVersion >= ActiveProtocol()) pnode->PushInventory(inv); @@ -1999,7 +2002,7 @@ bool CAddrDB::Read(CAddrMan& addr) // Don't try to resize to a negative number if file is small if (fileSize >= sizeof(uint256)) dataSize = fileSize - sizeof(uint256); - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -2255,7 +2258,7 @@ bool CBanDB::Read(banmap_t& banSet) // Don't try to resize to a negative number if file is small if (fileSize >= sizeof(uint256)) dataSize = fileSize - sizeof(uint256); - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; diff --git a/src/net.h b/src/net.h index 899ee573f607..1190ea9fa3fe 100644 --- a/src/net.h +++ b/src/net.h @@ -28,7 +28,7 @@ #endif #include -#include + #include #include @@ -47,6 +47,8 @@ static const unsigned int MAX_INV_SZ = 50000; static const unsigned int MAX_ADDR_TO_SEND = 1000; /** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */ static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000; +/** Maximum length of strSubVer in `version` message */ +static const unsigned int MAX_SUBVERSION_LENGTH = 256; /** -listen default */ static const bool DEFAULT_LISTEN = true; /** -upnp default */ @@ -139,6 +141,9 @@ extern CCriticalSection cs_vAddedNodes; extern NodeId nLastNodeId; extern CCriticalSection cs_nLastNodeId; +/** Subversion as sent to the P2P network in `version` messages */ +extern std::string strSubVersion; + struct LocalServiceInfo { int nScore; int nPort; @@ -404,7 +409,7 @@ class CNode unsigned int GetTotalRecvSize() { unsigned int total = 0; - BOOST_FOREACH (const CNetMessage& msg, vRecvMsg) + for (const CNetMessage& msg : vRecvMsg) total += msg.vRecv.size() + 24; return total; } @@ -416,7 +421,7 @@ class CNode void SetRecvVersion(int nVersionIn) { nRecvVersion = nVersionIn; - BOOST_FOREACH (CNetMessage& msg, vRecvMsg) + for (CNetMessage& msg : vRecvMsg) msg.SetVersion(nVersionIn); } @@ -670,7 +675,7 @@ class CNode bool HasFulfilledRequest(std::string strRequest) { - BOOST_FOREACH (std::string& type, vecRequestsFulfilled) { + for (std::string& type : vecRequestsFulfilled) { if (type == strRequest) return true; } return false; diff --git a/src/netbase.cpp b/src/netbase.cpp index 872a2a5f6c2a..c1ef243a666b 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -279,7 +279,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials vSocks5Init.push_back(0x01); // # METHODS vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED } - ssize_t ret = send(hSocket, (const char*)begin_ptr(vSocks5Init), vSocks5Init.size(), MSG_NOSIGNAL); + ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vSocks5Init.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); @@ -304,7 +304,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); vAuth.push_back(auth->password.size()); vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); - ret = send(hSocket, (const char*)begin_ptr(vAuth), vAuth.size(), MSG_NOSIGNAL); + ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vAuth.size()) { CloseSocket(hSocket); return error("Error sending authentication to proxy"); @@ -334,7 +334,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); vSocks5.push_back((port >> 8) & 0xFF); vSocks5.push_back((port >> 0) & 0xFF); - ret = send(hSocket, (const char*)begin_ptr(vSocks5), vSocks5.size(), MSG_NOSIGNAL); + ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vSocks5.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); diff --git a/src/obfuscation-relay.cpp b/src/obfuscation-relay.cpp index 2dff68b7bbe6..9f99691c9d78 100644 --- a/src/obfuscation-relay.cpp +++ b/src/obfuscation-relay.cpp @@ -14,7 +14,7 @@ CObfuScationRelay::CObfuScationRelay() out = CTxOut(); } -CObfuScationRelay::CObfuScationRelay(CTxIn& vinMasternodeIn, vector& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2) +CObfuScationRelay::CObfuScationRelay(CTxIn& vinMasternodeIn, std::vector& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2) { vinMasternode = vinMasternodeIn; vchSig = vchSigIn; diff --git a/src/obfuscation-relay.h b/src/obfuscation-relay.h index 07438a7d8015..c00106f9c391 100644 --- a/src/obfuscation-relay.h +++ b/src/obfuscation-relay.h @@ -15,15 +15,15 @@ class CObfuScationRelay { public: CTxIn vinMasternode; - vector vchSig; - vector vchSig2; + std::vector vchSig; + std::vector vchSig2; int nBlockHeight; int nRelayType; CTxIn in; CTxOut out; CObfuScationRelay(); - CObfuScationRelay(CTxIn& vinMasternodeIn, vector& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2); + CObfuScationRelay(CTxIn& vinMasternodeIn, std::vector& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2); ADD_SERIALIZE_METHODS; diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index d6ca1088d5f8..d2d5b0f886f9 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -15,15 +15,13 @@ #include "util.h" #include #include +#include #include #include #include #include -using namespace std; -using namespace boost; - // The main object for accessing Obfuscation CObfuscationPool obfuScationPool; // A helper object for signing messages from Masternodes @@ -33,356 +31,16 @@ std::vector vecObfuscationQueue; // Keep track of the used Masternodes std::vector vecMasternodesUsed; // Keep track of the scanning errors I've seen -map mapObfuscationBroadcastTxes; +std::map mapObfuscationBroadcastTxes; // Keep track of the active Masternode CActiveMasternode activeMasternode; -/* *** BEGIN OBFUSCATION MAGIC - PHR ********** - Copyright (c) 2014-2015, Dash Developers - eduffield - evan@dashpay.io - udjinm6 - udjinm6@dashpay.io -*/ - -void CObfuscationPool::ProcessMessageObfuscation(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) -{ - if (fLiteMode) return; //disable all Obfuscation/Masternode related functionality - if (!masternodeSync.IsBlockchainSynced()) return; - - if (strCommand == NetMsgType::DSA) { //Obfuscation Accept Into Pool - - int errorID; - - if (pfrom->nVersion < ActiveProtocol()) { - errorID = ERR_VERSION; - LogPrintf("dsa -- incompatible version! \n"); - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - if (!fMasterNode) { - errorID = ERR_NOT_A_MN; - LogPrintf("dsa -- not a Masternode! \n"); - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - int nDenom; - CTransaction txCollateral; - vRecv >> nDenom >> txCollateral; - - CMasternode* pmn = mnodeman.Find(activeMasternode.vin); - if (pmn == NULL) { - errorID = ERR_MN_LIST; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - if (sessionUsers == 0) { - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - LogPrintf("dsa -- last dsq too recent, must wait. %s \n", pfrom->addr.ToString()); - errorID = ERR_RECENT; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - - if (!IsCompatibleWithSession(nDenom, txCollateral, errorID)) { - LogPrintf("dsa -- not compatible with existing transactions! \n"); - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } else { - LogPrintf("dsa -- is compatible, please submit! \n"); - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID); - return; - } - - } else if (strCommand == NetMsgType::DSQ) { //Obfuscation Queue - TRY_LOCK(cs_obfuscation, lockRecv); - if (!lockRecv) return; - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - CObfuscationQueue dsq; - vRecv >> dsq; - - CService addr; - if (!dsq.GetAddress(addr)) return; - if (!dsq.CheckSignature()) return; - - if (dsq.IsExpired()) return; - - CMasternode* pmn = mnodeman.Find(dsq.vin); - if (pmn == NULL) return; - - // if the queue is ready, submit if we can - if (dsq.ready) { - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)addr) { - LogPrintf("dsq - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), addr.ToString()); - return; - } - - if (state == POOL_STATUS_QUEUE) { - LogPrint("obfuscation", "Obfuscation queue is ready - %s\n", addr.ToString()); - PrepareObfuscationDenominate(); - } - } else { - BOOST_FOREACH (CObfuscationQueue q, vecObfuscationQueue) { - if (q.vin == dsq.vin) return; - } - - LogPrint("obfuscation", "dsq last %d last2 %d count %d\n", pmn->nLastDsq, pmn->nLastDsq + mnodeman.size() / 5, mnodeman.nDsqCount); - //don't allow a few nodes to dominate the queuing process - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - LogPrint("obfuscation", "dsq -- Masternode sending too many dsq messages. %s \n", pmn->addr.ToString()); - return; - } - mnodeman.nDsqCount++; - pmn->nLastDsq = mnodeman.nDsqCount; - pmn->allowFreeTx = true; - - LogPrint("obfuscation", "dsq - new Obfuscation queue object - %s\n", addr.ToString()); - vecObfuscationQueue.push_back(dsq); - dsq.Relay(); - dsq.time = GetTime(); - } - - } else if (strCommand == NetMsgType::DSI) { //ObfuScation vIn - int errorID; - - if (pfrom->nVersion < ActiveProtocol()) { - LogPrintf("dsi -- incompatible version! \n"); - errorID = ERR_VERSION; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - if (!fMasterNode) { - LogPrintf("dsi -- not a Masternode! \n"); - errorID = ERR_NOT_A_MN; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - std::vector in; - CAmount nAmount; - CTransaction txCollateral; - std::vector out; - vRecv >> in >> nAmount >> txCollateral >> out; - - //do we have enough users in the current session? - if (!IsSessionReady()) { - LogPrintf("dsi -- session not complete! \n"); - errorID = ERR_SESSION; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - //do we have the same denominations as the current session? - if (!IsCompatibleWithEntries(out)) { - LogPrintf("dsi -- not compatible with existing transactions! \n"); - errorID = ERR_EXISTING_TX; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - //check it like a transaction - { - CAmount nValueIn = 0; - CAmount nValueOut = 0; - bool missingTx = false; - - CValidationState state; - CMutableTransaction tx; - - BOOST_FOREACH (const CTxOut o, out) { - nValueOut += o.nValue; - tx.vout.push_back(o); - - if (o.scriptPubKey.size() != 25) { - LogPrintf("dsi - non-standard pubkey detected! %s\n", o.scriptPubKey.ToString()); - errorID = ERR_NON_STANDARD_PUBKEY; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - if (!o.scriptPubKey.IsNormalPaymentScript()) { - LogPrintf("dsi - invalid script! %s\n", o.scriptPubKey.ToString()); - errorID = ERR_INVALID_SCRIPT; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - - BOOST_FOREACH (const CTxIn i, in) { - tx.vin.push_back(i); - - LogPrint("obfuscation", "dsi -- tx in %s\n", i.ToString()); - - CTransaction tx2; - uint256 hash; - if (GetTransaction(i.prevout.hash, tx2, hash, true)) { - if (tx2.vout.size() > i.prevout.n) { - nValueIn += tx2.vout[i.prevout.n].nValue; - } - } else { - missingTx = true; - } - } - - if (nValueIn > OBFUSCATION_POOL_MAX) { - LogPrintf("dsi -- more than Obfuscation pool max! %s\n", tx.ToString()); - errorID = ERR_MAXIMUM; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - if (!missingTx) { - if (nValueIn - nValueOut > nValueIn * .01) { - LogPrintf("dsi -- fees are too high! %s\n", tx.ToString()); - errorID = ERR_FEES; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } else { - LogPrintf("dsi -- missing input tx! %s\n", tx.ToString()); - errorID = ERR_MISSING_TX; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - { - LOCK(cs_main); - if (!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL, false, true)) { - LogPrintf("dsi -- transaction not valid! \n"); - errorID = ERR_INVALID_TX; - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - } - - if (AddEntry(in, nAmount, txCollateral, out, errorID)) { - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID); - Check(); - - RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); - } else { - pfrom->PushMessage(NetMsgType::DSSU, sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - } - - } else if (strCommand == NetMsgType::DSSU) { //Obfuscation status update - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - //LogPrintf("dssu - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString()); - return; - } - - int sessionIDMessage; - int state; - int entriesCount; - int accepted; - int errorID; - vRecv >> sessionIDMessage >> state >> entriesCount >> accepted >> errorID; - - LogPrint("obfuscation", "dssu - state: %i entriesCount: %i accepted: %i error: %s \n", state, entriesCount, accepted, GetMessageByID(errorID)); - - if ((accepted != 1 && accepted != 0) && sessionID != sessionIDMessage) { - LogPrintf("dssu - message doesn't match current Obfuscation session %d %d\n", sessionID, sessionIDMessage); - return; - } - - StatusUpdate(state, entriesCount, accepted, errorID, sessionIDMessage); - - } else if (strCommand == NetMsgType::DSS) { //Obfuscation Sign Final Tx - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - vector sigs; - vRecv >> sigs; - - bool success = false; - int count = 0; - - BOOST_FOREACH (const CTxIn item, sigs) { - if (AddScriptSig(item)) success = true; - LogPrint("obfuscation", " -- sigs count %d %d\n", (int)sigs.size(), count); - count++; - } - - if (success) { - obfuScationPool.Check(); - RelayStatus(obfuScationPool.sessionID, obfuScationPool.GetState(), obfuScationPool.GetEntriesCount(), MASTERNODE_RESET); - } - } else if (strCommand == NetMsgType::DSF) { //Obfuscation Final tx - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - //LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString()); - return; - } - - int sessionIDMessage; - CTransaction txNew; - vRecv >> sessionIDMessage >> txNew; - - if (sessionID != sessionIDMessage) { - LogPrint("obfuscation", "dsf - message doesn't match current Obfuscation session %d %d\n", sessionID, sessionIDMessage); - return; - } - - //check to see if input is spent already? (and probably not confirmed) - SignFinalTransaction(txNew, pfrom); - - } else if (strCommand == NetMsgType::DSC) { //Obfuscation Complete - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - //LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString()); - return; - } - - int sessionIDMessage; - bool error; - int errorID; - vRecv >> sessionIDMessage >> error >> errorID; - - if (sessionID != sessionIDMessage) { - LogPrint("obfuscation", "dsc - message doesn't match current Obfuscation session %d %d\n", obfuScationPool.sessionID, sessionIDMessage); - return; - } - - obfuScationPool.CompletedTransaction(error, errorID); - } -} - int randomizeList(int i) { return std::rand() % i; } void CObfuscationPool::Reset() { cachedLastSuccess = 0; lastNewBlock = 0; - txCollateral = CMutableTransaction(); vecMasternodesUsed.clear(); UnlockCoins(); SetNull(); @@ -398,7 +56,6 @@ void CObfuscationPool::SetNull() entriesCount = 0; lastEntryAccepted = 0; countEntriesAccepted = 0; - sessionFoundMasternode = false; // Both sides state = POOL_STATUS_IDLE; @@ -437,7 +94,7 @@ void CObfuscationPool::UnlockCoins() MilliSleep(50); continue; } - BOOST_FOREACH (CTxIn v, lockedCoins) + for (CTxIn v : lockedCoins) pwalletMain->UnlockCoin(v.prevout); break; } @@ -445,72 +102,6 @@ void CObfuscationPool::UnlockCoins() lockedCoins.clear(); } -std::string CObfuscationPool::GetStatus() -{ - static int showingObfuScationMessage = 0; - showingObfuScationMessage += 10; - std::string suffix = ""; - - if (chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing || !masternodeSync.IsBlockchainSynced()) { - return strAutoDenomResult; - } - switch (state) { - case POOL_STATUS_IDLE: - return _("Obfuscation is idle."); - case POOL_STATUS_ACCEPTING_ENTRIES: - if (entriesCount == 0) { - showingObfuScationMessage = 0; - return strAutoDenomResult; - } else if (lastEntryAccepted == 1) { - if (showingObfuScationMessage % 10 > 8) { - lastEntryAccepted = 0; - showingObfuScationMessage = 0; - } - return _("Obfuscation request complete:") + " " + _("Your transaction was accepted into the pool!"); - } else { - std::string suffix = ""; - if (showingObfuScationMessage % 70 <= 40) - return strprintf(_("Submitted following entries to masternode: %u / %d"), entriesCount, GetMaxPoolTransactions()); - else if (showingObfuScationMessage % 70 <= 50) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 60) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Submitted to masternode, waiting for more entries ( %u / %d ) %s"), entriesCount, GetMaxPoolTransactions(), suffix); - } - case POOL_STATUS_SIGNING: - if (showingObfuScationMessage % 70 <= 40) - return _("Found enough users, signing ..."); - else if (showingObfuScationMessage % 70 <= 50) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 60) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Found enough users, signing ( waiting %s )"), suffix); - case POOL_STATUS_TRANSMISSION: - return _("Transmitting final transaction."); - case POOL_STATUS_FINALIZE_TRANSACTION: - return _("Finalizing transaction."); - case POOL_STATUS_ERROR: - return _("Obfuscation request incomplete:") + " " + lastMessage + " " + _("Will retry..."); - case POOL_STATUS_SUCCESS: - return _("Obfuscation request complete:") + " " + lastMessage; - case POOL_STATUS_QUEUE: - if (showingObfuScationMessage % 70 <= 30) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 50) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Submitted to masternode, waiting in queue %s"), suffix); - ; - default: - return strprintf(_("Unknown state: id = %u"), state); - } -} - // // Check the Obfuscation progress and send client updates if a Masternode // @@ -539,10 +130,10 @@ void CObfuscationPool::Check() // make our new transaction for (unsigned int i = 0; i < entries.size(); i++) { - BOOST_FOREACH (const CTxOut& v, entries[i].vout) + for (const CTxOut& v : entries[i].vout) txNew.vout.push_back(v); - BOOST_FOREACH (const CTxDSIn& s, entries[i].sev) + for (const CTxDSIn& s : entries[i].sev) txNew.vin.push_back(s); } @@ -630,7 +221,7 @@ void CObfuscationPool::CheckFinalTransaction() dstx.vchSig = vchSig; dstx.sigTime = sigTime; - mapObfuscationBroadcastTxes.insert(make_pair(txNew.GetHash(), dstx)); + mapObfuscationBroadcastTxes.insert(std::make_pair(txNew.GetHash(), dstx)); } CInv inv(MSG_DSTX, txNew.GetHash()); @@ -671,9 +262,9 @@ void CObfuscationPool::ChargeFees() if (r > 33) return; if (state == POOL_STATUS_ACCEPTING_ENTRIES) { - BOOST_FOREACH (const CTransaction& txCollateral, vecSessionCollateral) { + for (const CTransaction& txCollateral : vecSessionCollateral) { bool found = false; - BOOST_FOREACH (const CObfuScationEntry& v, entries) { + for (const CObfuScationEntry& v : entries) { if (v.collateral == txCollateral) { found = true; } @@ -689,8 +280,8 @@ void CObfuscationPool::ChargeFees() if (state == POOL_STATUS_SIGNING) { // who didn't sign? - BOOST_FOREACH (const CObfuScationEntry v, entries) { - BOOST_FOREACH (const CTxDSIn s, v.sev) { + for (const CObfuScationEntry v : entries) { + for (const CTxDSIn s : v.sev) { if (!s.fHasSig) { LogPrintf("CObfuscationPool::ChargeFees -- found uncooperative node (didn't sign). Found offence\n"); offences++; @@ -715,9 +306,9 @@ void CObfuscationPool::ChargeFees() r = rand() % 100; if (state == POOL_STATUS_ACCEPTING_ENTRIES) { - BOOST_FOREACH (const CTransaction& txCollateral, vecSessionCollateral) { + for (const CTransaction& txCollateral : vecSessionCollateral) { bool found = false; - BOOST_FOREACH (const CObfuScationEntry& v, entries) { + for (const CObfuScationEntry& v : entries) { if (v.collateral == txCollateral) { found = true; } @@ -742,8 +333,8 @@ void CObfuscationPool::ChargeFees() if (state == POOL_STATUS_SIGNING) { // who didn't sign? - BOOST_FOREACH (const CObfuScationEntry v, entries) { - BOOST_FOREACH (const CTxDSIn s, v.sev) { + for (const CObfuScationEntry v : entries) { + for (const CTxDSIn s : v.sev) { if (!s.fHasSig && r > target) { LogPrintf("CObfuscationPool::ChargeFees -- found uncooperative node (didn't sign). charging fees.\n"); @@ -769,7 +360,7 @@ void CObfuscationPool::ChargeRandomFees() if (fMasterNode) { int i = 0; - BOOST_FOREACH (const CTransaction& txCollateral, vecSessionCollateral) { + for (const CTransaction& txCollateral : vecSessionCollateral) { int r = rand() % 100; /* @@ -824,7 +415,7 @@ void CObfuscationPool::CheckTimeout() // check Obfuscation queue objects for timeouts int c = 0; - vector::iterator it = vecObfuscationQueue.begin(); + std::vector::iterator it = vecObfuscationQueue.begin(); while (it != vecObfuscationQueue.end()) { if ((*it).IsExpired()) { LogPrint("obfuscation", "CObfuscationPool::CheckTimeout() : Removing expired queue entry - %d\n", c); @@ -841,7 +432,7 @@ void CObfuscationPool::CheckTimeout() c = 0; // check for a timeout and reset if needed - vector::iterator it2 = entries.begin(); + std::vector::iterator it2 = entries.begin(); while (it2 != entries.end()) { if ((*it2).IsExpired()) { LogPrint("obfuscation", "CObfuscationPool::CheckTimeout() : Removing expired entry - %d\n", c); @@ -907,1379 +498,164 @@ void CObfuscationPool::CheckForCompleteQueue() } } -// check to see if the signature is valid -bool CObfuscationPool::SignatureValid(const CScript& newSig, const CTxIn& newVin) +// Check to make sure everything is signed +bool CObfuscationPool::SignaturesComplete() { - CMutableTransaction txNew; - txNew.vin.clear(); - txNew.vout.clear(); + for (const CObfuScationEntry& v : entries) { + for (const CTxDSIn& s : v.sev) { + if (!s.fHasSig) return false; + } + } + return true; +} - int found = -1; - CScript sigPubKey = CScript(); - unsigned int i = 0; +void CObfuscationPool::NewBlock() +{ + LogPrint("obfuscation", "CObfuscationPool::NewBlock \n"); - CAmount zeroAmount = 0; + //we we're processing lots of blocks, we'll just leave + if (GetTime() - lastNewBlock < 10) return; + lastNewBlock = GetTime(); - BOOST_FOREACH (CObfuScationEntry& e, entries) { - BOOST_FOREACH (const CTxOut& out, e.vout) - txNew.vout.push_back(out); + obfuScationPool.CheckTimeout(); +} - BOOST_FOREACH (const CTxDSIn& s, e.sev) { - txNew.vin.push_back(s); +bool CObfuScationSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey) +{ + CScript payee2; + payee2 = GetScriptForDestination(pubkey.GetID()); - if (s == newVin) { - found = i; - sigPubKey = s.prevPubKey; + CTransaction txVin; + uint256 hash; + if (GetTransaction(vin.prevout.hash, txVin, hash, true)) { + for (CTxOut out : txVin.vout) { + if (out.nValue == 10000 * COIN) { + if (out.scriptPubKey == payee2) return true; } - i++; } } - if (found >= 0) { //might have to do this one input at a time? - int n = found; - txNew.vin[n].scriptSig = newSig; - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Sign with sig %s\n", newSig.ToString().substr(0, 24)); - if (!VerifyScript(txNew.vin[n].scriptSig, sigPubKey, NULL, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, n, zeroAmount))) { - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Signing - Error signing input %u\n", n); - return false; - } + return false; +} + +bool CObfuScationSigner::SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey) +{ + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(strSecret); + + if (!fGood) { + errorMessage = _("Invalid private key."); + return false; } - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Signing - Successfully validated input\n"); + key = vchSecret.GetKey(); + pubkey = key.GetPubKey(); + return true; } -// check to make sure the collateral provided by the client is valid -bool CObfuscationPool::IsCollateralValid(const CTransaction& txCollateral) +bool CObfuScationSigner::GetKeysFromSecret(std::string strSecret, CKey& keyRet, CPubKey& pubkeyRet) { - if (txCollateral.vout.size() < 1) return false; - if (txCollateral.nLockTime != 0) return false; + CBitcoinSecret vchSecret; - int64_t nValueIn = 0; - int64_t nValueOut = 0; - bool missingTx = false; + if (!vchSecret.SetString(strSecret)) return false; - BOOST_FOREACH (const CTxOut o, txCollateral.vout) { - nValueOut += o.nValue; + keyRet = vchSecret.GetKey(); + pubkeyRet = keyRet.GetPubKey(); - if (!o.scriptPubKey.IsNormalPaymentScript()) { - LogPrintf("CObfuscationPool::IsCollateralValid - Invalid Script %s\n", txCollateral.ToString()); - return false; - } - } + return true; +} - BOOST_FOREACH (const CTxIn i, txCollateral.vin) { - CTransaction tx2; - uint256 hash; - if (GetTransaction(i.prevout.hash, tx2, hash, true)) { - if (tx2.vout.size() > i.prevout.n) { - nValueIn += tx2.vout[i.prevout.n].nValue; - } - } else { - missingTx = true; - } - } +bool CObfuScationSigner::SignMessage(std::string strMessage, std::string& errorMessage, std::vector& vchSig, CKey key) +{ + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; - if (missingTx) { - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString()); + if (!key.SignCompact(ss.GetHash(), vchSig)) { + errorMessage = _("Signing failed."); return false; } - //collateral transactions are required to pay out OBFUSCATION_COLLATERAL as a fee to the miners - if (nValueIn - nValueOut < OBFUSCATION_COLLATERAL) { - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid - did not include enough fees in transaction %d\n%s\n", nValueOut - nValueIn, txCollateral.ToString()); - return false; - } + return true; +} - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid %s\n", txCollateral.ToString()); +bool CObfuScationSigner::VerifyMessage(CPubKey pubkey, std::vector& vchSig, std::string strMessage, std::string& errorMessage) +{ + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; - { - LOCK(cs_main); - CValidationState state; - if (!AcceptableInputs(mempool, state, txCollateral, true, NULL)) { - if (fDebug) LogPrintf("CObfuscationPool::IsCollateralValid - didn't pass IsAcceptable\n"); - return false; - } + CPubKey pubkey2; + if (!pubkey2.RecoverCompact(ss.GetHash(), vchSig)) { + errorMessage = _("Error recovering public key."); + return false; } - return true; -} + if (fDebug && pubkey2.GetID() != pubkey.GetID()) + LogPrintf("CObfuScationSigner::VerifyMessage -- keys don't match: %s %s\n", pubkey2.GetID().ToString(), pubkey.GetID().ToString()); + return (pubkey2.GetID() == pubkey.GetID()); +} -// -// Add a clients transaction to the pool -// -bool CObfuscationPool::AddEntry(const std::vector& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, int& errorID) +bool CObfuscationQueue::Sign() { if (!fMasterNode) return false; - BOOST_FOREACH (CTxIn in, newInput) { - if (in.prevout.IsNull() || nAmount < 0) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - input not valid!\n"); - errorID = ERR_INVALID_INPUT; - sessionUsers--; - return false; - } - } + std::string strMessage = vin.ToString() + std::to_string(nDenom) + std::to_string(time) + std::to_string(ready); + + CKey key2; + CPubKey pubkey2; + std::string errorMessage = ""; - if (!IsCollateralValid(txCollateral)) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - collateral not valid!\n"); - errorID = ERR_INVALID_COLLATERAL; - sessionUsers--; + if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2)) { + LogPrintf("CObfuscationQueue():Relay - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage); return false; } - if ((int)entries.size() >= GetMaxPoolTransactions()) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - entries is full!\n"); - errorID = ERR_ENTRIES_FULL; - sessionUsers--; + if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, key2)) { + LogPrintf("CObfuscationQueue():Relay - Sign message failed"); return false; } - BOOST_FOREACH (CTxIn in, newInput) { - LogPrint("obfuscation", "looking for vin -- %s\n", in.ToString()); - BOOST_FOREACH (const CObfuScationEntry& v, entries) { - BOOST_FOREACH (const CTxDSIn& s, v.sev) { - if ((CTxIn)s == in) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - found in vin\n"); - errorID = ERR_ALREADY_HAVE; - sessionUsers--; - return false; - } - } - } + if (!obfuScationSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) { + LogPrintf("CObfuscationQueue():Relay - Verify message failed"); + return false; } - CObfuScationEntry v; - v.Add(newInput, nAmount, txCollateral, newOutput); - entries.push_back(v); - - LogPrint("obfuscation", "CObfuscationPool::AddEntry -- adding %s\n", newInput[0].ToString()); - errorID = MSG_ENTRIES_ADDED; - return true; } -bool CObfuscationPool::AddScriptSig(const CTxIn& newVin) +bool CObfuscationQueue::Relay() { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig -- new sig %s\n", newVin.scriptSig.ToString().substr(0, 24)); - - - BOOST_FOREACH (const CObfuScationEntry& v, entries) { - BOOST_FOREACH (const CTxDSIn& s, v.sev) { - if (s.scriptSig == newVin.scriptSig) { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig - already exists\n"); - return false; - } - } + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) { + // always relay to everyone + pnode->PushMessage(NetMsgType::DSQ, (*this)); } - if (!SignatureValid(newVin.scriptSig, newVin)) { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig - Invalid Sig\n"); - return false; - } - - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig -- sig %s\n", newVin.ToString()); - - BOOST_FOREACH (CTxIn& vin, finalTransaction.vin) { - if (newVin.prevout == vin.prevout && vin.nSequence == newVin.nSequence) { - vin.scriptSig = newVin.scriptSig; - vin.prevPubKey = newVin.prevPubKey; - LogPrint("obfuscation", "CObfuScationPool::AddScriptSig -- adding to finalTransaction %s\n", newVin.scriptSig.ToString().substr(0, 24)); - } - } - for (unsigned int i = 0; i < entries.size(); i++) { - if (entries[i].AddSig(newVin)) { - LogPrint("obfuscation", "CObfuScationPool::AddScriptSig -- adding %s\n", newVin.scriptSig.ToString().substr(0, 24)); - return true; - } - } - - LogPrintf("CObfuscationPool::AddScriptSig -- Couldn't set sig!\n"); - return false; -} - -// Check to make sure everything is signed -bool CObfuscationPool::SignaturesComplete() -{ - BOOST_FOREACH (const CObfuScationEntry& v, entries) { - BOOST_FOREACH (const CTxDSIn& s, v.sev) { - if (!s.fHasSig) return false; - } - } - return true; -} - -// -// Execute a Obfuscation denomination via a Masternode. -// This is only ran from clients -// -void CObfuscationPool::SendObfuscationDenominate(std::vector& vin, std::vector& vout, CAmount amount) -{ - if (fMasterNode) { - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Obfuscation from a Masternode is not supported currently.\n"); - return; - } - - if (txCollateral == CMutableTransaction()) { - LogPrintf("CObfuscationPool:SendObfuscationDenominate() - Obfuscation collateral not set"); - return; - } - - // lock the funds we're going to use - BOOST_FOREACH (CTxIn in, txCollateral.vin) - lockedCoins.push_back(in); - - BOOST_FOREACH (CTxIn in, vin) - lockedCoins.push_back(in); - - //BOOST_FOREACH(CTxOut o, vout) - // LogPrintf(" vout - %s\n", o.ToString()); - - - // we should already be connected to a Masternode - if (!sessionFoundMasternode) { - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - No Masternode has been selected yet.\n"); - UnlockCoins(); - SetNull(); - return; - } - - if (!CheckDiskSpace()) { - UnlockCoins(); - SetNull(); - fEnableZeromint = false; - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Not enough disk space, disabling Obfuscation.\n"); - return; - } - - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Added transaction to pool.\n"); - - ClearLastMessage(); - - //check it against the memory pool to make sure it's valid - { - CAmount nValueOut = 0; - - CValidationState state; - CMutableTransaction tx; - - BOOST_FOREACH (const CTxOut& o, vout) { - nValueOut += o.nValue; - tx.vout.push_back(o); - } - - BOOST_FOREACH (const CTxIn& i, vin) { - tx.vin.push_back(i); - - LogPrint("obfuscation", "dsi -- tx in %s\n", i.ToString()); - } - - LogPrintf("Submitting tx %s\n", tx.ToString()); - - while (true) { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) { - MilliSleep(50); - continue; - } - if (!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL, false, true)) { - LogPrintf("dsi -- transaction not valid! %s \n", tx.ToString()); - UnlockCoins(); - SetNull(); - return; - } - break; - } - } - - // store our entry for later use - CObfuScationEntry e; - e.Add(vin, amount, txCollateral, vout); - entries.push_back(e); - - RelayIn(entries[0].sev, entries[0].amount, txCollateral, entries[0].vout); - Check(); -} - -// Incoming message from Masternode updating the progress of Obfuscation -// newAccepted: -1 mean's it'n not a "transaction accepted/not accepted" message, just a standard update -// 0 means transaction was not accepted -// 1 means transaction was accepted - -bool CObfuscationPool::StatusUpdate(int newState, int newEntriesCount, int newAccepted, int& errorID, int newSessionID) -{ - if (fMasterNode) return false; - if (state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; - - UpdateState(newState); - entriesCount = newEntriesCount; - - if (errorID != MSG_NOERR) strAutoDenomResult = _("Masternode:") + " " + GetMessageByID(errorID); - - if (newAccepted != -1) { - lastEntryAccepted = newAccepted; - countEntriesAccepted += newAccepted; - if (newAccepted == 0) { - UpdateState(POOL_STATUS_ERROR); - lastMessage = GetMessageByID(errorID); - } - - if (newAccepted == 1 && newSessionID != 0) { - sessionID = newSessionID; - LogPrintf("CObfuscationPool::StatusUpdate - set sessionID to %d\n", sessionID); - sessionFoundMasternode = true; - } - } - - if (newState == POOL_STATUS_ACCEPTING_ENTRIES) { - if (newAccepted == 1) { - LogPrintf("CObfuscationPool::StatusUpdate - entry accepted! \n"); - sessionFoundMasternode = true; - //wait for other users. Masternode will report when ready - UpdateState(POOL_STATUS_QUEUE); - } else if (newAccepted == 0 && sessionID == 0 && !sessionFoundMasternode) { - LogPrintf("CObfuscationPool::StatusUpdate - entry not accepted by Masternode \n"); - UnlockCoins(); - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - DoAutomaticDenominating(); //try another Masternode - } - if (sessionFoundMasternode) return true; - } - - return true; -} - -// -// After we receive the finalized transaction from the Masternode, we must -// check it to make sure it's what we want, then sign it if we agree. -// If we refuse to sign, it's possible we'll be charged collateral -// -bool CObfuscationPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node) -{ - if (fMasterNode) return false; - - finalTransaction = finalTransactionNew; - LogPrintf("CObfuscationPool::SignFinalTransaction %s", finalTransaction.ToString()); - - vector sigs; - - //make sure my inputs/outputs are present, otherwise refuse to sign - BOOST_FOREACH (const CObfuScationEntry e, entries) { - BOOST_FOREACH (const CTxDSIn s, e.sev) { - /* Sign my transaction and all outputs */ - int mine = -1; - CScript prevPubKey = CScript(); - CTxIn vin = CTxIn(); - - for (unsigned int i = 0; i < finalTransaction.vin.size(); i++) { - if (finalTransaction.vin[i] == s) { - mine = i; - prevPubKey = s.prevPubKey; - vin = s; - break; - } - } - - if (mine >= 0) { //might have to do this one input at a time? - int foundOutputs = 0; - CAmount nValue1 = 0; - CAmount nValue2 = 0; - - for (unsigned int i = 0; i < finalTransaction.vout.size(); i++) { - BOOST_FOREACH (const CTxOut& o, e.vout) { - if (finalTransaction.vout[i] == o) { - foundOutputs++; - nValue1 += finalTransaction.vout[i].nValue; - } - } - } - - BOOST_FOREACH (const CTxOut o, e.vout) - nValue2 += o.nValue; - - int targetOuputs = e.vout.size(); - if (foundOutputs < targetOuputs || nValue1 != nValue2) { - // in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's - // better then signing if the transaction doesn't look like what we wanted. - LogPrintf("CObfuscationPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n", foundOutputs, targetOuputs); - UnlockCoins(); - SetNull(); - - return false; - } - - const CKeyStore& keystore = *pwalletMain; - - LogPrint("obfuscation", "CObfuscationPool::Sign - Signing my input %i\n", mine); - if (!SignSignature(keystore, prevPubKey, finalTransaction, mine, nValue1, SIGHASH_ALL)) { // changes scriptSig - LogPrint("obfuscation", "CObfuscationPool::Sign - Unable to sign my own transaction! \n"); - // not sure what to do here, it will timeout...? - } - - sigs.push_back(finalTransaction.vin[mine]); - LogPrint("obfuscation", " -- dss %d %d %s\n", mine, (int)sigs.size(), finalTransaction.vin[mine].scriptSig.ToString()); - } - } - - LogPrint("obfuscation", "CObfuscationPool::Sign - txNew:\n%s", finalTransaction.ToString()); - } - - // push all of our signatures to the Masternode - if (sigs.size() > 0 && node != NULL) - node->PushMessage(NetMsgType::DSS, sigs); - - - return true; -} - -void CObfuscationPool::NewBlock() -{ - LogPrint("obfuscation", "CObfuscationPool::NewBlock \n"); - - //we we're processing lots of blocks, we'll just leave - if (GetTime() - lastNewBlock < 10) return; - lastNewBlock = GetTime(); - - obfuScationPool.CheckTimeout(); -} - -// Obfuscation transaction was completed (failed or successful) -void CObfuscationPool::CompletedTransaction(bool error, int errorID) -{ - if (fMasterNode) return; - - if (error) { - LogPrintf("CompletedTransaction -- error \n"); - UpdateState(POOL_STATUS_ERROR); - - Check(); - UnlockCoins(); - SetNull(); - } else { - LogPrintf("CompletedTransaction -- success \n"); - UpdateState(POOL_STATUS_SUCCESS); - - UnlockCoins(); - SetNull(); - - // To avoid race conditions, we'll only let DS run once per block - cachedLastSuccess = chainActive.Tip()->nHeight; - } - lastMessage = GetMessageByID(errorID); -} - -void CObfuscationPool::ClearLastMessage() -{ - lastMessage = ""; -} - -// -// Passively run Obfuscation in the background to anonymize funds based on the given configuration. -// -// This does NOT run by default for daemons, only for QT. -// -bool CObfuscationPool::DoAutomaticDenominating(bool fDryRun) -{ - return false; // Disabled until Obfuscation is completely removed - - if (!fEnableZeromint) return false; - if (fMasterNode) return false; - if (state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; - if (GetEntriesCount() > 0) { - strAutoDenomResult = _("Mixing in progress..."); - return false; - } - - TRY_LOCK(cs_obfuscation, lockDS); - if (!lockDS) { - strAutoDenomResult = _("Lock is already in place."); - return false; - } - - if (!masternodeSync.IsBlockchainSynced()) { - strAutoDenomResult = _("Can't mix while sync in progress."); - return false; - } - - if (!fDryRun && pwalletMain->IsLocked()) { - strAutoDenomResult = _("Wallet is locked."); - return false; - } - - if (chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing) { - LogPrintf("CObfuscationPool::DoAutomaticDenominating - Last successful Obfuscation action was too recent\n"); - strAutoDenomResult = _("Last successful Obfuscation action was too recent."); - return false; - } - - if (mnodeman.size() == 0) { - LogPrint("obfuscation", "CObfuscationPool::DoAutomaticDenominating - No Masternodes detected\n"); - strAutoDenomResult = _("No Masternodes detected."); - return false; - } - - // ** find the coins we'll use - std::vector vCoins; - CAmount nValueMin = CENT; - CAmount nValueIn = 0; - - CAmount nOnlyDenominatedBalance; - CAmount nBalanceNeedsDenominated; - - // should not be less than fees in OBFUSCATION_COLLATERAL + few (lets say 5) smallest denoms - CAmount nLowestDenom = OBFUSCATION_COLLATERAL + obfuScationDenominations[obfuScationDenominations.size() - 1] * 5; - - // if there are no OBF collateral inputs yet - if (!pwalletMain->HasCollateralInputs()) - // should have some additional amount for them - nLowestDenom += OBFUSCATION_COLLATERAL * 4; - - CAmount nBalanceNeedsAnonymized = nAnonymizePhoreAmount * COIN - pwalletMain->GetAnonymizedBalance(); - - // if balanceNeedsAnonymized is more than pool max, take the pool max - if (nBalanceNeedsAnonymized > OBFUSCATION_POOL_MAX) nBalanceNeedsAnonymized = OBFUSCATION_POOL_MAX; - - // if balanceNeedsAnonymized is more than non-anonymized, take non-anonymized - CAmount nAnonymizableBalance = pwalletMain->GetAnonymizableBalance(); - if (nBalanceNeedsAnonymized > nAnonymizableBalance) nBalanceNeedsAnonymized = nAnonymizableBalance; - - if (nBalanceNeedsAnonymized < nLowestDenom) { - LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating \n"); - strAutoDenomResult = _("No funds detected in need of denominating."); - return false; - } - - LogPrint("obfuscation", "DoAutomaticDenominating : nLowestDenom=%d, nBalanceNeedsAnonymized=%d\n", nLowestDenom, nBalanceNeedsAnonymized); - - // select coins that should be given to the pool - if (!pwalletMain->SelectCoinsDark(nValueMin, nBalanceNeedsAnonymized, vCoins, nValueIn, 0, nZeromintPercentage)) { - nValueIn = 0; - vCoins.clear(); - - if (pwalletMain->SelectCoinsDark(nValueMin, 9999999 * COIN, vCoins, nValueIn, -2, 0)) { - nOnlyDenominatedBalance = pwalletMain->GetDenominatedBalance(true) + pwalletMain->GetDenominatedBalance() - pwalletMain->GetAnonymizedBalance(); - nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance; - - if (nBalanceNeedsDenominated > nValueIn) nBalanceNeedsDenominated = nValueIn; - - if (nBalanceNeedsDenominated < nLowestDenom) return false; // most likely we just waiting for denoms to confirm - if (!fDryRun) return CreateDenominated(nBalanceNeedsDenominated); - - return true; - } else { - LogPrintf("DoAutomaticDenominating : Can't denominate - no compatible inputs left\n"); - strAutoDenomResult = _("Can't denominate: no compatible inputs left."); - return false; - } - } - - if (fDryRun) return true; - - nOnlyDenominatedBalance = pwalletMain->GetDenominatedBalance(true) + pwalletMain->GetDenominatedBalance() - pwalletMain->GetAnonymizedBalance(); - nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance; - - //check if we have should create more denominated inputs - if (nBalanceNeedsDenominated > nOnlyDenominatedBalance) return CreateDenominated(nBalanceNeedsDenominated); - - //check if we have the collateral sized inputs - if (!pwalletMain->HasCollateralInputs()) return !pwalletMain->HasCollateralInputs(false) && MakeCollateralAmounts(); - - std::vector vOut; - - // initial phase, find a Masternode - if (!sessionFoundMasternode) { - // Clean if there is anything left from previous session - UnlockCoins(); - SetNull(); - - int nUseQueue = rand() % 100; - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - - if (pwalletMain->GetDenominatedBalance(true) > 0) { //get denominated unconfirmed inputs - LogPrintf("DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n"); - strAutoDenomResult = _("Found unconfirmed denominated outputs, will wait till they confirm to continue."); - return false; - } - - //check our collateral nad create new if needed - std::string strReason; - CValidationState state; - if (txCollateral == CMutableTransaction()) { - if (!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)) { - LogPrintf("% -- create collateral error:%s\n", __func__, strReason); - return false; - } - } else { - if (!IsCollateralValid(txCollateral)) { - LogPrintf("%s -- invalid collateral, recreating...\n", __func__); - if (!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)) { - LogPrintf("%s -- create collateral error: %s\n", __func__, strReason); - return false; - } - } - } - - //if we've used 90% of the Masternode list then drop all the oldest first - int nThreshold = (int)(mnodeman.CountEnabled(ActiveProtocol()) * 0.9); - LogPrint("obfuscation", "Checking vecMasternodesUsed size %d threshold %d\n", (int)vecMasternodesUsed.size(), nThreshold); - while ((int)vecMasternodesUsed.size() > nThreshold) { - vecMasternodesUsed.erase(vecMasternodesUsed.begin()); - LogPrint("obfuscation", " vecMasternodesUsed size %d threshold %d\n", (int)vecMasternodesUsed.size(), nThreshold); - } - - //don't use the queues all of the time for mixing - if (nUseQueue > 33) { - // Look through the queues and see if anything matches - BOOST_FOREACH (CObfuscationQueue& dsq, vecObfuscationQueue) { - CService addr; - if (dsq.time == 0) continue; - - if (!dsq.GetAddress(addr)) continue; - if (dsq.IsExpired()) continue; - - int protocolVersion; - if (!dsq.GetProtocolVersion(protocolVersion)) continue; - if (protocolVersion < ActiveProtocol()) continue; - - //non-denom's are incompatible - if ((dsq.nDenom & (1 << 4))) continue; - - bool fUsed = false; - //don't reuse Masternodes - BOOST_FOREACH (CTxIn usedVin, vecMasternodesUsed) { - if (dsq.vin == usedVin) { - fUsed = true; - break; - } - } - if (fUsed) continue; - - std::vector vTempCoins; - std::vector vTempCoins2; - // Try to match their denominations if possible - if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, nBalanceNeedsAnonymized, vTempCoins, vTempCoins2, nValueIn, 0, nZeromintPercentage)) { - LogPrintf("DoAutomaticDenominating --- Couldn't match denominations %d\n", dsq.nDenom); - continue; - } - - CMasternode* pmn = mnodeman.Find(dsq.vin); - if (pmn == NULL) { - LogPrintf("DoAutomaticDenominating --- dsq vin %s is not in masternode list!", dsq.vin.ToString()); - continue; - } - - LogPrintf("DoAutomaticDenominating --- attempt to connect to masternode from queue %s\n", pmn->addr.ToString()); - lastTimeChanged = GetTimeMillis(); - - // connect to Masternode and submit the queue request - CNode* pnode = ConnectNode((CAddress)addr, NULL, true); - if (pnode != NULL) { - pSubmittedToMasternode = pmn; - vecMasternodesUsed.push_back(dsq.vin); - sessionDenom = dsq.nDenom; - - pnode->PushMessage(NetMsgType::DSA, sessionDenom, txCollateral); - LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for %d - %s\n", sessionDenom, pnode->addr.ToString()); - strAutoDenomResult = _("Mixing in progress..."); - dsq.time = 0; //remove node - return true; - } else { - LogPrintf("DoAutomaticDenominating --- error connecting \n"); - strAutoDenomResult = _("Error connecting to Masternode."); - dsq.time = 0; //remove node - continue; - } - } - } - - // do not initiate queue if we are a liquidity proveder to avoid useless inter-mixing - if (nLiquidityProvider) return false; - - int i = 0; - - // otherwise, try one randomly - while (i < 10) { - CMasternode* pmn = mnodeman.FindRandomNotInVec(vecMasternodesUsed, ActiveProtocol()); - if (pmn == NULL) { - LogPrintf("DoAutomaticDenominating --- Can't find random masternode!\n"); - strAutoDenomResult = _("Can't find random Masternode."); - return false; - } - - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - i++; - continue; - } - - lastTimeChanged = GetTimeMillis(); - LogPrintf("DoAutomaticDenominating --- attempt %d connection to Masternode %s\n", i, pmn->addr.ToString()); - CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, true); - if (pnode != NULL) { - pSubmittedToMasternode = pmn; - vecMasternodesUsed.push_back(pmn->vin); - - std::vector vecAmounts; - pwalletMain->ConvertList(vCoins, vecAmounts); - // try to get a single random denom out of vecAmounts - while (sessionDenom == 0) - sessionDenom = GetDenominationsByAmounts(vecAmounts); - - pnode->PushMessage(NetMsgType::DSA, sessionDenom, txCollateral); - LogPrintf("DoAutomaticDenominating --- connected, sending dsa for %d\n", sessionDenom); - strAutoDenomResult = _("Mixing in progress..."); - return true; - } else { - vecMasternodesUsed.push_back(pmn->vin); // postpone MN we wasn't able to connect to - i++; - continue; - } - } - - strAutoDenomResult = _("No compatible Masternode found."); - return false; - } - - strAutoDenomResult = _("Mixing in progress..."); - return false; -} - - -bool CObfuscationPool::PrepareObfuscationDenominate() -{ - std::string strError = ""; - // Submit transaction to the pool if we get here - // Try to use only inputs with the same number of rounds starting from lowest number of rounds possible - for (int i = 0; i < nZeromintPercentage; i++) { - strError = pwalletMain->PrepareObfuscationDenominate(i, i + 1); - LogPrintf("DoAutomaticDenominating : Running Obfuscation denominate for %d rounds. Return '%s'\n", i, strError); - if (strError == "") return true; - } - - // We failed? That's strange but let's just make final attempt and try to mix everything - strError = pwalletMain->PrepareObfuscationDenominate(0, nZeromintPercentage); - LogPrintf("DoAutomaticDenominating : Running Obfuscation denominate for all rounds. Return '%s'\n", strError); - if (strError == "") return true; - - // Should never actually get here but just in case - strAutoDenomResult = strError; - LogPrintf("DoAutomaticDenominating : Error running denominate, %s\n", strError); - return false; -} - -bool CObfuscationPool::SendRandomPaymentToSelf() -{ - int64_t nBalance = pwalletMain->GetBalance(); - int64_t nPayment = (nBalance * 0.35) + (rand() % nBalance); - - if (nPayment > nBalance) nPayment = nBalance - (0.1 * COIN); - - // make our change address - CReserveKey reservekey(pwalletMain); - - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey, false)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey.GetID()); - - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - vector > vecSend; - - // ****** Add fees ************ / - vecSend.push_back(make_pair(scriptChange, nPayment)); - - CCoinControl* coinControl = NULL; - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRet, strFail, coinControl, ONLY_DENOMINATED); - if (!success) { - LogPrintf("SendRandomPaymentToSelf: Error - %s\n", strFail); - return false; - } - - pwalletMain->CommitTransaction(wtx, reservekey); - - LogPrintf("SendRandomPaymentToSelf Success: tx %s\n", wtx.GetHash().GetHex()); - - return true; -} - -// Split up large inputs or create fee sized inputs -bool CObfuscationPool::MakeCollateralAmounts() -{ - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - vector > vecSend; - CCoinControl coinControl; - coinControl.fAllowOtherInputs = false; - coinControl.fAllowWatchOnly = false; - // make our collateral address - CReserveKey reservekeyCollateral(pwalletMain); - // make our change address - CReserveKey reservekeyChange(pwalletMain); - - CScript scriptCollateral; - CPubKey vchPubKey; - assert(reservekeyCollateral.GetReservedKey(vchPubKey, false)); // should never fail, as we just unlocked - scriptCollateral = GetScriptForDestination(vchPubKey.GetID()); - - vecSend.push_back(make_pair(scriptCollateral, OBFUSCATION_COLLATERAL * 4)); - - // try to use non-denominated and not mn-like funds - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, strFail, &coinControl, ONLY_NONDENOMINATED_NOT10000IFMN); - if (!success) { - // if we failed (most likeky not enough funds), try to use all coins instead - - // MN-like funds should not be touched in any case and we can't mix denominated without collaterals anyway - CCoinControl* coinControlNull = NULL; - LogPrintf("MakeCollateralAmounts: ONLY_NONDENOMINATED_NOT10000IFMN Error - %s\n", strFail); - success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, strFail, coinControlNull, ONLY_NOT10000IFMN); - if (!success) { - LogPrintf("MakeCollateralAmounts: ONLY_NOT10000IFMN Error - %s\n", strFail); - reservekeyCollateral.ReturnKey(); - return false; - } - } - - reservekeyCollateral.KeepKey(); - - LogPrintf("MakeCollateralAmounts: tx %s\n", wtx.GetHash().GetHex()); - - // use the same cachedLastSuccess as for DS mixinx to prevent race - if (!pwalletMain->CommitTransaction(wtx, reservekeyChange)) { - LogPrintf("MakeCollateralAmounts: CommitTransaction failed!\n"); - return false; - } - - cachedLastSuccess = chainActive.Tip()->nHeight; - - return true; -} - -// Create denominations -bool CObfuscationPool::CreateDenominated(CAmount nTotalValue) -{ - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - vector > vecSend; - CAmount nValueLeft = nTotalValue; - - // make our collateral address - CReserveKey reservekeyCollateral(pwalletMain); - // make our change address - CReserveKey reservekeyChange(pwalletMain); - // make our denom addresses - CReserveKey reservekeyDenom(pwalletMain); - - CScript scriptCollateral; - CPubKey vchPubKey; - assert(reservekeyCollateral.GetReservedKey(vchPubKey, false)); // should never fail, as we just unlocked - scriptCollateral = GetScriptForDestination(vchPubKey.GetID()); - - // ****** Add collateral outputs ************ / - if (!pwalletMain->HasCollateralInputs()) { - vecSend.push_back(make_pair(scriptCollateral, OBFUSCATION_COLLATERAL * 4)); - nValueLeft -= OBFUSCATION_COLLATERAL * 4; - } - - // ****** Add denoms ************ / - BOOST_REVERSE_FOREACH (CAmount v, obfuScationDenominations) { - int nOutputs = 0; - - // add each output up to 10 times until it can't be added again - while (nValueLeft - v >= OBFUSCATION_COLLATERAL && nOutputs <= 10) { - CScript scriptDenom; - CPubKey vchPubKey; - //use a unique change address - assert(reservekeyDenom.GetReservedKey(vchPubKey, false)); // should never fail, as we just unlocked - scriptDenom = GetScriptForDestination(vchPubKey.GetID()); - // TODO: do not keep reservekeyDenom here - reservekeyDenom.KeepKey(); - - vecSend.push_back(make_pair(scriptDenom, v)); - - //increment outputs and subtract denomination amount - nOutputs++; - nValueLeft -= v; - LogPrintf("CreateDenominated1 %d\n", nValueLeft); - } - - if (nValueLeft == 0) break; - } - LogPrintf("CreateDenominated2 %d\n", nValueLeft); - - // if we have anything left over, it will be automatically send back as change - there is no need to send it manually - - CCoinControl* coinControl = NULL; - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, strFail, coinControl, ONLY_NONDENOMINATED_NOT10000IFMN); - if (!success) { - LogPrintf("CreateDenominated: Error - %s\n", strFail); - // TODO: return reservekeyDenom here - reservekeyCollateral.ReturnKey(); - return false; - } - - // TODO: keep reservekeyDenom here - reservekeyCollateral.KeepKey(); - - // use the same cachedLastSuccess as for DS mixinx to prevent race - if (pwalletMain->CommitTransaction(wtx, reservekeyChange)) - cachedLastSuccess = chainActive.Tip()->nHeight; - else - LogPrintf("CreateDenominated: CommitTransaction failed!\n"); - - LogPrintf("CreateDenominated: tx %s\n", wtx.GetHash().GetHex()); - - return true; -} - -bool CObfuscationPool::IsCompatibleWithEntries(std::vector& vout) -{ - if (GetDenominations(vout) == 0) return false; - - BOOST_FOREACH (const CObfuScationEntry v, entries) { - LogPrintf(" IsCompatibleWithEntries %d %d\n", GetDenominations(vout), GetDenominations(v.vout)); - /* - BOOST_FOREACH(CTxOut o1, vout) - LogPrintf(" vout 1 - %s\n", o1.ToString()); - - BOOST_FOREACH(CTxOut o2, v.vout) - LogPrintf(" vout 2 - %s\n", o2.ToString()); -*/ - if (GetDenominations(vout) != GetDenominations(v.vout)) return false; - } - - return true; -} - -bool CObfuscationPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txCollateral, int& errorID) -{ - if (nDenom == 0) return false; - - LogPrintf("CObfuscationPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d\n", sessionDenom, sessionUsers); - - if (!unitTest && !IsCollateralValid(txCollateral)) { - LogPrint("obfuscation", "CObfuscationPool::IsCompatibleWithSession - collateral not valid!\n"); - errorID = ERR_INVALID_COLLATERAL; - return false; - } - - if (sessionUsers < 0) sessionUsers = 0; - - if (sessionUsers == 0) { - sessionID = 1 + (rand() % 999999); - sessionDenom = nDenom; - sessionUsers++; - lastTimeChanged = GetTimeMillis(); - - if (!unitTest) { - //broadcast that I'm accepting entries, only if it's the first entry through - CObfuscationQueue dsq; - dsq.nDenom = nDenom; - dsq.vin = activeMasternode.vin; - dsq.time = GetTime(); - dsq.Sign(); - dsq.Relay(); - } - - UpdateState(POOL_STATUS_QUEUE); - vecSessionCollateral.push_back(txCollateral); - return true; - } - - if ((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE) || sessionUsers >= GetMaxPoolTransactions()) { - if ((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE)) errorID = ERR_MODE; - if (sessionUsers >= GetMaxPoolTransactions()) errorID = ERR_QUEUE_FULL; - LogPrintf("CObfuscationPool::IsCompatibleWithSession - incompatible mode, return false %d %d\n", state != POOL_STATUS_ACCEPTING_ENTRIES, sessionUsers >= GetMaxPoolTransactions()); - return false; - } - - if (nDenom != sessionDenom) { - errorID = ERR_DENOM; - return false; - } - - LogPrintf("CObfuScationPool::IsCompatibleWithSession - compatible\n"); - - sessionUsers++; - lastTimeChanged = GetTimeMillis(); - vecSessionCollateral.push_back(txCollateral); - - return true; -} - -//create a nice string to show the denominations -void CObfuscationPool::GetDenominationsToString(int nDenom, std::string& strDenom) -{ - // Function returns as follows: - // - // bit 0 - 100PHR+1 ( bit on if present ) - // bit 1 - 10PHR+1 - // bit 2 - 1PHR+1 - // bit 3 - .1PHR+1 - // bit 3 - non-denom - - - strDenom = ""; - - if (nDenom & (1 << 0)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "100"; - } - - if (nDenom & (1 << 1)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "10"; - } - - if (nDenom & (1 << 2)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "1"; - } - - if (nDenom & (1 << 3)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "0.1"; - } -} - -int CObfuscationPool::GetDenominations(const std::vector& vout) -{ - std::vector vout2; - - BOOST_FOREACH (CTxDSOut out, vout) - vout2.push_back(out); - - return GetDenominations(vout2); -} - -// return a bitshifted integer representing the denominations in this list -int CObfuscationPool::GetDenominations(const std::vector& vout, bool fSingleRandomDenom) -{ - std::vector > denomUsed; - - // make a list of denominations, with zero uses - BOOST_FOREACH (int64_t d, obfuScationDenominations) - denomUsed.push_back(make_pair(d, 0)); - - // look for denominations and update uses to 1 - BOOST_FOREACH (CTxOut out, vout) { - bool found = false; - BOOST_FOREACH (PAIRTYPE(int64_t, int) & s, denomUsed) { - if (out.nValue == s.first) { - s.second = 1; - found = true; - } - } - if (!found) return 0; - } - - int denom = 0; - int c = 0; - // if the denomination is used, shift the bit on. - // then move to the next - BOOST_FOREACH (PAIRTYPE(int64_t, int) & s, denomUsed) { - int bit = (fSingleRandomDenom ? rand() % 2 : 1) * s.second; - denom |= bit << c++; - if (fSingleRandomDenom && bit) break; // use just one random denomination - } - - // Function returns as follows: - // - // bit 0 - 100PHR+1 ( bit on if present ) - // bit 1 - 10PHR+1 - // bit 2 - 1PHR+1 - // bit 3 - .1PHR+1 - - return denom; -} - - -int CObfuscationPool::GetDenominationsByAmounts(std::vector& vecAmount) -{ - CScript e = CScript(); - std::vector vout1; - - // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH (CAmount v, vecAmount) { - CTxOut o(v, e); - vout1.push_back(o); - } - - return GetDenominations(vout1, true); -} - -int CObfuscationPool::GetDenominationsByAmount(CAmount nAmount, int nDenomTarget) -{ - CScript e = CScript(); - CAmount nValueLeft = nAmount; - - std::vector vout1; - - // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH (CAmount v, obfuScationDenominations) { - if (nDenomTarget != 0) { - bool fAccepted = false; - if ((nDenomTarget & (1 << 0)) && v == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 1)) && v == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 2)) && v == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 3)) && v == ((.1 * COIN) + 100)) { - fAccepted = true; - } - if (!fAccepted) continue; - } - - int nOutputs = 0; - - // add each output up to 10 times until it can't be added again - while (nValueLeft - v >= 0 && nOutputs <= 10) { - CTxOut o(v, e); - vout1.push_back(o); - nValueLeft -= v; - nOutputs++; - } - LogPrintf("GetDenominationsByAmount --- %d nOutputs %d\n", v, nOutputs); - } - - return GetDenominations(vout1); -} - -std::string CObfuscationPool::GetMessageByID(int messageID) -{ - switch (messageID) { - case ERR_ALREADY_HAVE: - return _("Already have that input."); - case ERR_DENOM: - return _("No matching denominations found for mixing."); - case ERR_ENTRIES_FULL: - return _("Entries are full."); - case ERR_EXISTING_TX: - return _("Not compatible with existing transactions."); - case ERR_FEES: - return _("Transaction fees are too high."); - case ERR_INVALID_COLLATERAL: - return _("Collateral not valid."); - case ERR_INVALID_INPUT: - return _("Input is not valid."); - case ERR_INVALID_SCRIPT: - return _("Invalid script detected."); - case ERR_INVALID_TX: - return _("Transaction not valid."); - case ERR_MAXIMUM: - return _("Value more than Obfuscation pool maximum allows."); - case ERR_MN_LIST: - return _("Not in the Masternode list."); - case ERR_MODE: - return _("Incompatible mode."); - case ERR_NON_STANDARD_PUBKEY: - return _("Non-standard public key detected."); - case ERR_NOT_A_MN: - return _("This is not a Masternode."); - case ERR_QUEUE_FULL: - return _("Masternode queue is full."); - case ERR_RECENT: - return _("Last Obfuscation was too recent."); - case ERR_SESSION: - return _("Session not complete!"); - case ERR_MISSING_TX: - return _("Missing input transaction information."); - case ERR_VERSION: - return _("Incompatible version."); - case MSG_SUCCESS: - return _("Transaction created successfully."); - case MSG_ENTRIES_ADDED: - return _("Your entries added successfully."); - case MSG_NOERR: - default: - return ""; - } -} - -bool CObfuScationSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey) -{ - CScript payee2; - payee2 = GetScriptForDestination(pubkey.GetID()); - - CTransaction txVin; - uint256 hash; - if (GetTransaction(vin.prevout.hash, txVin, hash, true)) { - BOOST_FOREACH (CTxOut out, txVin.vout) { - if (out.nValue == 10000 * COIN) { - if (out.scriptPubKey == payee2) return true; - } - } - } - - return false; -} - -bool CObfuScationSigner::SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey) -{ - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strSecret); - - if (!fGood) { - errorMessage = _("Invalid private key."); - return false; - } - - key = vchSecret.GetKey(); - pubkey = key.GetPubKey(); - return true; } -bool CObfuScationSigner::GetKeysFromSecret(std::string strSecret, CKey& keyRet, CPubKey& pubkeyRet) -{ - CBitcoinSecret vchSecret; - - if (!vchSecret.SetString(strSecret)) return false; - - keyRet = vchSecret.GetKey(); - pubkeyRet = keyRet.GetPubKey(); - - return true; -} - -bool CObfuScationSigner::SignMessage(std::string strMessage, std::string& errorMessage, vector& vchSig, CKey key) -{ - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - if (!key.SignCompact(ss.GetHash(), vchSig)) { - errorMessage = _("Signing failed."); - return false; - } - - return true; -} - -bool CObfuScationSigner::VerifyMessage(CPubKey pubkey, vector& vchSig, std::string strMessage, std::string& errorMessage) -{ - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - CPubKey pubkey2; - if (!pubkey2.RecoverCompact(ss.GetHash(), vchSig)) { - errorMessage = _("Error recovering public key."); - return false; - } - - if (fDebug && pubkey2.GetID() != pubkey.GetID()) - LogPrintf("CObfuScationSigner::VerifyMessage -- keys don't match: %s %s\n", pubkey2.GetID().ToString(), pubkey.GetID().ToString()); - - return (pubkey2.GetID() == pubkey.GetID()); -} - -bool CObfuscationQueue::Sign() -{ - if (!fMasterNode) return false; - - std::string strMessage = vin.ToString() + std::to_string(nDenom) + std::to_string(time) + std::to_string(ready); - - CKey key2; - CPubKey pubkey2; - std::string errorMessage = ""; - - if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2)) { - LogPrintf("CObfuscationQueue():Relay - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage); - return false; - } - - if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, key2)) { - LogPrintf("CObfuscationQueue():Relay - Sign message failed"); - return false; - } - - if (!obfuScationSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) { - LogPrintf("CObfuscationQueue():Relay - Verify message failed"); - return false; - } - - return true; -} - -bool CObfuscationQueue::Relay() -{ - LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { - // always relay to everyone - pnode->PushMessage(NetMsgType::DSQ, (*this)); - } - - return true; -} - -bool CObfuscationQueue::CheckSignature() -{ - CMasternode* pmn = mnodeman.Find(vin); - - if (pmn != NULL) { - std::string strMessage = vin.ToString() + std::to_string(nDenom) + std::to_string(time) + std::to_string(ready); - - std::string errorMessage = ""; - if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - return error("CObfuscationQueue::CheckSignature() - Got bad Masternode address signature %s \n", vin.ToString().c_str()); - } - - return true; - } - - return false; -} - - void CObfuscationPool::RelayFinalTransaction(const int sessionID, const CTransaction& txNew) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { pnode->PushMessage(NetMsgType::DSF, sessionID, txNew); } } -void CObfuscationPool::RelayIn(const std::vector& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& vout) -{ - if (!pSubmittedToMasternode) return; - - std::vector vin2; - std::vector vout2; - - BOOST_FOREACH (CTxDSIn in, vin) - vin2.push_back(in); - - BOOST_FOREACH (CTxDSOut out, vout) - vout2.push_back(out); - - CNode* pnode = FindNode(pSubmittedToMasternode->addr); - if (pnode != NULL) { - LogPrintf("RelayIn - found master, relaying message - %s \n", pnode->addr.ToString()); - pnode->PushMessage(NetMsgType::DSI, vin2, nAmount, txCollateral, vout2); - } -} - void CObfuscationPool::RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage(NetMsgType::DSSU, sessionID, newState, newEntriesCount, newAccepted, errorID); } void CObfuscationPool::RelayCompletedTransaction(const int sessionID, const bool error, const int errorID) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage(NetMsgType::DSC, sessionID, error, errorID); } @@ -2318,10 +694,6 @@ void ThreadCheckObfuScationPool() obfuScationPool.CheckTimeout(); obfuScationPool.CheckForCompleteQueue(); - - if (obfuScationPool.GetState() == POOL_STATUS_IDLE && c % 15 == 0) { - obfuScationPool.DoAutomaticDenominating(); - } } } } diff --git a/src/obfuscation.h b/src/obfuscation.h index 9823d6983b96..2f2df1898efd 100644 --- a/src/obfuscation.h +++ b/src/obfuscation.h @@ -52,7 +52,7 @@ extern CObfuscationPool obfuScationPool; extern CObfuScationSigner obfuScationSigner; extern std::vector vecObfuscationQueue; extern std::string strMasterNodePrivKey; -extern map mapObfuscationBroadcastTxes; +extern std::map mapObfuscationBroadcastTxes; extern CActiveMasternode activeMasternode; /** Holds an Obfuscation input @@ -61,7 +61,6 @@ class CTxDSIn : public CTxIn { public: bool fHasSig; // flag to indicate if signed - int nSentTimes; //times we've sent this anonymously CTxDSIn(const CTxIn& in) { @@ -69,7 +68,6 @@ class CTxDSIn : public CTxIn scriptSig = in.scriptSig; prevPubKey = in.prevPubKey; nSequence = in.nSequence; - nSentTimes = 0; fHasSig = false; } }; @@ -99,7 +97,6 @@ class CObfuScationEntry std::vector vout; CAmount amount; CTransaction collateral; - CTransaction txSupporting; int64_t addedTime; // time in UTC milliseconds CObfuScationEntry() @@ -116,10 +113,10 @@ class CObfuScationEntry return false; } - BOOST_FOREACH (const CTxIn& in, vinIn) + for (const CTxIn& in : vinIn) sev.push_back(in); - BOOST_FOREACH (const CTxOut& out, voutIn) + for (const CTxOut& out : voutIn) vout.push_back(out); amount = amountIn; @@ -130,24 +127,6 @@ class CObfuScationEntry return true; } - bool AddSig(const CTxIn& vin) - { - BOOST_FOREACH (CTxDSIn& s, sev) { - if (s.prevout == vin.prevout && s.nSequence == vin.nSequence) { - if (s.fHasSig) { - return false; - } - s.scriptSig = vin.scriptSig; - s.prevPubKey = vin.prevPubKey; - s.fHasSig = true; - - return true; - } - } - - return false; - } - bool IsExpired() { return (GetTime() - addedTime) > OBFUSCATION_QUEUE_TIMEOUT; // 120 seconds @@ -188,27 +167,6 @@ class CObfuscationQueue READWRITE(vchSig); } - bool GetAddress(CService& addr) - { - CMasternode* pmn = mnodeman.Find(vin); - if (pmn != NULL) { - addr = pmn->addr; - return true; - } - return false; - } - - /// Get the protocol version - bool GetProtocolVersion(int& protocolVersion) - { - CMasternode* pmn = mnodeman.Find(vin); - if (pmn != NULL) { - protocolVersion = pmn->protocolVersion; - return true; - } - return false; - } - /** Sign this Obfuscation transaction * \return true if all conditions are met: * 1) we have an active Masternode, @@ -226,8 +184,6 @@ class CObfuscationQueue return (GetTime() - time) > OBFUSCATION_QUEUE_TIMEOUT; // 120 seconds } - /// Check if we have a valid Masternode address - bool CheckSignature(); }; /** Helper class to store Obfuscation transaction (tx) information. @@ -237,7 +193,7 @@ class CObfuscationBroadcastTx public: CTransaction tx; CTxIn vin; - vector vchSig; + std::vector vchSig; int64_t sigTime; }; @@ -263,7 +219,6 @@ class CObfuScationSigner class CObfuscationPool { private: - mutable CCriticalSection cs_obfuscation; std::vector entries; // Masternode/clients entries CMutableTransaction finalTransaction; // the finalized transaction ready for signing @@ -278,18 +233,15 @@ class CObfuscationPool std::vector lockedCoins; std::string lastMessage; - bool unitTest; int sessionID; int sessionUsers; //N Users have said they'll join - bool sessionFoundMasternode; //If we've found a compatible Masternode std::vector vecSessionCollateral; int cachedLastSuccess; int minBlockSpacing; //required blocks between mixes - CMutableTransaction txCollateral; int64_t lastNewBlock; @@ -327,7 +279,6 @@ class CObfuscationPool CMasternode* pSubmittedToMasternode; int sessionDenom; //Users must submit an denom matching this - int cachedNumBlocks; //used for the overview screen CObfuscationPool() { @@ -335,42 +286,17 @@ class CObfuscationPool to behave themselves. If they don't it takes their money. */ cachedLastSuccess = 0; - cachedNumBlocks = std::numeric_limits::max(); - unitTest = false; - txCollateral = CMutableTransaction(); minBlockSpacing = 0; lastNewBlock = 0; SetNull(); } - /** Process a Obfuscation message using the Obfuscation protocol - * \param pfrom - * \param strCommand lower case command string; valid values are: - * Command | Description - * -------- | ----------------- - * dsa | Obfuscation Acceptable - * dsc | Obfuscation Complete - * dsf | Obfuscation Final tx - * dsi | Obfuscation vIn - * dsq | Obfuscation Queue - * dss | Obfuscation Signal Final Tx - * dssu | Obfuscation status update - * dssub | Obfuscation Subscribe To - * \param vRecv - */ - void ProcessMessageObfuscation(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); - void InitCollateralAddress() { SetCollateralAddress(Params().ObfuscationPoolDummyAddress()); } - void SetMinBlockSpacing(int minBlockSpacingIn) - { - minBlockSpacing = minBlockSpacingIn; - } - bool SetCollateralAddress(std::string strAddress); void Reset(); void SetNull(); @@ -387,19 +313,11 @@ class CObfuscationPool return state; } - std::string GetStatus(); - int GetEntriesCount() const { return entries.size(); } - /// Get the time the last entry was accepted (time in UTC milliseconds) - int GetLastEntryAccepted() const - { - return lastEntryAccepted; - } - /// Get the count of the accepted entries int GetCountEntriesAccepted() const { @@ -430,22 +348,6 @@ class CObfuscationPool return Params().PoolMaxTransactions(); } - /// Do we have enough users to take entries? - bool IsSessionReady() - { - return sessionUsers >= GetMaxPoolTransactions(); - } - - /// Are these outputs compatible with other client in the pool? - bool IsCompatibleWithEntries(std::vector& vout); - - /// Is this amount compatible with other client in the pool? - bool IsCompatibleWithSession(CAmount nAmount, CTransaction txCollateral, int& errorID); - - /// Passively run Obfuscation in the background according to the configuration in settings (only for QT) - bool DoAutomaticDenominating(bool fDryRun = false); - bool PrepareObfuscationDenominate(); - /// Check for process in Obfuscation void Check(); void CheckFinalTransaction(); @@ -455,57 +357,14 @@ class CObfuscationPool void ChargeRandomFees(); void CheckTimeout(); void CheckForCompleteQueue(); - /// Check to make sure a signature matches an input in the pool - bool SignatureValid(const CScript& newSig, const CTxIn& newVin); - /// If the collateral is valid given by a client - bool IsCollateralValid(const CTransaction& txCollateral); - /// Add a clients entry to the pool - bool AddEntry(const std::vector& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, int& errorID); - /// Add signature to a vin - bool AddScriptSig(const CTxIn& newVin); /// Check that all inputs are signed. (Are all inputs signed?) bool SignaturesComplete(); - /// As a client, send a transaction to a Masternode to start the denomination process - void SendObfuscationDenominate(std::vector& vin, std::vector& vout, CAmount amount); - /// Get Masternode updates about the progress of Obfuscation - bool StatusUpdate(int newState, int newEntriesCount, int newAccepted, int& errorID, int newSessionID = 0); - - /// As a client, check and sign the final transaction - bool SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node); - - /// Get the last valid block hash for a given modulus - bool GetLastValidBlockHash(uint256& hash, int mod = 1, int nBlockHeight = 0); /// Process a new block void NewBlock(); - void CompletedTransaction(bool error, int errorID); - void ClearLastMessage(); - /// Used for liquidity providers - bool SendRandomPaymentToSelf(); - - /// Split up large inputs or make fee sized inputs - bool MakeCollateralAmounts(); - bool CreateDenominated(CAmount nTotalValue); - - /// Get the denominations for a list of outputs (returns a bitshifted integer) - int GetDenominations(const std::vector& vout, bool fSingleRandomDenom = false); - int GetDenominations(const std::vector& vout); - - void GetDenominationsToString(int nDenom, std::string& strDenom); - - /// Get the denominations for a specific amount of phore. - int GetDenominationsByAmount(CAmount nAmount, int nDenomTarget = 0); // is not used anymore? - int GetDenominationsByAmounts(std::vector& vecAmount); - - std::string GetMessageByID(int messageID); - // // Relay Obfuscation Messages // - void RelayFinalTransaction(const int sessionID, const CTransaction& txNew); - void RelaySignaturesAnon(std::vector& vin); - void RelayInAnon(std::vector& vin, std::vector& vout); - void RelayIn(const std::vector& vin, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& vout); void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID = MSG_NOERR); void RelayCompletedTransaction(const int sessionID, const bool error, const int errorID); }; diff --git a/src/phore-cli.cpp b/src/phore-cli.cpp index 56ab479e031a..c31fa8ac608c 100644 --- a/src/phore-cli.cpp +++ b/src/phore-cli.cpp @@ -8,8 +8,8 @@ #include "chainparamsbase.h" #include "clientversion.h" -#include "rpcclient.h" -#include "rpcprotocol.h" +#include "rpc/client.h" +#include "rpc/protocol.h" #include "util.h" #include "utilstrencodings.h" @@ -25,13 +25,12 @@ #define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ -using namespace std; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; std::string HelpMessageCli() { - string strUsage; + std::string strUsage; strUsage += HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), "phore.conf")); @@ -142,7 +141,7 @@ static void http_request_done(struct evhttp_request *req, void *ctx) } } -UniValue CallRPC(const string& strMethod, const UniValue& params) +UniValue CallRPC(const std::string& strMethod, const UniValue& params) { std::string host = GetArg("-rpcconnect", "127.0.0.1"); int port = GetArg("-rpcport", BaseParams().RPCPort()); @@ -150,25 +149,25 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) // Create event base struct event_base *base = event_base_new(); // TODO RAII if (!base) - throw runtime_error("cannot create event_base"); + throw std::runtime_error("cannot create event_base"); // Synchronously look up hostname struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII if (evcon == NULL) - throw runtime_error("create connection failed"); + throw std::runtime_error("create connection failed"); evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); HTTPReply response; struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII if (req == NULL) - throw runtime_error("create http request failed"); + throw std::runtime_error("create http request failed"); // Get credentials std::string strRPCUserColonPass; if (mapArgs["-rpcpassword"] == "") { // Try fall back to cookie-based authentication if no password is provided if (!GetAuthCookie(&strRPCUserColonPass)) { - throw runtime_error(strprintf( + throw std::runtime_error(strprintf( _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"), GetConfigFile().string().c_str())); @@ -203,26 +202,26 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) if (response.status == 0) throw CConnectionFailed("couldn't connect to server"); else if (response.status == HTTP_UNAUTHORIZED) - throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); + throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) - throw runtime_error(strprintf("server returned HTTP error %d", response.status)); + throw std::runtime_error(strprintf("server returned HTTP error %d", response.status)); else if (response.body.empty()) - throw runtime_error("no response from server"); + throw std::runtime_error("no response from server"); // Parse reply UniValue valReply(UniValue::VSTR); if (!valReply.read(response.body)) - throw runtime_error("couldn't parse reply from server"); + throw std::runtime_error("couldn't parse reply from server"); const UniValue& reply = valReply.get_obj(); if (reply.empty()) - throw runtime_error("expected reply to have result, error and id properties"); + throw std::runtime_error("expected reply to have result, error and id properties"); return reply; } int CommandLineRPC(int argc, char* argv[]) { - string strPrint; + std::string strPrint; int nRet = 0; try { // Skip switches @@ -233,8 +232,8 @@ int CommandLineRPC(int argc, char* argv[]) // Method if (argc < 2) - throw runtime_error("too few parameters"); - string strMethod = argv[1]; + throw std::runtime_error("too few parameters"); + std::string strMethod = argv[1]; // Parameters default to strings std::vector strParams(&argv[2], &argv[argc]); @@ -278,7 +277,7 @@ int CommandLineRPC(int argc, char* argv[]) } catch (boost::thread_interrupted) { throw; } catch (std::exception& e) { - strPrint = string("error: ") + e.what(); + strPrint = std::string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { PrintExceptionContinue(NULL, "CommandLineRPC()"); diff --git a/src/phore-tx.cpp b/src/phore-tx.cpp index 837b4a161796..e795a42613d6 100644 --- a/src/phore-tx.cpp +++ b/src/phore-tx.cpp @@ -24,11 +24,9 @@ #include #include -using namespace boost::assign; -using namespace std; static bool fCreateBlank; -static map registers; +static std::map registers; CClientUIInterface uiInterface; static bool AppInitRawTx(int argc, char* argv[]) @@ -92,52 +90,52 @@ static bool AppInitRawTx(int argc, char* argv[]) return true; } -static void RegisterSetJson(const string& key, const string& rawJson) +static void RegisterSetJson(const std::string& key, const std::string& rawJson) { UniValue val; if (!val.read(rawJson)) { - string strErr = "Cannot parse JSON for key " + key; - throw runtime_error(strErr); + std::string strErr = "Cannot parse JSON for key " + key; + throw std::runtime_error(strErr); } registers[key] = val; } -static void RegisterSet(const string& strInput) +static void RegisterSet(const std::string& strInput) { // separate NAME:VALUE in string size_t pos = strInput.find(':'); - if ((pos == string::npos) || + if ((pos == std::string::npos) || (pos == 0) || (pos == (strInput.size() - 1))) - throw runtime_error("Register input requires NAME:VALUE"); + throw std::runtime_error("Register input requires NAME:VALUE"); - string key = strInput.substr(0, pos); - string valStr = strInput.substr(pos + 1, string::npos); + std::string key = strInput.substr(0, pos); + std::string valStr = strInput.substr(pos + 1, std::string::npos); RegisterSetJson(key, valStr); } -static void RegisterLoad(const string& strInput) +static void RegisterLoad(const std::string& strInput) { // separate NAME:FILENAME in string size_t pos = strInput.find(':'); - if ((pos == string::npos) || + if ((pos == std::string::npos) || (pos == 0) || (pos == (strInput.size() - 1))) - throw runtime_error("Register load requires NAME:FILENAME"); + throw std::runtime_error("Register load requires NAME:FILENAME"); - string key = strInput.substr(0, pos); - string filename = strInput.substr(pos + 1, string::npos); + std::string key = strInput.substr(0, pos); + std::string filename = strInput.substr(pos + 1, std::string::npos); FILE* f = fopen(filename.c_str(), "r"); if (!f) { - string strErr = "Cannot open file " + filename; - throw runtime_error(strErr); + std::string strErr = "Cannot open file " + filename; + throw std::runtime_error(strErr); } // load file chunks into one big buffer - string valStr; + std::string valStr; while ((!feof(f)) && (!ferror(f))) { char buf[4096]; int bread = fread(buf, 1, sizeof(buf), f); @@ -148,8 +146,8 @@ static void RegisterLoad(const string& strInput) } if (ferror(f)) { - string strErr = "Error reading file " + filename; - throw runtime_error(strErr); + std::string strErr = "Error reading file " + filename; + throw std::runtime_error(strErr); } fclose(f); @@ -158,74 +156,74 @@ static void RegisterLoad(const string& strInput) RegisterSetJson(key, valStr); } -static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal) +static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) { int64_t newVersion = atoi64(cmdVal); if (newVersion < 1 || newVersion > CTransaction::CURRENT_VERSION) - throw runtime_error("Invalid TX version requested"); + throw std::runtime_error("Invalid TX version requested"); tx.nVersion = (int)newVersion; } -static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal) +static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal) { int64_t newLocktime = atoi64(cmdVal); if (newLocktime < 0LL || newLocktime > 0xffffffffLL) - throw runtime_error("Invalid TX locktime requested"); + throw std::runtime_error("Invalid TX locktime requested"); tx.nLockTime = (unsigned int)newLocktime; } -static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) +static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput) { // separate TXID:VOUT in string size_t pos = strInput.find(':'); - if ((pos == string::npos) || + if ((pos == std::string::npos) || (pos == 0) || (pos == (strInput.size() - 1))) - throw runtime_error("TX input missing separator"); + throw std::runtime_error("TX input missing separator"); // extract and validate TXID - string strTxid = strInput.substr(0, pos); + std::string strTxid = strInput.substr(0, pos); if ((strTxid.size() != 64) || !IsHex(strTxid)) - throw runtime_error("invalid TX input txid"); + throw std::runtime_error("invalid TX input txid"); uint256 txid(strTxid); static const unsigned int minTxOutSz = 9; static const unsigned int maxVout = MAX_BLOCK_SIZE_LEGACY / minTxOutSz; // extract and validate vout - string strVout = strInput.substr(pos + 1, string::npos); + std::string strVout = strInput.substr(pos + 1, std::string::npos); int vout = atoi(strVout); if ((vout < 0) || (vout > (int)maxVout)) - throw runtime_error("invalid TX input vout"); + throw std::runtime_error("invalid TX input vout"); // append to transaction input list CTxIn txin(txid, vout); tx.vin.push_back(txin); } -static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput) +static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) { // separate VALUE:ADDRESS in string size_t pos = strInput.find(':'); - if ((pos == string::npos) || + if ((pos == std::string::npos) || (pos == 0) || (pos == (strInput.size() - 1))) - throw runtime_error("TX output missing separator"); + throw std::runtime_error("TX output missing separator"); // extract and validate VALUE - string strValue = strInput.substr(0, pos); + std::string strValue = strInput.substr(0, pos); CAmount value; if (!ParseMoney(strValue, value)) - throw runtime_error("invalid TX output value"); + throw std::runtime_error("invalid TX output value"); // extract and validate ADDRESS - string strAddr = strInput.substr(pos + 1, string::npos); + std::string strAddr = strInput.substr(pos + 1, std::string::npos); if (!IsValidDestinationString(strAddr)) - throw runtime_error("invalid TX output address"); + throw std::runtime_error("invalid TX output address"); // build standard output script via GetScriptForDestination() CScript scriptPubKey = GetScriptForDestination(DecodeDestination(strAddr)); @@ -235,22 +233,22 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput) tx.vout.push_back(txout); } -static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput) +static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) { // separate VALUE:SCRIPT in string size_t pos = strInput.find(':'); - if ((pos == string::npos) || + if ((pos == std::string::npos) || (pos == 0)) - throw runtime_error("TX output missing separator"); + throw std::runtime_error("TX output missing separator"); // extract and validate VALUE - string strValue = strInput.substr(0, pos); + std::string strValue = strInput.substr(0, pos); CAmount value; if (!ParseMoney(strValue, value)) - throw runtime_error("invalid TX output value"); + throw std::runtime_error("invalid TX output value"); // extract and validate script - string strScript = strInput.substr(pos + 1, string::npos); + std::string strScript = strInput.substr(pos + 1, std::string::npos); CScript scriptPubKey = ParseScript(strScript); // throws on err // construct TxOut, append to transaction output list @@ -258,26 +256,26 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput tx.vout.push_back(txout); } -static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx) +static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx) { // parse requested deletion index int inIdx = atoi(strInIdx); if (inIdx < 0 || inIdx >= (int)tx.vin.size()) { - string strErr = "Invalid TX input index '" + strInIdx + "'"; - throw runtime_error(strErr.c_str()); + std::string strErr = "Invalid TX input index '" + strInIdx + "'"; + throw std::runtime_error(strErr.c_str()); } // delete input from transaction tx.vin.erase(tx.vin.begin() + inIdx); } -static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx) +static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx) { // parse requested deletion index int outIdx = atoi(strOutIdx); if (outIdx < 0 || outIdx >= (int)tx.vout.size()) { - string strErr = "Invalid TX output index '" + strOutIdx + "'"; - throw runtime_error(strErr.c_str()); + std::string strErr = "Invalid TX output index '" + strOutIdx + "'"; + throw std::runtime_error(strErr.c_str()); } // delete output from transaction @@ -297,7 +295,7 @@ static const struct { {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE | SIGHASH_ANYONECANPAY}, }; -static bool findSighashFlags(int& flags, const string& flagStr) +static bool findSighashFlags(int& flags, const std::string& flagStr) { flags = 0; @@ -311,17 +309,17 @@ static bool findSighashFlags(int& flags, const string& flagStr) return false; } -uint256 ParseHashUO(map& o, string strKey) +uint256 ParseHashUO(std::map& o, std::string strKey) { if (!o.count(strKey)) return 0; return ParseHashUV(o[strKey], strKey); } -vector ParseHexUO(map& o, string strKey) +std::vector ParseHexUO(std::map& o, std::string strKey) { if (!o.count(strKey)) { - vector emptyVec; + std::vector emptyVec; return emptyVec; } return ParseHexUV(o[strKey], strKey); @@ -330,22 +328,22 @@ vector ParseHexUO(map& o, string strKey) static CAmount AmountFromValue(const UniValue& value) { if (!value.isNum() && !value.isStr()) - throw runtime_error("Amount is not a number or string"); + throw std::runtime_error("Amount is not a number or string"); CAmount amount; if (!ParseFixedPoint(value.getValStr(), 8, &amount)) - throw runtime_error("Invalid amount"); + throw std::runtime_error("Invalid amount"); return amount; } -static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) +static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) { int nHashType = SIGHASH_ALL; if (flagStr.size() > 0) if (!findSighashFlags(nHashType, flagStr)) - throw runtime_error("unknown sighash flag/sign option"); + throw std::runtime_error("unknown sighash flag/sign option"); - vector txVariants; + std::vector txVariants; txVariants.push_back(tx); // mergedTx will end up with all the signatures; it @@ -356,7 +354,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) CCoinsViewCache view(&viewDummy); if (!registers.count("privatekeys")) - throw runtime_error("privatekeys register variable must be set."); + throw std::runtime_error("privatekeys register variable must be set."); bool fGivenKeys = false; CBasicKeyStore tempKeystore; UniValue keysObj = registers["privatekeys"]; @@ -364,11 +362,11 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) - throw runtime_error("privatekey not a string"); + throw std::runtime_error("privatekey not a string"); CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(keysObj[kidx].getValStr()); if (!fGood) - throw runtime_error("privatekey not valid"); + throw std::runtime_error("privatekey not valid"); CKey key = vchSecret.GetKey(); tempKeystore.AddKey(key); @@ -376,34 +374,34 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) // Add previous txouts given in the RPC call: if (!registers.count("prevtxs")) - throw runtime_error("prevtxs register variable must be set."); + throw std::runtime_error("prevtxs register variable must be set."); UniValue prevtxsObj = registers["prevtxs"]; { for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) { UniValue prevOut = prevtxsObj[previdx]; if (!prevOut.isObject()) - throw runtime_error("expected prevtxs internal object"); + throw std::runtime_error("expected prevtxs internal object"); - map types = map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR); + std::map types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR); if (!prevOut.checkObject(types)) - throw runtime_error("prevtxs internal object typecheck fail"); + throw std::runtime_error("prevtxs internal object typecheck fail"); uint256 txid = ParseHashUV(prevOut["txid"], "txid"); int nOut = atoi(prevOut["vout"].getValStr()); if (nOut < 0) - throw runtime_error("vout must be positive"); + throw std::runtime_error("vout must be positive"); - vector pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); + std::vector pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); { CCoinsModifier coins = view.ModifyCoins(txid); if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { - string err("Previous output scriptPubKey mismatch:\n"); + std::string err("Previous output scriptPubKey mismatch:\n"); err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n" + scriptPubKey.ToString(); - throw runtime_error(err); + throw std::runtime_error(err); } if ((unsigned int)nOut >= coins->vout.size()) coins->vout.resize(nOut + 1); @@ -419,7 +417,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) && prevOut.exists("redeemScript")) { UniValue v = prevOut["redeemScript"]; - vector rsData(ParseHexUV(v, "redeemScript")); + std::vector rsData(ParseHexUV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); } @@ -447,7 +445,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); // ... and merge in other signatures: - BOOST_FOREACH(const CTransaction& txv, txVariants) + for (const CTransaction& txv : txVariants) sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i)); UpdateTransaction(mergedTx, i, sigdata); @@ -463,8 +461,22 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) tx = mergedTx; } -static void MutateTx(CMutableTransaction& tx, const string& command, const string& commandVal) +class Secp256k1Init { + ECCVerifyHandle globalVerifyHandle; + +public: + Secp256k1Init() { + ECC_Start(); + } + ~Secp256k1Init() { + ECC_Stop(); + } +}; + +static void MutateTx(CMutableTransaction& tx, const std::string& command, const std::string& commandVal) +{ + boost::scoped_ptr ecc; if (command == "nversion") MutateTxVersion(tx, commandVal); else if (command == "locktime") @@ -482,8 +494,10 @@ static void MutateTx(CMutableTransaction& tx, const string& command, const strin else if (command == "outscript") MutateTxAddOutScript(tx, commandVal); - else if (command == "sign") + else if (command == "sign"){ + if (!ecc) { ecc.reset(new Secp256k1Init()); } MutateTxSign(tx, commandVal); + } else if (command == "load") RegisterLoad(commandVal); @@ -492,7 +506,7 @@ static void MutateTx(CMutableTransaction& tx, const string& command, const strin RegisterSet(commandVal); else - throw runtime_error("unknown command"); + throw std::runtime_error("unknown command"); } static void OutputTxJSON(const CTransaction& tx) @@ -500,20 +514,20 @@ static void OutputTxJSON(const CTransaction& tx) UniValue entry(UniValue::VOBJ); TxToUniv(tx, 0, entry); - string jsonOutput = entry.write(4); + std::string jsonOutput = entry.write(4); fprintf(stdout, "%s\n", jsonOutput.c_str()); } static void OutputTxHash(const CTransaction& tx) { - string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id) + std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id) fprintf(stdout, "%s\n", strHexHash.c_str()); } static void OutputTxHex(const CTransaction& tx) { - string strHex = EncodeHexTx(tx, PROTOCOL_VERSION); + std::string strHex = EncodeHexTx(tx, PROTOCOL_VERSION); fprintf(stdout, "%s\n", strHex.c_str()); } @@ -528,10 +542,10 @@ static void OutputTx(const CTransaction& tx) OutputTxHex(tx); } -static string readStdin() +static std::string readStdin() { char buf[4096]; - string ret; + std::string ret; while (!feof(stdin)) { size_t bread = fread(buf, 1, sizeof(buf), stdin); @@ -541,7 +555,7 @@ static string readStdin() } if (ferror(stdin)) - throw runtime_error("error reading stdin"); + throw std::runtime_error("error reading stdin"); boost::algorithm::trim_right(ret); @@ -550,7 +564,7 @@ static string readStdin() static int CommandLineRawTx(int argc, char* argv[]) { - string strPrint; + std::string strPrint; int nRet = 0; try { // Skip switches; Permit common stdin convention "-" @@ -566,15 +580,15 @@ static int CommandLineRawTx(int argc, char* argv[]) if (!fCreateBlank) { // require at least one param if (argc < 2) - throw runtime_error("too few parameters"); + throw std::runtime_error("too few parameters"); // param: hex-encoded phore transaction - string strHexTx(argv[1]); + std::string strHexTx(argv[1]); if (strHexTx == "-") // "-" implies standard input strHexTx = readStdin(); if (!DecodeHexTx(txDecodeTmp, strHexTx, true)) - throw runtime_error("invalid transaction encoding"); + throw std::runtime_error("invalid transaction encoding"); startArg = 2; } else @@ -583,10 +597,10 @@ static int CommandLineRawTx(int argc, char* argv[]) CMutableTransaction tx(txDecodeTmp); for (int i = startArg; i < argc; i++) { - string arg = argv[i]; - string key, value; + std::string arg = argv[i]; + std::string key, value; size_t eqpos = arg.find('='); - if (eqpos == string::npos) + if (eqpos == std::string::npos) key = arg; else { key = arg.substr(0, eqpos); @@ -602,7 +616,7 @@ static int CommandLineRawTx(int argc, char* argv[]) catch (boost::thread_interrupted) { throw; } catch (std::exception& e) { - strPrint = string("error: ") + e.what(); + strPrint = std::string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { PrintExceptionContinue(NULL, "CommandLineRawTx()"); diff --git a/src/phored.cpp b/src/phored.cpp index c027ca65919c..31c7237c0a47 100644 --- a/src/phored.cpp +++ b/src/phored.cpp @@ -10,13 +10,12 @@ #include "init.h" #include "main.h" #include "noui.h" -#include "scheduler.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "ui_interface.h" #include "util.h" #include "httpserver.h" #include "httprpc.h" -#include "rpcserver.h" +#include "rpc/server.h" #include #include @@ -42,7 +41,7 @@ static bool fDaemon; -void WaitForShutdown(boost::thread_group* threadGroup) +void WaitForShutdown() { bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. @@ -50,10 +49,7 @@ void WaitForShutdown(boost::thread_group* threadGroup) MilliSleep(200); fShutdown = ShutdownRequested(); } - if (threadGroup) { - Interrupt(*threadGroup); - threadGroup->join_all(); - } + Interrupt(); } ////////////////////////////////////////////////////////////////////////////// @@ -62,9 +58,6 @@ void WaitForShutdown(boost::thread_group* threadGroup) // bool AppInit(int argc, char* argv[]) { - boost::thread_group threadGroup; - CScheduler scheduler; - bool fRet = false; // @@ -140,9 +133,9 @@ bool AppInit(int argc, char* argv[]) } #endif SoftSetBoolArg("-server", true); - + std::vector words; - fRet = AppInit2(threadGroup, scheduler, words); + fRet = AppInit2(words); } catch (std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); } catch (...) { @@ -150,12 +143,9 @@ bool AppInit(int argc, char* argv[]) } if (!fRet) { - Interrupt(threadGroup); - // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of - // the startup-failure cases to make sure they don't result in a hang due to some - // thread-blocking-waiting-for-another-thread-during-startup case + Interrupt(); } else { - WaitForShutdown(&threadGroup); + WaitForShutdown(); } Shutdown(); diff --git a/src/primitives/block.h b/src/primitives/block.h index c53833dcfa69..4193344adb99 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -113,8 +113,8 @@ class CBlock : public CBlockHeader inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(*(CBlockHeader*)this); READWRITE(vtx); - if(vtx.size() > 1 && vtx[1].IsCoinStake()) - READWRITE(vchBlockSig); + if(vtx.size() > 1 && vtx[1].IsCoinStake()) + READWRITE(vchBlockSig); } void SetNull() diff --git a/src/primitives/deterministicmint.cpp b/src/primitives/deterministicmint.cpp index 208944f0f2e9..ffc4e643e6b6 100644 --- a/src/primitives/deterministicmint.cpp +++ b/src/primitives/deterministicmint.cpp @@ -6,8 +6,6 @@ #include "libzerocoin/Coin.h" #include "deterministicmint.h" -using namespace libzerocoin; - CDeterministicMint::CDeterministicMint() { SetNull(); @@ -26,7 +24,7 @@ CDeterministicMint::CDeterministicMint(uint8_t nVersion, const uint32_t& nCount, void CDeterministicMint::SetNull() { - nVersion = PrivateCoin::CURRENT_VERSION; + nVersion = libzerocoin::PrivateCoin::CURRENT_VERSION; nCount = 0; hashSeed = 0; hashSerial = 0; @@ -34,7 +32,7 @@ void CDeterministicMint::SetNull() hashPubcoin = 0; txid = 0; nHeight = 0; - denom = CoinDenomination::ZQ_ERROR; + denom = libzerocoin::CoinDenomination::ZQ_ERROR; isUsed = false; } diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 27dde412f2d9..93154c484c1c 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -14,7 +14,7 @@ #include "utilstrencodings.h" #include "transaction.h" -#include + extern bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index da727182801f..0106555e4b54 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -491,8 +491,6 @@ class CTransaction } std::string ToString() const; - - bool GetCoinAge(uint64_t& nCoinAge) const; // ppcoin: get transaction coin age void UpdateHash() const; }; @@ -522,17 +520,6 @@ struct CMutableTransaction uint256 GetHash() const; std::string ToString() const; - - friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b) - { - return a.GetHash() == b.GetHash(); - } - - friend bool operator!=(const CMutableTransaction& a, const CMutableTransaction& b) - { - return !(a == b); - } - }; /** Compute the cost of a transaction, as defined by BIP 141 */ diff --git a/src/protocol.cpp b/src/protocol.cpp index 49f8c30e214f..352b01700708 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -214,7 +214,6 @@ void CAddress::Init() { nServices = NODE_NETWORK; nTime = 100000000; - nLastTry = 0; } CInv::CInv() @@ -255,7 +254,7 @@ bool CInv::IsKnownType() const } bool CInv::IsMasterNodeType() const{ - return (type >= 6); + return (type >= 6); } const char* CInv::GetCommand() const diff --git a/src/protocol.h b/src/protocol.h index 7e4e7a9176f1..ad530bfdb22b 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -315,10 +315,10 @@ enum { // witness data. NODE_WITNESS = (1 << 3), - // NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference - // that the node doens't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here ) + // NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference + // that the node doens't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here ) - NODE_BLOOM_WITHOUT_MN = (1 << 4), + NODE_BLOOM_WITHOUT_MN = (1 << 4), // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the @@ -360,9 +360,6 @@ class CAddress : public CService // disk and network only unsigned int nTime; - - // memory only - int64_t nLastTry; }; /** inv message data */ diff --git a/src/pubkey.cpp b/src/pubkey.cpp index f71ab1bdcc82..569032cc7ba2 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -4,50 +4,203 @@ #include "pubkey.h" -#include "eccryptoverify.h" - -#ifdef USE_SECP256K1 #include -#else -#include "ecwrapper.h" -#endif +#include + +namespace +{ +/* Global secp256k1_context object used for verification. */ +secp256k1_context* secp256k1_context_verify = nullptr; +} // namespace + +/** This function is taken from the libsecp256k1 distribution and implements + * DER parsing for ECDSA signatures, while supporting an arbitrary subset of + * format violations. + * + * Supported violations include negative integers, excessive padding, garbage + * at the end, and overly long length descriptors. This is safe to use in + * Bitcoin because since the activation of BIP66, signatures are verified to be + * strict DER before being passed to this module, and we know it supports all + * violations present in the blockchain before that point. + */ +static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (lenbyte > inputlen - pos) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (lenbyte > inputlen - pos) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + static_assert(sizeof(size_t) >= 4, "size_t too small"); + if (lenbyte >= 4) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (lenbyte > inputlen - pos) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + static_assert(sizeof(size_t) >= 4, "size_t too small"); + if (lenbyte >= 4) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + /* Overwrite the result again with a correctly-parsed but invalid + signature if parsing failed. */ + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} bool CPubKey::Verify(const uint256& hash, const std::vector& vchSig) const { if (!IsValid()) return false; -#ifdef USE_SECP256K1 - if (secp256k1_ecdsa_verify((const unsigned char*)&hash, 32, &vchSig[0], vchSig.size(), begin(), size()) != 1) - return false; -#else - CECKey key; - if (!key.SetPubKey(begin(), size())) + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; - if (!key.Verify(hash, vchSig)) + } + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) { return false; -#endif - return true; + } + /* libsecp256k1's ECDSA verification requires lower-S signatures, which have + * not historically been enforced in Bitcoin, so normalize them first. */ + secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig); + return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); } bool CPubKey::RecoverCompact(const uint256& hash, const std::vector& vchSig) { - if (vchSig.size() != 65) + if (vchSig.size() != COMPACT_SIGNATURE_SIZE) return false; int recid = (vchSig[0] - 27) & 3; bool fComp = ((vchSig[0] - 27) & 4) != 0; -#ifdef USE_SECP256K1 - int pubkeylen = 65; - if (!secp256k1_ecdsa_recover_compact((const unsigned char*)&hash, 32, &vchSig[1], (unsigned char*)begin(), &pubkeylen, fComp, recid)) + secp256k1_pubkey pubkey; + secp256k1_ecdsa_recoverable_signature sig; + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) { return false; - assert((int)size() == pubkeylen); -#else - CECKey key; - if (!key.Recover(hash, &vchSig[1], recid)) + } + if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) { return false; - std::vector pubkey; - key.GetPubKey(pubkey, fComp); - Set(pubkey.begin(), pubkey.end()); -#endif + } + unsigned char pub[PUBLIC_KEY_SIZE]; + size_t publen = PUBLIC_KEY_SIZE; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } @@ -55,86 +208,102 @@ bool CPubKey::IsFullyValid() const { if (!IsValid()) return false; -#ifdef USE_SECP256K1 - if (!secp256k1_ecdsa_pubkey_verify(begin(), size())) - return false; -#else - CECKey key; - if (!key.SetPubKey(begin(), size())) - return false; -#endif - return true; + secp256k1_pubkey pubkey; + return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size()); } bool CPubKey::Decompress() { if (!IsValid()) return false; -#ifdef USE_SECP256K1 - int clen = size(); - int ret = secp256k1_ecdsa_pubkey_decompress((unsigned char*)begin(), &clen); - assert(ret); - assert(clen == (int)size()); -#else - CECKey key; - if (!key.SetPubKey(begin(), size())) + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; - std::vector pubkey; - key.GetPubKey(pubkey, false); - Set(pubkey.begin(), pubkey.end()); -#endif + } + unsigned char pub[PUBLIC_KEY_SIZE]; + size_t publen = PUBLIC_KEY_SIZE; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } -bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const +bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const { assert(IsValid()); assert((nChild >> 31) == 0); - assert(begin() + 33 == end()); + assert(size() == COMPRESSED_PUBLIC_KEY_SIZE); unsigned char out[64]; - BIP32Hash(cc, nChild, *begin(), begin() + 1, out); - memcpy(ccChild, out + 32, 32); -#ifdef USE_SECP256K1 - pubkeyChild = *this; - bool ret = secp256k1_ecdsa_pubkey_tweak_add((unsigned char*)pubkeyChild.begin(), pubkeyChild.size(), out); -#else - CECKey key; - bool ret = key.SetPubKey(begin(), size()); - ret &= key.TweakPublic(out); - std::vector pubkey; - key.GetPubKey(pubkey, true); - pubkeyChild.Set(pubkey.begin(), pubkey.end()); -#endif - return ret; + BIP32Hash(cc, nChild, *begin(), begin()+1, out); + memcpy(ccChild.begin(), out+32, 32); + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { + return false; + } + if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) { + return false; + } + unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE]; + size_t publen = COMPRESSED_PUBLIC_KEY_SIZE; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); + pubkeyChild.Set(pub, pub + publen); +return true; } void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; - memcpy(code + 1, vchFingerprint, 4); - code[5] = (nChild >> 24) & 0xFF; - code[6] = (nChild >> 16) & 0xFF; - code[7] = (nChild >> 8) & 0xFF; - code[8] = (nChild >> 0) & 0xFF; - memcpy(code + 9, vchChainCode, 32); - assert(pubkey.size() == 33); - memcpy(code + 41, pubkey.begin(), 33); + memcpy(code+1, vchFingerprint, 4); + code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; + code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; + memcpy(code+9, chaincode.begin(), 32); + assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); + memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); } void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; - memcpy(vchFingerprint, code + 1, 4); + memcpy(vchFingerprint, code+1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; - memcpy(vchChainCode, code + 9, 32); - pubkey.Set(code + 41, code + 74); + memcpy(chaincode.begin(), code+9, 32); + pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE); } -bool CExtPubKey::Derive(CExtPubKey& out, unsigned int nChild) const +bool CExtPubKey::Derive(CExtPubKey& out, unsigned int _nChild) const { out.nDepth = nDepth + 1; CKeyID id = pubkey.GetID(); memcpy(&out.vchFingerprint[0], &id, 4); - out.nChild = nChild; - return pubkey.Derive(out.pubkey, out.vchChainCode, nChild, vchChainCode); + out.nChild = _nChild; + return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode); } + +/* static */ bool CPubKey::CheckLowS(const std::vector& vchSig) { + secp256k1_ecdsa_signature sig; + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) { + return false; + } + return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, nullptr, &sig)); +} + +/* static */ int ECCVerifyHandle::refcount = 0; + +ECCVerifyHandle::ECCVerifyHandle() +{ + if (refcount == 0) { + assert(secp256k1_context_verify == nullptr); + secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + assert(secp256k1_context_verify != nullptr); + } + refcount++; +} + +ECCVerifyHandle::~ECCVerifyHandle() +{ + refcount--; + if (refcount == 0) { + assert(secp256k1_context_verify != nullptr); + secp256k1_context_destroy(secp256k1_context_verify); + secp256k1_context_verify = nullptr; + } +} \ No newline at end of file diff --git a/src/pubkey.h b/src/pubkey.h index 702a1c3b8133..f75c3b54baea 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_PUBKEY_H -#define BITCOIN_PUBKEY_H +#ifndef PHORE_PUBKEY_H +#define PHORE_PUBKEY_H #include "hash.h" #include "serialize.h" @@ -13,43 +13,51 @@ #include #include -/** - * secp256k1: - * const unsigned int PRIVATE_KEY_SIZE = 279; - * const unsigned int PUBLIC_KEY_SIZE = 65; - * const unsigned int SIGNATURE_SIZE = 72; - * - * see www.keylength.com - * script supports up to 75 for single byte push - */ - const unsigned int BIP32_EXTKEY_SIZE = 74; /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { public: - CKeyID() : uint160(0) {} - CKeyID(const uint160& in) : uint160(in) {} + CKeyID() : uint160() {} + explicit CKeyID(const uint160& in) : uint160(in) {} }; +typedef uint256 ChainCode; + /** An encapsulated public key. */ class CPubKey { +public: + /** + * secp256k1: + */ + static const unsigned int PUBLIC_KEY_SIZE = 65; + static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; + static const unsigned int SIGNATURE_SIZE = 72; + static const unsigned int COMPACT_SIGNATURE_SIZE = 65; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, + "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); + private: /** * Just store the serialized data. * Its length can very cheaply be computed from the first byte. */ - unsigned char vch[65]; + unsigned char vch[PUBLIC_KEY_SIZE]; //! Compute the length of a pubkey with a given first byte. unsigned int static GetLen(unsigned char chHeader) { if (chHeader == 2 || chHeader == 3) - return 33; + return COMPRESSED_PUBLIC_KEY_SIZE; if (chHeader == 4 || chHeader == 6 || chHeader == 7) - return 65; + return PUBLIC_KEY_SIZE; return 0; } @@ -89,9 +97,9 @@ class CPubKey } //! Construct a public key from a byte vector. - CPubKey(const std::vector& vch) + explicit CPubKey(const std::vector& _vch) { - Set(vch.begin(), vch.end()); + Set(_vch.begin(), _vch.end()); } //! Simple read-only vector-like interface to the pubkey data. @@ -132,7 +140,7 @@ class CPubKey void Unserialize(Stream& s, int nType, int nVersion) { unsigned int len = ::ReadCompactSize(s); - if (len <= 65) { + if (len <= PUBLIC_KEY_SIZE) { s.read((char*)vch, len); } else { // invalid pubkey, skip available data @@ -171,7 +179,7 @@ class CPubKey //! Check whether this is a compressed public key. bool IsCompressed() const { - return size() == 33; + return size() == COMPRESSED_PUBLIC_KEY_SIZE; } /** @@ -180,6 +188,11 @@ class CPubKey */ bool Verify(const uint256& hash, const std::vector& vchSig) const; + /** + * Check whether a signature is normalized (lower-S). + */ + static bool CheckLowS(const std::vector& vchSig); + //! Recover a public key from a compact signature. bool RecoverCompact(const uint256& hash, const std::vector& vchSig); @@ -187,7 +200,7 @@ class CPubKey bool Decompress(); //! Derive BIP32 child pubkey. - bool Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const; + bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; std::vector Raw() const { @@ -205,17 +218,20 @@ struct CExtPubKey { unsigned char nDepth; unsigned char vchFingerprint[4]; unsigned int nChild; - unsigned char vchChainCode[32]; + ChainCode chaincode; CPubKey pubkey; friend bool operator==(const CExtPubKey& a, const CExtPubKey& b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - memcmp(&a.vchChainCode[0], &b.vchChainCode[0], 32) == 0 && a.pubkey == b.pubkey; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.pubkey == b.pubkey; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey& out, unsigned int nChild) const; unsigned int GetSerializeSize(int nType, int nVersion) const { @@ -240,6 +256,41 @@ struct CExtPubKey { s.read((char *)&code[0], len); Decode(code); } + void Serialize(CSizeComputer& s) const + { + // Optimized implementation for ::GetSerializeSize that avoids copying. + s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int) + } + template + void Serialize(Stream& s) const + { + unsigned int len = BIP32_EXTKEY_SIZE; + ::WriteCompactSize(s, len); + unsigned char code[BIP32_EXTKEY_SIZE]; + Encode(code); + s.write((const char *)&code[0], len); + } + template + void Unserialize(Stream& s) + { + unsigned int len = ::ReadCompactSize(s); + unsigned char code[BIP32_EXTKEY_SIZE]; + if (len != BIP32_EXTKEY_SIZE) + throw std::runtime_error("Invalid extended key size\n"); + s.read((char *)&code[0], len); + Decode(code); + } +}; + +/** Users of this module must hold an ECCVerifyHandle. The constructor and + * destructor of these are not allowed to run in parallel, though. */ +class ECCVerifyHandle +{ + static int refcount; + +public: + ECCVerifyHandle(); + ~ECCVerifyHandle(); }; -#endif // BITCOIN_PUBKEY_H \ No newline at end of file +#endif // PHORE_PUBKEY_H \ No newline at end of file diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt new file mode 100644 index 000000000000..71979b725f00 --- /dev/null +++ b/src/qt/CMakeLists.txt @@ -0,0 +1,199 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.10) + +set(CMAKE_INCLUDE_CURRENT_DIR OFF) +set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/forms) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif () + +find_package(Qrcode) +if (QRCODE_FOUND) + include_directories ( ${QRCODE_INCLUDE_DIR} ) + link_directories ( ${QRCODE_LIBRARY_DIRS} ) +endif() + +if($ENV{target} MATCHES "Windows") + find_package(Qt5) +else() + unset(Qt5Enables) + foreach(comp Widgets Core Gui Network LinguistTools DBus) + find_package(Qt5${comp}) + set(Qt5Enables "${Qt5Enables};Qt5${comp}_FOUND") + if(Qt5${comp}_FOUND) + MESSAGE(STATUS "FOUND QT5${comp}") + include_directories(${include_directories} ${Qt5${comp}_INCLUDE_DIRS} ${QT_USE_FILE}) + add_definitions(${Qt5${comp}_DEFINITIONS}) + list(APPEND Qt5_LIBRARIES ${Qt5${comp}_LIBRARIES}) + else() + MESSAGE(WARNING "Cant find Qt5${comp}") + endif() + endforeach(comp) + + find_package(Qt5DBus) + if (Qt5DBus_FOUND) + include_directories(${include_directories} "/usr/local/opt/qt5/include/QtDBus/") + add_compile_options("-DUSE_DBUS") + endif() +endif() + +# Why isn't this done automatically?? +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_AUTOMOC_MOC_OPTIONS "-DQ_OS_MAC") +endif() + +file(GLOB LOCAL_QT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) +source_group("QtHeaders" FILES ${LOCAL_QT_HEADERS}) + +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/paymentrequest.proto) + +set(GUI_FORMS + ${CMAKE_CURRENT_SOURCE_DIR}/forms/addressbookpage.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/askpassphrasedialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/bip38tooldialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/coincontroldialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/governancepage.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/zpivcontroldialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/blockexplorer.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/editaddressdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/helpmessagedialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/intro.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/masternodelist.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/multisenddialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/obfuscationconfig.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/privacydialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/openuridialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/optionsdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/overviewpage.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/receivecoinsdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/receiverequestdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/rpcconsole.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/sendcoinsdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/sendcoinsentry.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/signverifymessagedialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/transactiondescdialog.ui + ) + +SET(QT_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/multisenddialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bantablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bip38tooldialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/blockexplorer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinaddressvalidator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinamountfield.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoingui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinunits.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/clientmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/csvmodelwriter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/governancepage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/guiutil.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/intro.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/multisigdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/masternodelist.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/networkstyle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/notificator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/optionsdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/optionsmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/peertablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/platformstyle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qvalidatedlineedit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qvaluecombobox.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpcconsole.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/splashscreen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/trafficgraphwidget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utilitydialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/addressbookpage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/addresstablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/askpassphrasedialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/coincontroldialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/zpivcontroldialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/coincontroltreewidget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/privacydialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/proposalframe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/editaddressdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/masternodelist.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/openuridialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/overviewpage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/paymentrequestplus.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/paymentserver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/receivecoinsdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/receiverequestdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/recentrequeststablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sendcoinsdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sendcoinsentry.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/signverifymessagedialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactiondesc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactiondescdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactionfilterproxy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactionrecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactiontablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactionview.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletframe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletmodeltransaction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletview.cpp + ) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + list(APPEND QT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/macdockiconhandler.mm) + list(APPEND QT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/macnotificationhandler.mm) +endif() + +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + list(APPEND QT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/winshutdownmonitor.cpp) +endif () + +add_library(qt_stuff STATIC ${BitcoinHeaders} ${QtHeaders} ${QT_SOURCES} ${PROTO_SRCS} ${PROTO_HDRS}) +target_include_directories(qt_stuff PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +set_property(TARGET qt_stuff PROPERTY CXX_STANDARD 11) + +file(GLOB QT_TRANSLATIONS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/locale/*.ts) + +get_filename_component(QM_FILES_BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/locale" ABSOLUTE) +set_source_files_properties(${QT_TRANSLATIONS_FILES} PROPERTIES OUTPUT_LOCATION "${QM_FILES_BINARY_DIR}") + +QT5_ADD_TRANSLATION(QM ${QT_TRANSLATIONS_FILES}) +add_custom_target(translations_target ALL DEPENDS ${QM}) + +QT5_ADD_RESOURCES(QRC_RESOURCE pivx.qrc) +QT5_ADD_RESOURCES(QRC_LOCALE_RESOURCE pivx_locale.qrc) + +add_executable(pivx-qt pivx.cpp ${QM} ${QRC_RESOURCE} ${QRC_LOCALE_RESOURCE}) +add_dependencies(pivx-qt translations_target libunivalue libsecp256k1 leveldb leveldb_sse42 memenv) +target_link_libraries(pivx-qt + qt_stuff + univalue + SERVER_A UTIL_A WALLET_A CLI_A COMMON_A BITCOIN_CRYPTO_A ZEROCOIN_A + leveldb leveldb_sse42 memenv miniupnpc secp256k1 + ${BerkeleyDB_LIBRARIES} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${PROTOBUF_LIBRARIES} ${LIBEVENT_LIB} + pthread + ) +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + target_link_libraries(pivx-qt "-framework Cocoa") +endif() +if(GMP_FOUND) + target_link_libraries(pivx-qt ${GMP_LIBRARY}) +endif() +if(ZMQ_FOUND) + target_link_libraries(pivx-qt ZMQ_A ${ZMQ_LIB}) +endif() +if (QRCODE_FOUND) + target_link_libraries(pivx-qt ${QRCODE_LIB}) +endif() + +QT5_USE_Modules(pivx-qt Gui) +QT5_USE_Modules(pivx-qt Core) +QT5_USE_Modules(pivx-qt Widgets) +QT5_USE_Modules(pivx-qt Test) +QT5_USE_Modules(pivx-qt PrintSupport) +QT5_USE_Modules(pivx-qt Network) +if (Qt5DBus_FOUND) + QT5_USE_Modules(pivx-qt DBus) +endif() diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 7bbd91d8df2c..dcd042b4a616 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -23,7 +23,7 @@ #include #include -AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget* parent) : QDialog(parent), +AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::AddressBookPage), model(0), mode(mode), @@ -133,14 +133,9 @@ void AddressBookPage::setModel(AddressTableModel* model) ui->tableView->setModel(proxyModel); ui->tableView->sortByColumn(0, Qt::AscendingOrder); -// Set column widths -#if QT_VERSION < 0x050000 - ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch); - ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); -#else + // Set column widths ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); -#endif connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged())); diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 1514e9892d89..4f784159025f 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -81,7 +81,7 @@ class AddressTablePriv cachedAddressTable.clear(); { LOCK(wallet->cs_wallet); - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, wallet->mapAddressBook) { + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : wallet->mapAddressBook) { const CTxDestination& address = item.first; const CScript redeemDestination = GetScriptForDestination(address); bool fMine = IsMine(*wallet, redeemDestination); diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 2fc912891d0b..0e38fa87f977 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -17,7 +17,7 @@ #include #include -AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model) : QDialog(parent), +AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::AskPassphraseDialog), mode(mode), model(model), diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 7707ce7b6beb..67ea7dc31513 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -51,9 +51,7 @@ class BanTablePriv CNode::GetBanned(banMap); cachedBanlist.clear(); -#if QT_VERSION >= 0x040700 cachedBanlist.reserve(banMap.size()); -#endif for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) { CCombinedBan banEntry; diff --git a/src/qt/bip38tooldialog.cpp b/src/qt/bip38tooldialog.cpp index 6fbc2e53e54b..7b28ad39f9ec 100644 --- a/src/qt/bip38tooldialog.cpp +++ b/src/qt/bip38tooldialog.cpp @@ -21,15 +21,13 @@ #include -Bip38ToolDialog::Bip38ToolDialog(QWidget* parent) : QDialog(parent), +Bip38ToolDialog::Bip38ToolDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::Bip38ToolDialog), model(0) { ui->setupUi(this); -#if QT_VERSION >= 0x040700 ui->decryptedKeyOut_DEC->setPlaceholderText(tr("Click \"Decrypt Key\" to compute key")); -#endif GUIUtil::setupAddressWidget(ui->addressIn_ENC, this); ui->addressIn_ENC->installEventFilter(this); @@ -187,8 +185,8 @@ void Bip38ToolDialog::on_pasteButton_DEC_clicked() void Bip38ToolDialog::on_decryptKeyButton_DEC_clicked() { - string strPassphrase = ui->passphraseIn_DEC->text().toStdString(); - string strKey = ui->encryptedKeyIn_DEC->text().toStdString(); + std::string strPassphrase = ui->passphraseIn_DEC->text().toStdString(); + std::string strKey = ui->encryptedKeyIn_DEC->text().toStdString(); uint256 privKey; bool fCompressed; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index cc812374fe19..ea41b94bd4d9 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -56,14 +56,8 @@ #include #include #include -#include - -#if QT_VERSION < 0x050000 -#include -#include -#else #include -#endif +#include const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; @@ -74,6 +68,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai labelStakingIcon(0), labelEncryptionIcon(0), labelWalletHDStatusIcon(0), + labelTorIcon(0), labelConnectionsIcon(0), labelBlocksIcon(0), progressBarLabel(0), @@ -119,7 +114,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai QFontDatabase::addApplicationFont(":/fonts/Hind-SemiBold"); QFontDatabase::addApplicationFont(":/fonts/Hind-Regular"); QFontDatabase::addApplicationFont(":/fonts/Hind-Light"); - QFontDatabase::addApplicationFont(":/fonts/Montserrat-Bold"); + QFontDatabase::addApplicationFont(":/fonts/Montserrat-Bold"); /* Open CSS when configured */ this->setStyleSheet(GUIUtil::loadStyleSheet()); @@ -148,12 +143,6 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai #endif setWindowTitle(windowTitle); -#if defined(Q_OS_MAC) && QT_VERSION < 0x050000 - // This property is not implemented in Qt 5. Setting it has no effect. - // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras. - setUnifiedTitleAndToolBarOnMac(true); -#endif - rpcConsole = new RPCConsole(enableWallet ? this : 0); #ifdef ENABLE_WALLET if (enableWallet) { @@ -203,6 +192,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai labelEncryptionIcon->setFlat(true); // Make the button look like a label, but clickable labelEncryptionIcon->setStyleSheet(".QPushButton { background-color: rgba(255, 255, 255, 0);}"); labelEncryptionIcon->setMaximumSize(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE); + labelTorIcon = new QLabel(); labelConnectionsIcon = new QPushButton(); labelConnectionsIcon->setObjectName("labelConnectionsIcon"); labelConnectionsIcon->setFlat(true); // Make the button look like a label, but clickable @@ -210,15 +200,18 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai labelConnectionsIcon->setMaximumSize(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE); labelBlocksIcon = new QLabel(); +#ifdef ENABLE_WALLET if (enableWallet) { frameBlocksLayout->addStretch(); frameBlocksLayout->addWidget(unitDisplayControl); frameBlocksLayout->addStretch(); frameBlocksLayout->addWidget(labelEncryptionIcon); frameBlocksLayout->addWidget(labelWalletHDStatusIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelStakingIcon); } - frameBlocksLayout->addStretch(); - frameBlocksLayout->addWidget(labelStakingIcon); +#endif // ENABLE_WALLET + frameBlocksLayout->addWidget(labelTorIcon); frameBlocksLayout->addStretch(); frameBlocksLayout->addWidget(labelConnectionsIcon); frameBlocksLayout->addStretch(); @@ -235,7 +228,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai // Override style sheet for progress bar for styles that have a segmented progress bar, // as they make the text unreadable (workaround for issue #1071) - // See https://qt-project.org/doc/qt-4.8/gallery.html + // See https://doc.qt.io/qt-5/gallery.html QString curStyle = QApplication::style()->metaObject()->className(); if (curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle") { progressBar->setStyleSheet("QProgressBar { background-color: #F8F8F8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #00CCFF, stop: 1 #33CCFF); border-radius: 7px; margin: 0px; }"); @@ -438,11 +431,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) aboutAction = new QAction(networkStyle->getAppIcon(), tr("&About Phore Core"), this); aboutAction->setStatusTip(tr("Show information about Phore Core")); aboutAction->setMenuRole(QAction::AboutRole); -#if QT_VERSION < 0x050000 - aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); -#else aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); -#endif aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); @@ -672,6 +661,9 @@ void BitcoinGUI::setClientModel(ClientModel* clientModel) connect(clientModel, SIGNAL(showProgress(QString, int)), this, SLOT(showProgress(QString, int))); rpcConsole->setClientModel(clientModel); + + updateTorIcon(); + #ifdef ENABLE_WALLET if (walletFrame) { walletFrame->setClientModel(clientModel); @@ -1231,17 +1223,22 @@ bool BitcoinGUI::eventFilter(QObject* object, QEvent* event) #ifdef ENABLE_WALLET void BitcoinGUI::setStakingStatus() { - if (pwalletMain) - fMultiSend = pwalletMain->isMultiSendEnabled(); - - if (nLastCoinStakeSearchInterval) { - labelStakingIcon->show(); - labelStakingIcon->setPixmap(QIcon(":/icons/staking_active").pixmap(QSize(16,16))); - labelStakingIcon->setToolTip(tr("Staking is active\n MultiSend: %1").arg(fMultiSend ? tr("Active") : tr("Not Active"))); - } else { - labelStakingIcon->show(); - labelStakingIcon->setPixmap(QIcon(":/icons/staking_inactive").pixmap(QSize(16,16))); - labelStakingIcon->setToolTip(tr("Staking is not active\n MultiSend: %1").arg(fMultiSend ? tr("Active") : tr("Not Active"))); + if (walletFrame) { + if (pwalletMain) + fMultiSend = pwalletMain->isMultiSendEnabled(); + + if (nLastCoinStakeSearchInterval) { + labelStakingIcon->show(); + labelStakingIcon->setPixmap(QIcon(":/icons/staking_active").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelStakingIcon->setToolTip( + tr("Staking is active\n MultiSend: %1").arg(fMultiSend ? tr("Active") : tr("Not Active"))); + } else { + labelStakingIcon->show(); + labelStakingIcon->setPixmap( + QIcon(":/icons/staking_inactive").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelStakingIcon->setToolTip( + tr("Staking is not active\n MultiSend: %1").arg(fMultiSend ? tr("Active") : tr("Not Active"))); + } } } @@ -1309,6 +1306,24 @@ void BitcoinGUI::setEncryptionStatus(int status) } #endif // ENABLE_WALLET +void BitcoinGUI::updateTorIcon() +{ + std::string ip_port; + bool tor_enabled = clientModel->getTorInfo(ip_port); + + if (tor_enabled) { + if (labelTorIcon->pixmap() == 0) { + QString ip_port_q = QString::fromStdString(ip_port); + labelTorIcon->setPixmap(QIcon(":/icons/onion").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelTorIcon->setToolTip(tr("Tor is enabled: %1").arg(ip_port_q)); + } else { + labelTorIcon->show(); + } + } else { + labelTorIcon->hide(); + } +} + void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) { if (!clientModel) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index d5545ffda3df..905ba18d5d4d 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -87,6 +87,7 @@ class BitcoinGUI : public QMainWindow QLabel* labelStakingIcon; QPushButton* labelEncryptionIcon; QLabel *labelWalletHDStatusIcon; + QLabel* labelTorIcon; QPushButton* labelConnectionsIcon; QLabel* labelBlocksIcon; QLabel* progressBarLabel; @@ -203,6 +204,10 @@ public slots: void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address); #endif // ENABLE_WALLET +private: + /** Set the Tor-enabled icon as shown in the UI. */ + void updateTorIcon(); + private slots: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index f2665b14a69c..73e27c7053ad 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -400,7 +400,7 @@ std::string AddressToString(const CTxDestination& dest) { std::vector Txs; paddressmap->GetTxs(Txs, AddressScript.GetID()); - BOOST_FOREACH (const CDiskTxPos& pos, Txs) + for (const CDiskTxPos& pos : Txs) { CTransaction tx; CBlock block; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 38ec60cffe3f..d5cb6441d322 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -8,6 +8,7 @@ #include "bantablemodel.h" #include "guiconstants.h" +#include "guiutil.h" #include "peertablemodel.h" #include "alert.h" @@ -18,6 +19,7 @@ #include "masternode-sync.h" #include "masternodeman.h" #include "net.h" +#include "netbase.h" #include "ui_interface.h" #include "util.h" @@ -64,7 +66,7 @@ int ClientModel::getNumConnections(unsigned int flags) const return vNodes.size(); int nNum = 0; - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) nNum++; @@ -111,6 +113,15 @@ QDateTime ClientModel::getLastBlockDate() const return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network } +QString ClientModel::getLastBlockHash() const +{ + LOCK(cs_main); + if (chainActive.Tip()) + return QString::fromStdString(chainActive.Tip()->GetBlockHash().ToString()); + else + return QString::fromStdString(Params().GenesisBlock().GetHash().ToString()); // Genesis block's hash of current network +} + double ClientModel::getVerificationProgress() const { LOCK(cs_main); @@ -247,6 +258,11 @@ QString ClientModel::formatClientStartupTime() const return QDateTime::fromTime_t(nClientStartupTime).toString(); } +QString ClientModel::dataDir() const +{ + return GUIUtil::boostPathToQString(GetDataDir()); +} + void ClientModel::updateBanlist() { banTableModel->refresh(); @@ -299,3 +315,21 @@ void ClientModel::unsubscribeFromCoreSignals() uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); } + +bool ClientModel::getTorInfo(std::string& ip_port) const +{ + proxyType onion; + if (GetProxy((Network) 3, onion) && IsReachable((Network) 3)) { + { + LOCK(cs_mapLocalHost); + for (const std::pair &item : mapLocalHost) { + if (item.first.IsTor()) { + CService addrOnion = CService(item.first.ToString(), item.second.nPort); + ip_port = addrOnion.ToStringIPPort(); + return true; + } + } + } + } + return false; +} \ No newline at end of file diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 0e2cb67bdf4e..5988f3a07249 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -8,6 +8,7 @@ #ifndef BITCOIN_QT_CLIENTMODEL_H #define BITCOIN_QT_CLIENTMODEL_H +#include "uint256.h" #include #include @@ -63,6 +64,8 @@ class ClientModel : public QObject double getVerificationProgress() const; QDateTime getLastBlockDate() const; + QString getLastBlockHash() const; + //! Return true if core is doing initial block download bool inInitialBlockDownload() const; //! Return true if core is importing blocks @@ -75,6 +78,9 @@ class ClientModel : public QObject bool isReleaseVersion() const; QString clientName() const; QString formatClientStartupTime() const; + QString dataDir() const; + + bool getTorInfo(std::string& ip_port) const; private: OptionsModel* optionsModel; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 0d72a37f52ee..6cdc5260098f 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -33,12 +33,11 @@ #include #include -using namespace std; QList CoinControlDialog::payAmounts; int CoinControlDialog::nSplitBlockDummy; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); -CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : QDialog(parent), +CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::CoinControlDialog), model(0) { @@ -110,12 +109,8 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q // click on checkbox connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int))); -// click on header -#if QT_VERSION < 0x050000 - ui->treeWidget->header()->setClickable(true); -#else + // click on header ui->treeWidget->header()->setSectionsClickable(true); -#endif connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int))); // ok button @@ -445,16 +440,14 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) updateDialogLabels(); } } -// todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node -// including all childs are partially selected. But the parent node should be fully selected -// as well as the childs. Childs should never be partially selected in the first place. -// Please remove this ugly fix, once the bug is solved upstream. -#if QT_VERSION >= 0x050000 - else if (column == COLUMN_CHECKBOX && item->childCount() > 0) { + + // TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used. + // Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473 + else if (column == COLUMN_CHECKBOX && item->childCount() > 0) + { if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked) item->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } -#endif } // return human readable label for priority number @@ -488,7 +481,7 @@ QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEsti // shows count of locked unspent outputs void CoinControlDialog::updateLabelLocked() { - vector vOutpts; + std::vector vOutpts; model->listLockedCoins(vOutpts); if (vOutpts.size() > 0) { ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size())); @@ -505,8 +498,8 @@ void CoinControlDialog::updateDialogLabels() return; } - vector vCoinControl; - vector vOutputs; + std::vector vCoinControl; + std::vector vOutputs; coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); @@ -546,7 +539,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) nPayAmount += amount; if (amount > 0) { - CTxOut txout(amount, (CScript)vector(24, 0)); + CTxOut txout(amount, (CScript)std::vector(24, 0)); txDummy.vout.push_back(txout); if (txout.IsDust(::minRelayTxFee)) fDust = true; @@ -572,7 +565,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); - BOOST_FOREACH (const COutput& out, vOutputs) { + for (const COutput& out : vOutputs) { // unselect already spent, very unlikely scenario, this could happen // when selected are spent elsewhere, like rpc or another computer uint256 txhash = out.tx->GetHash(); @@ -617,7 +610,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) // calculation if (nQuantity > 0) { // Bytes - nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + max(1, CoinControlDialog::nSplitBlockDummy) : 2) * 34) + 10; // always assume +1 output for change here + nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + std::max(1, CoinControlDialog::nSplitBlockDummy) : 2) * 34) + 10; // always assume +1 output for change here if (fWitness) { // there is some fudging in these numbers related to the actual virtual transaction size calculation that will keep this estimate from being exact. @@ -636,7 +629,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); // IX Fee - if (coinControl->useSwiftTX) nPayFee = max(nPayFee, CENT); + if (coinControl->useSwiftTX) nPayFee = std::max(nPayFee, CENT); // Allow free? double dPriorityNeeded = mempoolEstimatePriority; if (dPriorityNeeded <= 0) @@ -652,7 +645,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) // Never create dust outputs; if we would, just add the dust to the fee. if (nChange > 0 && nChange < CENT) { - CTxOut txout(nChange, (CScript)vector(24, 0)); + CTxOut txout(nChange, (CScript)std::vector(24, 0)); if (txout.IsDust(::minRelayTxFee)) { nPayFee += nChange; nChange = 0; @@ -764,10 +757,10 @@ void CoinControlDialog::updateView() int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); - map> mapCoins; + std::map> mapCoins; model->listCoins(mapCoins); - BOOST_FOREACH (PAIRTYPE(QString, vector) coins, mapCoins) { + for (PAIRTYPE(QString, std::vector) coins : mapCoins) { QTreeWidgetItem* itemWalletAddress = new QTreeWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; diff --git a/src/qt/configuremasternodepage.cpp b/src/qt/configuremasternodepage.cpp index 36f3c04172e1..2f491de80cb4 100644 --- a/src/qt/configuremasternodepage.cpp +++ b/src/qt/configuremasternodepage.cpp @@ -39,12 +39,12 @@ ConfigureMasternodePage::ConfigureMasternodePage(Mode mode, QWidget* parent) : Q mode(mode) { ui->setupUi(this); - - GUIUtil::setupAliasWidget(ui->aliasEdit, this); - GUIUtil::setupIPWidget(ui->vpsIpEdit, this); - GUIUtil::setupPrivKeyWidget(ui->privKeyEdit, this); - GUIUtil::setupTXIDWidget(ui->outputEdit, this); - GUIUtil::setupTXIDIndexWidget(ui->outputIdEdit, this); + + GUIUtil::setupAliasWidget(ui->aliasEdit, this); + GUIUtil::setupIPWidget(ui->vpsIpEdit, this); + GUIUtil::setupPrivKeyWidget(ui->privKeyEdit, this); + GUIUtil::setupTXIDWidget(ui->outputEdit, this); + GUIUtil::setupTXIDIndexWidget(ui->outputIdEdit, this); switch (mode) { case NewConfigureMasternode: @@ -105,53 +105,53 @@ void ConfigureMasternodePage::saveCurrentRow() switch (mode) { case NewConfigureMasternode: - if(ui->aliasEdit->text().toStdString().empty() || ui->vpsIpEdit->text().toStdString().empty() || ui->privKeyEdit->text().toStdString().empty() || ui->outputEdit->text().toStdString().empty() || ui->outputIdEdit->text().toStdString().empty()) { - break; - } - masternodeConfig.add(ui->aliasEdit->text().toStdString(), ui->vpsIpEdit->text().toStdString(), ui->privKeyEdit->text().toStdString(), ui->outputEdit->text().toStdString(), ui->outputIdEdit->text().toStdString()); - masternodeConfig.writeToMasternodeConf(); + if(ui->aliasEdit->text().toStdString().empty() || ui->vpsIpEdit->text().toStdString().empty() || ui->privKeyEdit->text().toStdString().empty() || ui->outputEdit->text().toStdString().empty() || ui->outputIdEdit->text().toStdString().empty()) { + break; + } + masternodeConfig.add(ui->aliasEdit->text().toStdString(), ui->vpsIpEdit->text().toStdString(), ui->privKeyEdit->text().toStdString(), ui->outputEdit->text().toStdString(), ui->outputIdEdit->text().toStdString()); + masternodeConfig.writeToMasternodeConf(); break; case EditConfigureMasternode: - if(ui->aliasEdit->text().toStdString().empty() || ui->vpsIpEdit->text().toStdString().empty() || ui->privKeyEdit->text().toStdString().empty() || ui->outputEdit->text().toStdString().empty() || ui->outputIdEdit->text().toStdString().empty()) { - break; - } - - QString MnAlias = getMnAliasCache(); - ConfigureMasternodePage::updateAlias(ui->aliasEdit->text().toStdString(), ui->vpsIpEdit->text().toStdString(), ui->privKeyEdit->text().toStdString(), ui->outputEdit->text().toStdString(), ui->outputIdEdit->text().toStdString(), MnAlias.toStdString()); - break; + if(ui->aliasEdit->text().toStdString().empty() || ui->vpsIpEdit->text().toStdString().empty() || ui->privKeyEdit->text().toStdString().empty() || ui->outputEdit->text().toStdString().empty() || ui->outputIdEdit->text().toStdString().empty()) { + break; + } + + QString MnAlias = getMnAliasCache(); + ConfigureMasternodePage::updateAlias(ui->aliasEdit->text().toStdString(), ui->vpsIpEdit->text().toStdString(), ui->privKeyEdit->text().toStdString(), ui->outputEdit->text().toStdString(), ui->outputIdEdit->text().toStdString(), MnAlias.toStdString()); + break; } } void ConfigureMasternodePage::accept() { - saveCurrentRow(); - emit accepted(); + saveCurrentRow(); + emit accepted(); QDialog::accept(); } void ConfigureMasternodePage::updateAlias(std::string Alias, std::string IP, std::string PrivKey, std::string TxHash, std::string OutputIndex, std::string mnAlias) { - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { - if(mnAlias == mne.getAlias()) { - int count = 0; - count = getCounters(); - vector confLockedCoins; - uint256 mnTxHash; - mnTxHash.SetHex(mne.getTxHash()); - int nIndex; - if(!mne.castOutputIndex(nIndex)) - continue; - COutPoint outpoint = COutPoint(mnTxHash, nIndex); - confLockedCoins.push_back(outpoint); - pwalletMain->UnlockCoin(outpoint); - - masternodeConfig.deleteAlias(count); - masternodeConfig.add(Alias, IP, PrivKey, TxHash, OutputIndex); - // write to masternode.conf - masternodeConfig.writeToMasternodeConf(); - } - } + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + if(mnAlias == mne.getAlias()) { + int count = 0; + count = getCounters(); + std::vector confLockedCoins; + uint256 mnTxHash; + mnTxHash.SetHex(mne.getTxHash()); + int nIndex; + if(!mne.castOutputIndex(nIndex)) + continue; + COutPoint outpoint = COutPoint(mnTxHash, nIndex); + confLockedCoins.push_back(outpoint); + pwalletMain->UnlockCoin(outpoint); + + masternodeConfig.deleteAlias(count); + masternodeConfig.add(Alias, IP, PrivKey, TxHash, OutputIndex); + // write to masternode.conf + masternodeConfig.writeToMasternodeConf(); + } + } } @@ -160,19 +160,19 @@ void ConfigureMasternodePage::on_AutoFillPrivKey_clicked() CKey secret; secret.MakeNewKey(false); - ui->privKeyEdit->setText(QString::fromStdString(CBitcoinSecret(secret).ToString())); + ui->privKeyEdit->setText(QString::fromStdString(CBitcoinSecret(secret).ToString())); } void ConfigureMasternodePage::on_AutoFillOutputs_clicked() { // Find possible candidates - vector possibleCoins = activeMasternode.SelectCoinsMasternode(); + std::vector possibleCoins = activeMasternode.SelectCoinsMasternode(); int test = 0; - BOOST_FOREACH (COutput& out, possibleCoins) { + for (COutput& out : possibleCoins) { std::string TXHash = out.tx->GetHash().ToString(); std::string OutputID = std::to_string(out.i); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if(OutputID == mne.getOutputIndex() && TXHash == mne.getTxHash()) { test = 1; diff --git a/src/qt/configuremasternodepage.h b/src/qt/configuremasternodepage.h index e6c8467502ed..ef78a275cbc7 100644 --- a/src/qt/configuremasternodepage.h +++ b/src/qt/configuremasternodepage.h @@ -47,33 +47,33 @@ class ConfigureMasternodePage : public QDialog explicit ConfigureMasternodePage(Mode mode, QWidget* parent); ~ConfigureMasternodePage(); - void counter(int counter); - void MNAliasCache(QString MnAliasCache); + void counter(int counter); + void MNAliasCache(QString MnAliasCache); void loadAlias(QString strAlias); void loadIP(QString strIP); void loadPrivKey(QString strPrivKey); void loadTxHash(QString strTxHash); void loadOutputIndex(QString strOutputIndex); - void updateAlias(std::string Alias, std::string IP, std::string PrivKey, std::string TxHash, std::string OutputIndex, std::string mnAlias); - int getCounters() - { - return counters; - } - - int setCounters(int counter) - { - counters = counter; - } - - QString getMnAliasCache() - { - return mnAliasCache; - } - - void setMnAliasCache(QString mnAliasCaches) - { - mnAliasCache = mnAliasCaches; - } + void updateAlias(std::string Alias, std::string IP, std::string PrivKey, std::string TxHash, std::string OutputIndex, std::string mnAlias); + int getCounters() + { + return counters; + } + + int setCounters(int counter) + { + counters = counter; + } + + QString getMnAliasCache() + { + return mnAliasCache; + } + + void setMnAliasCache(QString mnAliasCaches) + { + mnAliasCache = mnAliasCaches; + } QString getAddress() const; void setAddress(const QString& address); @@ -85,8 +85,8 @@ public slots: private: void saveCurrentRow(); - int counters; - QString mnAliasCache; + int counters; + QString mnAliasCache; Ui::ConfigureMasternodePage* ui; QDataWidgetMapper* mapper; Mode mode; diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index d9ee1c0194ae..fbbb4273f810 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -521,7 +521,7 @@ https://www.transifex.com/phore-project/phore-project-translations - + @@ -542,7 +542,7 @@ https://www.transifex.com/phore-project/phore-project-translations - + @@ -566,7 +566,7 @@ https://www.transifex.com/phore-project/phore-project-translations - + @@ -580,20 +580,47 @@ https://www.transifex.com/phore-project/phore-project-translations - - - Hide empty balances - - - Qt::LeftToRight - - - Hide empty balances - - + + + + + Hide empty balances + + + Qt::LeftToRight + + + Hide empty balances + + + + + + + Hide orphan stakes in transaction lists + + + Hide orphan stakes + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index d0672340c65c..1d45558713a7 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -7,7 +7,7 @@ 0 0 769 - 485 + 516 @@ -27,6 +27,13 @@ 12 + + + + N/A + + + @@ -184,7 +191,7 @@ - + @@ -197,14 +204,14 @@ - + Name - + IBeamCursor @@ -220,14 +227,14 @@ - + Number of connections - + IBeamCursor @@ -243,14 +250,14 @@ - + Number of Masternodes - + IBeamCursor @@ -266,7 +273,7 @@ - + @@ -279,14 +286,14 @@ - + Current number of blocks - + IBeamCursor @@ -302,14 +309,14 @@ - + Last block time - + IBeamCursor @@ -325,7 +332,7 @@ - + Qt::Vertical @@ -338,7 +345,7 @@ - + @@ -351,7 +358,7 @@ - + Open the Phore debug log file from the current data directory. This can take a few seconds for large log files. @@ -364,6 +371,27 @@ + + + + Data Directory + + + + + + + Last block hash + + + + + + + N/A + + + @@ -1298,12 +1326,12 @@ - - Custom Backup Path: - false + + Custom Backup Path: + @@ -1311,6 +1339,9 @@ IBeamCursor + + false + N/A @@ -1320,19 +1351,16 @@ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - false - - - Custom zPHR Backup Path: - false + + Custom zPHR Backup Path: + @@ -1340,6 +1368,9 @@ IBeamCursor + + false + N/A @@ -1349,19 +1380,16 @@ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - false - - - Custom Backups Threshold: - false + + Custom Backups Threshold: + @@ -1369,6 +1397,9 @@ IBeamCursor + + false + N/A @@ -1378,9 +1409,6 @@ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - false - diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index c7a6d9c1c4dc..13b3c6a606c8 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -893,7 +893,7 @@ 0 - + 0 @@ -907,31 +907,186 @@ 6 - - + + 0 + + 10 + + + 10 + + + 5 + - + + + + + true + + + + 85 + 0 + + + + SwiftX technology allows for near instant transactions - A flat fee of 0.01 PHR applies + + + SwiftX + + + + + + + Confirmation time: + + + 2 + + + + + + + normal + + + 8 + + + + + + + + 0 + 24 + + + + 0 + + + 24 + + + 1 + + + 0 + + + Qt::Horizontal + + + false + + + false + + + QSlider::NoTicks + + + + + + + fast + + + 8 + + + + + + + 0 - + - Qt::Vertical + Qt::Horizontal + + + + 40 + 20 + - - QSizePolicy::Fixed + + + + + + + + + 2 + + + + + + + (Smart fee not initialized yet. This usually takes a few blocks...) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + 2 + + + -1 + + + + + + + Qt::Horizontal - 1 - 4 + 40 + 20 + + + + + + + + 10 + + + 10 + + + 0 + + + + + 0 + @@ -1217,8 +1372,31 @@ + + + + + + + 2 + + + + + + + + + + true + + + groupFee + + + - + 6 @@ -1228,150 +1406,6 @@ 0 - - - - - - Confirmation time: - - - 2 - - - - - - - - 75 - true - - - - normal - - - 2 - - - - - - - - 0 - 24 - - - - 0 - - - 24 - - - 1 - - - 0 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - - 75 - true - - - - fast - - - - - - - - - 0 - - - - - Qt::Horizontal - - - - 100 - 20 - - - - - - - - - - - 2 - - - - - - - - 11 - - - - (Smart fee not initialized yet. This usually takes a few blocks...) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - 2 - - - -1 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - @@ -1436,29 +1470,6 @@ - - - - - - - 2 - - - - - - - - - - true - - - groupFee - - - @@ -1624,23 +1635,7 @@ - - - true - - - - 85 - 0 - - - - SwiftX - - - - - + Balance: diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 2bafc32100d9..7037953e79e7 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -56,12 +56,9 @@ #include #include // for Qt::mightBeRichText #include - -#if QT_VERSION < 0x050000 -#include -#else #include -#endif +#include + #if BOOST_FILESYSTEM_VERSION >= 3 static boost::filesystem::detail::utf8_codecvt_facet utf8; @@ -94,11 +91,7 @@ QString dateTimeStr(qint64 nTime) QFont bitcoinAddressFont() { QFont font("Monospace"); -#if QT_VERSION >= 0x040800 font.setStyleHint(QFont::Monospace); -#else - font.setStyleHint(QFont::TypeWriter); -#endif return font; } @@ -107,11 +100,10 @@ void setupAddressWidget(QValidatedLineEdit* widget, QWidget* parent) parent->setFocusProxy(widget); widget->setFont(bitcoinAddressFont()); -#if QT_VERSION >= 0x040700 // We don't want translators to use own addresses in translations // and this is the only place, where this address is supplied. + widget->setPlaceholderText(QObject::tr("Enter a Phore address (e.g. %1)").arg("PCYiHgGJJ6xGHqivmdZrYjRnhaYf6AJ2Mp")); -#endif widget->setValidator(new BitcoinAddressEntryValidator(parent)); widget->setCheckValidator(new BitcoinAddressCheckValidator(parent)); } @@ -199,13 +191,10 @@ bool parseBitcoinURI(const QUrl& uri, SendCoinsRecipient* out) } rv.amount = 0; -#if QT_VERSION < 0x050000 - QList > items = uri.queryItems(); -#else QUrlQuery uriQuery(uri); QList > items = uriQuery.queryItems(); -#endif - for (QList >::iterator i = items.begin(); i != items.end(); i++) { + for (QList >::iterator i = items.begin(); i != items.end(); i++) + { bool fShouldReturnFalse = false; if (i->first.startsWith("req-")) { i->first.remove(0, 4); @@ -285,11 +274,7 @@ bool isDust(const QString& address, const CAmount& amount) QString HtmlEscape(const QString& str, bool fMultiLine) { -#if QT_VERSION < 0x050000 - QString escaped = Qt::escape(str); -#else QString escaped = str.toHtmlEscaped(); -#endif escaped = escaped.replace(" ", " "); if (fMultiLine) { escaped = escaped.replace("\n", "
\n"); @@ -333,12 +318,10 @@ QString getSaveFileName(QWidget* parent, const QString& caption, const QString& QString myDir; if (dir.isEmpty()) // Default to user documents location { -#if QT_VERSION < 0x050000 - myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); -#else myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#endif - } else { + } + else + { myDir = dir; } /* Directly convert path to native OS path separators */ @@ -375,12 +358,10 @@ QString getOpenFileName(QWidget* parent, const QString& caption, const QString& QString myDir; if (dir.isEmpty()) // Default to user documents location { -#if QT_VERSION < 0x050000 - myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); -#else myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#endif - } else { + } + else + { myDir = dir; } /* Directly convert path to native OS path separators */ @@ -530,11 +511,7 @@ void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals() // Refactored here for readability. void TableViewLastColumnResizingFixer::setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode) { -#if QT_VERSION < 0x050000 - tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode); -#else tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode); -#endif } void TableViewLastColumnResizingFixer::resizeColumn(int nColumnIndex, int width) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index a08e39e9f433..83944a8cd539 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -232,19 +232,18 @@ QString formatPingTime(double dPingTime); /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ QString formatTimeOffset(int64_t nTimeOffset); -#if defined(Q_OS_MAC) && QT_VERSION >= 0x050000 -// workaround for Qt OSX Bug: -// https://bugreports.qt-project.org/browse/QTBUG-15631 -// QProgressBar uses around 10% CPU even when app is in background -class ProgressBar : public QProgressBar -{ - bool event(QEvent* e) +#if defined(Q_OS_MAC) + // workaround for Qt OSX Bug: + // https://bugreports.qt-project.org/browse/QTBUG-15631 + // QProgressBar uses around 10% CPU even when app is in background + class ProgressBar : public QProgressBar { - return (e->type() != QEvent::StyleAnimationUpdate) ? QProgressBar::event(e) : false; - } -}; + bool event(QEvent *e) { + return (e->type() != QEvent::StyleAnimationUpdate) ? QProgressBar::event(e) : false; + } + }; #else -typedef QProgressBar ProgressBar; + typedef QProgressBar ProgressBar; #endif } // namespace GUIUtil diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 46e64d5b6118..9dbe6902b3bc 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -103,7 +103,7 @@ void FreespaceChecker::check() } -Intro::Intro(QWidget* parent) : QDialog(parent), +Intro::Intro(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::Intro), thread(0), signalled(false) diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index e66154f144f8..19d83fc75265 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -14,18 +14,14 @@ #include #include -#if QT_VERSION < 0x050000 -extern void qt_mac_set_dock_menu(QMenu *); -#endif - -static MacDockIconHandler *s_instance = NULL; +static MacDockIconHandler *s_instance = nullptr; bool dockClickHandler(id self,SEL _cmd,...) { Q_UNUSED(self) Q_UNUSED(_cmd) - + s_instance->handleDockIconClickEvent(); - + // Return NO (false) to suppress the default OS X actions return false; } @@ -33,7 +29,7 @@ bool dockClickHandler(id self,SEL _cmd,...) { void setupDockClickHandler() { Class cls = objc_getClass("NSApplication"); id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication")); - + if (appInst != NULL) { id delegate = objc_msgSend(appInst, sel_registerName("delegate")); Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class")); @@ -53,10 +49,8 @@ void setupDockClickHandler() { setupDockClickHandler(); this->m_dummyWidget = new QWidget(); this->m_dockMenu = new QMenu(this->m_dummyWidget); - this->setMainWindow(NULL); -#if QT_VERSION < 0x050000 - qt_mac_set_dock_menu(this->m_dockMenu); -#elif QT_VERSION >= 0x050200 + this->setMainWindow(nullptr); +#if QT_VERSION >= 0x050200 this->m_dockMenu->setAsDockMenu(); #endif [pool release]; diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index ee5faeabba63..f1784c82a70b 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -59,21 +59,21 @@ MasternodeList::MasternodeList(QWidget* parent) : QWidget(parent), QAction* startAliasAction = new QAction(tr("Start alias"), this); QAction* copyAliasAction = new QAction(tr("Copy alias"), this); QAction* editAliasAction = new QAction(tr("Edit alias"), this); - QAction* deleteAliasAction = new QAction(tr("Delete"), this); + QAction* deleteAliasAction = new QAction(tr("Delete"), this); contextMenu = new QMenu(); contextMenu->addAction(startAliasAction); contextMenu->addAction(copyAliasAction); contextMenu->addAction(editAliasAction); - contextMenu->addAction(deleteAliasAction); - + contextMenu->addAction(deleteAliasAction); + connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); - connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked())); - connect(copyAliasAction, SIGNAL(triggered()), this, SLOT(copyAlias())); - connect(editAliasAction, SIGNAL(triggered()), this, SLOT(on_editConfigureMasternode_clicked())); - connect(deleteAliasAction, SIGNAL(triggered()), this, SLOT(deleteAlias())); - - + connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked())); + connect(copyAliasAction, SIGNAL(triggered()), this, SLOT(copyAlias())); + connect(editAliasAction, SIGNAL(triggered()), this, SLOT(on_editConfigureMasternode_clicked())); + connect(deleteAliasAction, SIGNAL(triggered()), this, SLOT(deleteAlias())); + + timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList())); timer->start(1000); @@ -109,7 +109,7 @@ void MasternodeList::StartAlias(std::string strAlias) std::string strStatusHtml; strStatusHtml += "
Alias: " + strAlias; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if (mne.getAlias() == strAlias) { std::string strError; CMasternodeBroadcast mnb; @@ -141,7 +141,7 @@ void MasternodeList::StartAll(std::string strCommand) int nCountFailed = 0; std::string strFailedHtml; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string strError; CMasternodeBroadcast mnb; @@ -186,7 +186,7 @@ void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, C bool fOldRowFound = false; int nNewRow = 0; - + for (int i = 0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) { if (ui->tableWidgetMyMasternodes->item(i, 0)->text() == strAlias) { fOldRowFound = true; @@ -230,7 +230,7 @@ void MasternodeList::updateMyNodeList(bool fForce) nTimeMyListUpdated = GetTime(); ui->tableWidgetMyMasternodes->setSortingEnabled(false); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { int nIndex; if(!mne.castOutputIndex(nIndex)) continue; @@ -291,35 +291,35 @@ void MasternodeList::on_editConfigureMasternode_clicked() int nSelectedRow = index.row(); std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString(); - int count = 0; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { - count = count + 1; - if(strAlias == mne.getAlias()) { - MasternodeList::openEditConfigureMasternodePage(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), QString::fromStdString(mne.getPrivKey()), QString::fromStdString(mne.getTxHash()), QString::fromStdString(mne.getOutputIndex()), count); - break; - - } + int count = 0; + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + count = count + 1; + if(strAlias == mne.getAlias()) { + MasternodeList::openEditConfigureMasternodePage(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), QString::fromStdString(mne.getPrivKey()), QString::fromStdString(mne.getTxHash()), QString::fromStdString(mne.getOutputIndex()), count); + break; + + } } } void MasternodeList::on_configureMasternodeButton_clicked() { - + ConfigureMasternodePage dlg(ConfigureMasternodePage::NewConfigureMasternode, this); if ( QDialog::Accepted == dlg.exec() ) { while (ui->tableWidgetMyMasternodes->rowCount() > 0) - { - ui->tableWidgetMyMasternodes->removeRow(0); - } - - // clear cache - masternodeConfig.clear(); + { + ui->tableWidgetMyMasternodes->removeRow(0); + } + + // clear cache + masternodeConfig.clear(); // parse masternode.conf std::string strErr; if (!masternodeConfig.read(strErr)) { LogPrintf("Error reading masternode configuration file: \n"); - } + } updateMyNodeList(true); } } @@ -328,26 +328,26 @@ void MasternodeList::openEditConfigureMasternodePage(QString strAlias, QString s { ConfigureMasternodePage dlg(ConfigureMasternodePage::EditConfigureMasternode, this); dlg.loadAlias(strAlias); - dlg.loadIP(strIP); - dlg.loadPrivKey(strPrivKey); - dlg.loadTxHash(strTxHash); - dlg.loadOutputIndex(strOutputIndex); - dlg.counter(count); - dlg.MNAliasCache(strAlias); + dlg.loadIP(strIP); + dlg.loadPrivKey(strPrivKey); + dlg.loadTxHash(strTxHash); + dlg.loadOutputIndex(strOutputIndex); + dlg.counter(count); + dlg.MNAliasCache(strAlias); if ( QDialog::Accepted == dlg.exec() ) { while (ui->tableWidgetMyMasternodes->rowCount() > 0) - { - ui->tableWidgetMyMasternodes->removeRow(0); - } - - // clear cache - masternodeConfig.clear(); + { + ui->tableWidgetMyMasternodes->removeRow(0); + } + + // clear cache + masternodeConfig.clear(); // parse masternode.conf std::string strErr; if (!masternodeConfig.read(strErr)) { LogPrintf("Error reading masternode configuration file: \n"); - } + } updateMyNodeList(true); } } @@ -363,38 +363,38 @@ void MasternodeList::deleteAlias() QModelIndex index = selected.at(0); int nSelectedRow = index.row(); std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString(); - int count = 0; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { - count = count + 1; - if(strAlias == mne.getAlias()) { - vector confLockedCoins; - uint256 mnTxHash; - mnTxHash.SetHex(mne.getTxHash()); + int count = 0; + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + count = count + 1; + if(strAlias == mne.getAlias()) { + std::vector confLockedCoins; + uint256 mnTxHash; + mnTxHash.SetHex(mne.getTxHash()); int nIndex; if(!mne.castOutputIndex(nIndex)) continue; - COutPoint outpoint = COutPoint(mnTxHash, nIndex); - confLockedCoins.push_back(outpoint); - pwalletMain->UnlockCoin(outpoint); - masternodeConfig.deleteAlias(count); - // write to masternode.conf - masternodeConfig.writeToMasternodeConf(); + COutPoint outpoint = COutPoint(mnTxHash, nIndex); + confLockedCoins.push_back(outpoint); + pwalletMain->UnlockCoin(outpoint); + masternodeConfig.deleteAlias(count); + // write to masternode.conf + masternodeConfig.writeToMasternodeConf(); while (ui->tableWidgetMyMasternodes->rowCount() > 0) - { - ui->tableWidgetMyMasternodes->removeRow(0); - } - - // clear cache - masternodeConfig.clear(); + { + ui->tableWidgetMyMasternodes->removeRow(0); + } + + // clear cache + masternodeConfig.clear(); // parse masternode.conf std::string strErr; if (!masternodeConfig.read(strErr)) { LogPrintf("Error reading masternode configuration file: \n"); - } - updateMyNodeList(true); - break; - - } + } + updateMyNodeList(true); + break; + + } } } @@ -410,15 +410,15 @@ void MasternodeList::copyAlias() int nSelectedRow = index.row(); std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString(); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { - - if(strAlias == mne.getAlias()) { - - std::string fullAliasCopy = mne.getAlias() + " " + mne.getIp() + " " + mne.getPrivKey() + " " + mne.getTxHash() + " " + mne.getOutputIndex(); - GUIUtil::setClipboard(QString::fromStdString(fullAliasCopy)); - break; - - } + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + + if(strAlias == mne.getAlias()) { + + std::string fullAliasCopy = mne.getAlias() + " " + mne.getIp() + " " + mne.getPrivKey() + " " + mne.getTxHash() + " " + mne.getOutputIndex(); + GUIUtil::setClipboard(QString::fromStdString(fullAliasCopy)); + break; + + } } } diff --git a/src/qt/masternodelist.h b/src/qt/masternodelist.h index c058d3784e45..0e6a5a962438 100644 --- a/src/qt/masternodelist.h +++ b/src/qt/masternodelist.h @@ -50,7 +50,7 @@ class MasternodeList : public QWidget void setWalletModel(WalletModel* walletModel); void StartAlias(std::string strAlias); void StartAll(std::string strCommand = "start-all"); - void deleteAlias(std::string Alias); + void deleteAlias(std::string Alias); private: QMenu* contextMenu; @@ -73,14 +73,14 @@ public Q_SLOTS: private Q_SLOTS: void showContextMenu(const QPoint&); - void deleteAlias(); - void copyAlias(); + void deleteAlias(); + void copyAlias(); void on_startButton_clicked(); void on_editConfigureMasternode_clicked(); void on_startAllButton_clicked(); void on_startMissingButton_clicked(); - void on_configureMasternodeButton_clicked(); - void openEditConfigureMasternodePage(QString strAlias, QString strIP, QString strPrivKey, QString strTxHash, QString strOutputIndex, int count); + void on_configureMasternodeButton_clicked(); + void openEditConfigureMasternodePage(QString strAlias, QString strIP, QString strPrivKey, QString strTxHash, QString strOutputIndex, int count); void on_tableWidgetMyMasternodes_itemSelectionChanged(); void on_UpdateButton_clicked(); }; diff --git a/src/qt/multisenddialog.cpp b/src/qt/multisenddialog.cpp index 4620d5af90f9..499f955fd036 100644 --- a/src/qt/multisenddialog.cpp +++ b/src/qt/multisenddialog.cpp @@ -1,28 +1,23 @@ #include "multisenddialog.h" +#include "ui_multisenddialog.h" + #include "addressbookpage.h" #include "addresstablemodel.h" #include "base58.h" #include "init.h" -#include "ui_multisenddialog.h" #include "walletmodel.h" -#include -#include -#include -#include -using namespace std; -using namespace boost; +#include -MultiSendDialog::MultiSendDialog(QWidget* parent) : QDialog(parent), +MultiSendDialog::MultiSendDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::MultiSendDialog), - model(0) + model(nullptr) { ui->setupUi(this); ui->multiSendPercentEdit->setAttribute(Qt::WA_MacShowFocusRect, 0); ui->multiSendAddressEdit->setAttribute(Qt::WA_MacShowFocusRect, 0); ui->labelAddressLabelEdit->setAttribute(Qt::WA_MacShowFocusRect, 0); - updateCheckBoxes(); } @@ -62,7 +57,7 @@ void MultiSendDialog::on_addressBookButton_clicked() if (dlg.exec()) setAddress(dlg.getReturnValue(), ui->multiSendAddressEdit); - //Update the label text box with the label in the addressbook + // Update the label text box with the label in the addressbook QString associatedLabel = model->getAddressTableModel()->labelForAddress(dlg.getReturnValue()); if (!associatedLabel.isEmpty()) ui->labelAddressLabelEdit->setText(associatedLabel); @@ -74,16 +69,17 @@ void MultiSendDialog::on_addressBookButton_clicked() void MultiSendDialog::on_viewButton_clicked() { std::pair pMultiSend; - std::string strMultiSendPrint = ""; + std::string strMultiSendPrint; + QString strStatus; if (pwalletMain->isMultiSendEnabled()) { if (pwalletMain->fMultiSendStake && pwalletMain->fMultiSendMasternodeReward) - strMultiSendPrint += "MultiSend Active for Stakes and Masternode Rewards\n"; + strStatus += tr("MultiSend Active for Stakes and Masternode Rewards") + "\n"; else if (pwalletMain->fMultiSendStake) - strMultiSendPrint += "MultiSend Active for Stakes\n"; + strStatus += tr("MultiSend Active for Stakes") + "\n"; else if (pwalletMain->fMultiSendMasternodeReward) - strMultiSendPrint += "MultiSend Active for Masternode Rewards\n"; + strStatus += tr("MultiSend Active for Masternode Rewards") + "\n"; } else - strMultiSendPrint += "MultiSend Not Active\n"; + strStatus += tr("MultiSend Not Active") + "\n"; for (int i = 0; i < (int)pwalletMain->vMultiSend.size(); i++) { pMultiSend = pwalletMain->vMultiSend[i]; @@ -95,13 +91,12 @@ void MultiSendDialog::on_viewButton_clicked() } strMultiSendPrint += pMultiSend.first.c_str(); strMultiSendPrint += " - "; - strMultiSendPrint += boost::lexical_cast(pMultiSend.second); - strMultiSendPrint += "% \n"; + strMultiSendPrint += std::to_string(pMultiSend.second); + strMultiSendPrint += "%\n"; } ui->message->setProperty("status", "ok"); ui->message->style()->polish(ui->message); - ui->message->setText(QString(strMultiSendPrint.c_str())); - return; + ui->message->setText(strStatus + QString(strMultiSendPrint.c_str())); } void MultiSendDialog::on_addButton_clicked() @@ -111,7 +106,7 @@ void MultiSendDialog::on_addButton_clicked() if (!IsValidDestinationString(strAddress)) { ui->message->setProperty("status", "error"); ui->message->style()->polish(ui->message); - ui->message->setText(tr("The entered address:\n") + ui->multiSendAddressEdit->text() + tr(" is invalid.\nPlease check the address and try again.")); + ui->message->setText(tr("The entered address: %1 is invalid.\nPlease check the address and try again.").arg(ui->multiSendAddressEdit->text())); ui->multiSendAddressEdit->setFocus(); return; } @@ -122,7 +117,7 @@ void MultiSendDialog::on_addButton_clicked() if (nSumMultiSend + nMultiSendPercent > 100) { ui->message->setProperty("status", "error"); ui->message->style()->polish(ui->message); - ui->message->setText(tr("The total amount of your MultiSend vector is over 100% of your stake reward\n")); + ui->message->setText(tr("The total amount of your MultiSend vector is over 100% of your stake reward")); ui->multiSendAddressEdit->setFocus(); return; } @@ -139,13 +134,13 @@ void MultiSendDialog::on_addButton_clicked() pwalletMain->vMultiSend.push_back(pMultiSend); ui->message->setProperty("status", "ok"); ui->message->style()->polish(ui->message); - std::string strMultiSendPrint = ""; + std::string strMultiSendPrint; for (int i = 0; i < (int)pwalletMain->vMultiSend.size(); i++) { pMultiSend = pwalletMain->vMultiSend[i]; strMultiSendPrint += pMultiSend.first.c_str(); strMultiSendPrint += " - "; - strMultiSendPrint += boost::lexical_cast(pMultiSend.second); - strMultiSendPrint += "% \n"; + strMultiSendPrint += std::to_string(pMultiSend.second); + strMultiSendPrint += "%\n"; } if (model && model->getAddressTableModel()) { @@ -162,12 +157,11 @@ void MultiSendDialog::on_addButton_clicked() if(!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) { ui->message->setProperty("status", "error"); ui->message->style()->polish(ui->message); - ui->message->setText(tr("Saved the MultiSend to memory, but failed saving properties to the database.\n")); + ui->message->setText(tr("Saved the MultiSend to memory, but failed saving properties to the database.")); ui->multiSendAddressEdit->setFocus(); return; } - ui->message->setText(tr("MultiSend Vector\n") + QString(strMultiSendPrint.c_str())); - return; + ui->message->setText(tr("MultiSend Vector") + "\n" + QString(strMultiSendPrint.c_str())); } void MultiSendDialog::on_deleteButton_clicked() @@ -188,50 +182,48 @@ void MultiSendDialog::on_deleteButton_clicked() fRemoved = false; if (fRemoved) - ui->message->setText(tr("Removed ") + QString(strAddress.c_str())); + ui->message->setText(tr("Removed %1").arg(QString(strAddress.c_str()))); else - ui->message->setText(tr("Could not locate address\n")); + ui->message->setText(tr("Could not locate address")); updateCheckBoxes(); - - return; } void MultiSendDialog::on_activateButton_clicked() { - std::string strRet = ""; + QString strRet; if (pwalletMain->vMultiSend.size() < 1) - strRet = "Unable to activate MultiSend, check MultiSend vector\n"; + strRet = tr("Unable to activate MultiSend, check MultiSend vector"); else if (!(ui->multiSendStakeCheckBox->isChecked() || ui->multiSendMasternodeCheckBox->isChecked())) { - strRet = "Need to select to send on stake and/or masternode rewards\n"; + strRet = tr("Need to select to send on stake and/or masternode rewards"); } else if (IsValidDestinationString(pwalletMain->vMultiSend[0].first)) { pwalletMain->fMultiSendStake = ui->multiSendStakeCheckBox->isChecked(); pwalletMain->fMultiSendMasternodeReward = ui->multiSendMasternodeCheckBox->isChecked(); CWalletDB walletdb(pwalletMain->strWalletFile); if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) - strRet = "MultiSend activated but writing settings to DB failed"; + strRet = tr("MultiSend activated but writing settings to DB failed"); else - strRet = "MultiSend activated"; + strRet = tr("MultiSend activated"); } else - strRet = "First Address Not Valid"; + strRet = tr("First Address Not Valid"); ui->message->setProperty("status", "ok"); ui->message->style()->polish(ui->message); - ui->message->setText(tr(strRet.c_str())); - return; + ui->message->setText(strRet); } void MultiSendDialog::on_disableButton_clicked() { - std::string strRet = ""; + QString strRet; pwalletMain->setMultiSendDisabled(); CWalletDB walletdb(pwalletMain->strWalletFile); + if (!walletdb.WriteMSettings(false, false, pwalletMain->nLastMultiSendHeight)) - strRet = "MultiSend deactivated but writing settings to DB failed"; + strRet = tr("MultiSend deactivated but writing settings to DB failed"); else - strRet = "MultiSend deactivated"; + strRet = tr("MultiSend deactivated"); + ui->message->setProperty("status", ""); ui->message->style()->polish(ui->message); - ui->message->setText(tr(strRet.c_str())); - return; + ui->message->setText(strRet); } diff --git a/src/qt/multisenddialog.h b/src/qt/multisenddialog.h index 2065243fbd62..e12e35c8cb68 100644 --- a/src/qt/multisenddialog.h +++ b/src/qt/multisenddialog.h @@ -16,7 +16,7 @@ class MultiSendDialog : public QDialog void updateCheckBoxes(); public: - explicit MultiSendDialog(QWidget* parent = 0); + explicit MultiSendDialog(QWidget* parent = nullptr); ~MultiSendDialog(); void setModel(WalletModel* model); void setAddress(const QString& address); @@ -34,4 +34,4 @@ private slots: WalletModel* model; }; -#endif // MULTISENDDIALOG_H +#endif // PHORE_QT_MULTISENDDIALOG_H diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index 07e51b6afbc9..cea10fa968ac 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -37,7 +37,7 @@ #include -MultisigDialog::MultisigDialog(QWidget* parent) : QDialog(parent), +MultisigDialog::MultisigDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::MultisigDialog), model(0) { @@ -200,7 +200,7 @@ void MultisigDialog::on_addMultisigButton_clicked() int m = ui->enterMSpinbox->value(); - vector keys; + std::vector keys; for (int i = 0; i < ui->addressList->count(); i++) { QWidget* address = qobject_cast(ui->addressList->itemAt(i)->widget()); @@ -219,7 +219,7 @@ void MultisigDialog::on_importAddressButton_clicked(){ if(!model) return; - string sRedeem = ui->importRedeem->text().toStdString(); + std::string sRedeem = ui->importRedeem->text().toStdString(); if(sRedeem.empty()){ ui->addMultisigStatus->setStyleSheet("QLabel { color: red; }"); @@ -227,7 +227,7 @@ void MultisigDialog::on_importAddressButton_clicked(){ return; } - vector vRedeem; + std::vector vRedeem; size_t pos = 0; //search redeem input delimited by space @@ -236,7 +236,7 @@ void MultisigDialog::on_importAddressButton_clicked(){ sRedeem.erase(0, pos + 1); } - vector keys(vRedeem.begin()+1, vRedeem.end()-1); + std::vector keys(vRedeem.begin()+1, vRedeem.end()-1); addMultisig(stoi(vRedeem[0]), keys); @@ -245,28 +245,28 @@ void MultisigDialog::on_importAddressButton_clicked(){ pwalletMain->ReacceptWalletTransactions(); } -bool MultisigDialog::addMultisig(int m, vector keys){ +bool MultisigDialog::addMultisig(int m, std::vector keys){ try{ - string error; + std::string error; CScript redeem; if(!createRedeemScript(m, keys, redeem, error)){ - throw runtime_error(error.data()); + throw std::runtime_error(error.data()); } if (::IsMine(*pwalletMain, redeem) == ISMINE_SPENDABLE){ - throw runtime_error("The wallet already contains this script"); + throw std::runtime_error("The wallet already contains this script"); } if(!pwalletMain->AddCScript(redeem)){ - throw runtime_error("Failure: address invalid or already exists"); + throw std::runtime_error("Failure: address invalid or already exists"); } CScriptID innerID(redeem); - string label = ui->multisigAddressLabel->text().toStdString(); + std::string label = ui->multisigAddressLabel->text().toStdString(); pwalletMain->SetAddressBook(innerID, label, "receive"); if (!pwalletMain->AddMultiSig(redeem)){ - throw runtime_error("Failure: unable to add address as watch only"); + throw std::runtime_error("Failure: unable to add address as watch only"); } ui->addMultisigStatus->setStyleSheet("QLabel { color: black; }"); @@ -274,7 +274,7 @@ bool MultisigDialog::addMultisig(int m, vector keys){ QString::fromStdString(EncodeDestination(innerID)) + " has been added to the wallet.\nSend the redeem below for other owners to import:\n" + QString::fromStdString(redeem.ToString())); - }catch(const runtime_error& e) { + }catch(const std::runtime_error& e) { ui->addMultisigStatus->setStyleSheet("QLabel { color: red; }"); ui->addMultisigStatus->setText(tr(e.what())); return false; @@ -289,12 +289,12 @@ void MultisigDialog::on_createButton_clicked() if(!model) return; - vector vUserIn; - vector vUserOut; + std::vector vUserIn; + std::vector vUserOut; try{ //Add inputs from Coin Control if any are selected if (CoinControlDialog::coinControl->HasSelected()) { - vector vSelected; + std::vector vSelected; CoinControlDialog::coinControl->ListSelected(vSelected); for (auto outpoint : vSelected) vUserIn.emplace_back(CTxIn(outpoint)); @@ -360,10 +360,10 @@ void MultisigDialog::on_createButton_clicked() //clear member variable multisigTx = CMutableTransaction(); - string error; - string fee; + std::string error; + std::string fee; if(!createMultisigTransaction(vUserIn, vUserOut, fee, error)){ - throw runtime_error(error); + throw std::runtime_error(error); } //display status string @@ -377,13 +377,13 @@ void MultisigDialog::on_createButton_clicked() ui->transactionHex->setText(QString::fromStdString(EncodeHexTx(multisigTx, PROTOCOL_VERSION))); } - }catch(const runtime_error& e){ + }catch(const std::runtime_error& e){ ui->createButtonStatus->setStyleSheet("QTextEdit{ color: red }"); ui->createButtonStatus->setText(tr(e.what())); } } -bool MultisigDialog::createMultisigTransaction(vector vUserIn, vector vUserOut, string& feeStringRet, string& errorRet) +bool MultisigDialog::createMultisigTransaction(std::vector vUserIn, std::vector vUserOut, std::string& feeStringRet, std::string& errorRet) { try{ //attempt to access the given inputs @@ -391,7 +391,7 @@ bool MultisigDialog::createMultisigTransaction(vector vUserIn, vector vInputVals; + std::vector vInputVals; CScript changePubKey; bool fFirst = true; @@ -408,7 +408,7 @@ bool MultisigDialog::createMultisigTransaction(vector vUserIn, vector vUserIn, vector vUserIn, vectorIsAvailable(tx.vin[0].prevout.n)){ - throw runtime_error("Coins unavailable (unconfirmed/spent)"); + throw std::runtime_error("Coins unavailable (unconfirmed/spent)"); } CScript prevPubKey = coins->vout[tx.vin[0].prevout.n].scriptPubKey; @@ -457,20 +457,20 @@ bool MultisigDialog::createMultisigTransaction(vector vUserIn, vector(address); CScript redeemScript; if (!pwalletMain->GetCScript(hash, redeemScript)){ - throw runtime_error("could not redeem"); + throw std::runtime_error("could not redeem"); } txnouttype type; - vector addresses; + std::vector addresses; int nReq; if(!ExtractDestinations(redeemScript, type, addresses, nReq)){ - throw runtime_error("Could not extract destinations from redeem script."); + throw std::runtime_error("Could not extract destinations from redeem script."); } for(CTxIn& in : tx.vin){ @@ -489,7 +489,7 @@ bool MultisigDialog::createMultisigTransaction(vector vUserIn, vector vUserIn, vectortransactionHex->text().toStdString(), true)){ - throw runtime_error("Failed to decode transaction hex!"); + throw std::runtime_error("Failed to decode transaction hex!"); } CMutableTransaction tx(txRead); @@ -527,7 +527,7 @@ void MultisigDialog::on_signButton_clicked() CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { const uint256& prevHash = txin.prevout.hash; CCoins coins; view.AccessCoins(prevHash); // this is certainly allowed to fail @@ -544,11 +544,11 @@ void MultisigDialog::on_signButton_clicked() return; } - string errorOut = string(); + std::string errorOut = std::string(); bool fComplete = signMultisigTx(tx, errorOut, ui->keyList); if(!errorOut.empty()){ - throw runtime_error(errorOut.data()); + throw std::runtime_error(errorOut.data()); }else{ this->multisigTx = tx; } @@ -556,7 +556,7 @@ void MultisigDialog::on_signButton_clicked() ui->signButtonStatus->setStyleSheet("QTextEdit{ color: black }"); ui->signButtonStatus->setText(buildMultisigTxStatusString(fComplete, tx)); - }catch(const runtime_error& e){ + }catch(const std::runtime_error& e){ ui->signButtonStatus->setStyleSheet("QTextEdit{ color: red }"); ui->signButtonStatus->setText(tr(e.what())); } @@ -567,19 +567,19 @@ void MultisigDialog::on_signButton_clicked() */ QString MultisigDialog::buildMultisigTxStatusString(bool fComplete, const CMutableTransaction& tx) { - string sTxHex = EncodeHexTx(tx, PROTOCOL_VERSION); + std::string sTxHex = EncodeHexTx(tx, PROTOCOL_VERSION); if(fComplete){ ui->commitButton->setEnabled(true); - string sTxId = tx.GetHash().GetHex(); - string sTxComplete = "Complete: true!\n" + std::string sTxId = tx.GetHash().GetHex(); + std::string sTxComplete = "Complete: true!\n" "The commit button has now been enabled for you to finalize the transaction.\n" "Once the commit button is clicked, the transaction will be published and coins transferred " "to their destinations.\nWARNING: THE ACTIONS OF THE COMMIT BUTTON ARE FINAL AND CANNOT BE REVERSED."; return QString(strprintf("%s\nTx Id:\n%s\nTx Hex:\n%s",sTxComplete, sTxId, sTxHex).c_str()); } else { - string sTxIncomplete = "Complete: false.\n" + std::string sTxIncomplete = "Complete: false.\n" "You may now send the hex below to another owner to sign.\n" "Keep in mind the transaction must be passed from one owner to the next for signing.\n" "Ensure all owners have imported the redeem before trying to sign. (besides creator)"; @@ -589,7 +589,7 @@ QString MultisigDialog::buildMultisigTxStatusString(bool fComplete, const CMutab } -CCoinsViewCache MultisigDialog::getInputsCoinsViewCache(const vector& vin) +CCoinsViewCache MultisigDialog::getInputsCoinsViewCache(const std::vector& vin) { CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); @@ -611,7 +611,7 @@ CCoinsViewCache MultisigDialog::getInputsCoinsViewCache(const vector& vin } -bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, QVBoxLayout* keyList) +bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, std::string& errorOut, QVBoxLayout* keyList) { //will be set false if all inputs are not fully signed(valid) bool fComplete = true; @@ -631,10 +631,10 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q QLineEdit* key = keyFrame->findChild("key"); CBitcoinSecret vchSecret; if (!vchSecret.SetString(key->text().toStdString())) - throw runtime_error("Invalid private key"); + throw std::runtime_error("Invalid private key"); CKey cKey = vchSecret.GetKey(); if (!cKey.IsValid()) - throw runtime_error("Private key outside allowed range"); + throw std::runtime_error("Private key outside allowed range"); privKeystore.AddKey(cKey); } @@ -643,10 +643,10 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q CTransaction txVin; uint256 hashBlock; if (!GetTransaction(txin.prevout.hash, txVin, hashBlock, true)) - throw runtime_error("txin could not be found"); + throw std::runtime_error("txin could not be found"); if (hashBlock == 0) - throw runtime_error("txin is unconfirmed"); + throw std::runtime_error("txin is unconfirmed"); //get pubkey from input CScript prevPubKey = txVin.vout[txin.prevout.n].scriptPubKey; @@ -654,7 +654,7 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q //get payment destination CTxDestination address; if(!ExtractDestination(prevPubKey, address)){ - throw runtime_error("Could not find address for destination."); + throw std::runtime_error("Could not find address for destination."); } //get redeem script related to destination @@ -670,7 +670,7 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q if (model->getEncryptionStatus() == model->Locked) { if (!model->requestUnlock(true).isValid()) { // Unlock wallet was cancelled - throw runtime_error("Error: Your wallet is locked. Please enter the wallet passphrase first."); + throw std::runtime_error("Error: Your wallet is locked. Please enter the wallet passphrase first."); } } } @@ -685,10 +685,10 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q CTransaction txVin; uint256 hashBlock; if (!GetTransaction(txin.prevout.hash, txVin, hashBlock, true)) - throw runtime_error("txin could not be found"); + throw std::runtime_error("txin could not be found"); if (hashBlock == 0) - throw runtime_error("txin is unconfirmed"); + throw std::runtime_error("txin is unconfirmed"); const CAmount& amount = txVin.vout[txin.prevout.n].nValue; @@ -713,8 +713,8 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q ui->signButtonStatus->setText(buildMultisigTxStatusString(fComplete, tx)); - }catch(const runtime_error& e){ - errorOut = string(e.what()); + }catch(const std::runtime_error& e){ + errorOut = std::string(e.what()); fComplete = false; } return fComplete; @@ -728,10 +728,10 @@ bool MultisigDialog::isFullyVerified(CMutableTransaction& tx){ CTransaction txVin; uint256 hashBlock; if (!GetTransaction(txin.prevout.hash, txVin, hashBlock, true)){ - throw runtime_error("txin could not be found"); + throw std::runtime_error("txin could not be found"); } if (hashBlock == 0){ - throw runtime_error("txin is unconfirmed"); + throw std::runtime_error("txin is unconfirmed"); } const CAmount& amount = txVin.vout[txin.prevout.n].nValue; @@ -746,7 +746,7 @@ bool MultisigDialog::isFullyVerified(CMutableTransaction& tx){ nIn++; } - }catch(const runtime_error& e){ + }catch(const std::runtime_error& e){ return false; } @@ -761,7 +761,7 @@ void MultisigDialog::commitMultisigTx() CWalletTx wtx(pwalletMain, tx); CReserveKey keyChange(pwalletMain); if (!pwalletMain->CommitTransaction(wtx, keyChange)) - throw runtime_error(string("Transaction rejected - Failed to commit")); + throw std::runtime_error(std::string("Transaction rejected - Failed to commit")); #else uint256 hashTx = tx.GetHash(); CCoinsViewCache& view = *pcoinsTip; @@ -775,60 +775,60 @@ void MultisigDialog::commitMultisigTx() CValidationState state; if (!AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) { if (state.IsInvalid()) - throw runtime_error(strprintf("Transaction rejected - %i: %s", state.GetRejectCode(), state.GetRejectReason())); + throw std::runtime_error(strprintf("Transaction rejected - %i: %s", state.GetRejectCode(), state.GetRejectReason())); else - throw runtime_error(string("Transaction rejected - ") + state.GetRejectReason()); + throw std::runtime_error(std::string("Transaction rejected - ") + state.GetRejectReason()); } } else if (fHaveChain) { - throw runtime_error("transaction already in block chain"); + throw std::runtime_error("transaction already in block chain"); } RelayTransaction(tx); #endif //disable commit if successfully committed ui->commitButton->setEnabled(false); ui->signButtonStatus->setText(strprintf("Transaction has been successfully published with transaction ID:\n %s", tx.GetHash().GetHex()).c_str()); - }catch(const runtime_error& e){ + }catch(const std::runtime_error& e){ ui->signButtonStatus->setText(e.what()); } } -bool MultisigDialog::createRedeemScript(int m, vector vKeys, CScript& redeemRet, string& errorRet) +bool MultisigDialog::createRedeemScript(int m, std::vector vKeys, CScript& redeemRet, std::string& errorRet) { try{ int n = vKeys.size(); //gather pub keys if (n < 1) - throw runtime_error("a Multisignature address must require at least one key to redeem"); + throw std::runtime_error("a Multisignature address must require at least one key to redeem"); if (n < m) - throw runtime_error( + throw std::runtime_error( strprintf("not enough keys supplied " "(got %d keys, but need at least %d to redeem)", m, n)); if (n > 15) - throw runtime_error("Number of addresses involved in the Multisignature address creation > 15\nReduce the number"); + throw std::runtime_error("Number of addresses involved in the Multisignature address creation > 15\nReduce the number"); - vector pubkeys; + std::vector pubkeys; pubkeys.resize(n); int i = 0; - for(vector::iterator it = vKeys.begin(); it != vKeys.end(); ++it) { - string keyString = *it; + for(std::vector::iterator it = vKeys.begin(); it != vKeys.end(); ++it) { + std::string keyString = *it; #ifdef ENABLE_WALLET // Case 1: Phore address and we have full public key: if (pwalletMain && IsValidDestinationString(keyString)) { CTxDestination address = DecodeDestination(keyString); CKeyID keyID = GetKeyForDestination(*pwalletMain, address); if (keyID.IsNull()) { - throw runtime_error( + throw std::runtime_error( strprintf("%s does not refer to a key", keyString)); } CPubKey vchPubKey; if (!pwalletMain->GetPubKey(keyID, vchPubKey)) - throw runtime_error( + throw std::runtime_error( strprintf("no full public key for address %s", keyString)); if (!vchPubKey.IsFullyValid()){ - string sKey = keyString.empty()?"(empty)":keyString; - throw runtime_error(" Invalid public key: " + sKey ); + std::string sKey = keyString.empty()?"(empty)":keyString; + throw std::runtime_error(" Invalid public key: " + sKey ); } pubkeys[i++] = vchPubKey; } @@ -839,11 +839,11 @@ bool MultisigDialog::createRedeemScript(int m, vector vKeys, CScript& re if (IsHex(keyString)) { CPubKey vchPubKey(ParseHex(keyString)); if (!vchPubKey.IsFullyValid()){ - throw runtime_error(" Invalid public key: " + keyString); + throw std::runtime_error(" Invalid public key: " + keyString); } pubkeys[i++] = vchPubKey; } else { - throw runtime_error(" Invalid public key: " + keyString); + throw std::runtime_error(" Invalid public key: " + keyString); } } //populate redeem script @@ -851,15 +851,15 @@ bool MultisigDialog::createRedeemScript(int m, vector vKeys, CScript& re redeemRet << redeemRet.EncodeOP_N(m); //public keys for(CPubKey& key : pubkeys){ - vector vKey= ToByteVector(key); + std::vector vKey= ToByteVector(key); redeemRet << vKey; } //OP_N for total pubkeys redeemRet << redeemRet.EncodeOP_N(pubkeys.size()); redeemRet << OP_CHECKMULTISIG; return true; - }catch(const runtime_error& e){ - errorRet = string(e.what()); + }catch(const std::runtime_error& e){ + errorRet = std::string(e.what()); return false; } } diff --git a/src/qt/multisigdialog.h b/src/qt/multisigdialog.h index eaf37a2abc54..3e21d800ee46 100644 --- a/src/qt/multisigdialog.h +++ b/src/qt/multisigdialog.h @@ -47,7 +47,7 @@ public slots: CCoinsViewCache getInputsCoinsViewCache(const std::vector& vin); QString buildMultisigTxStatusString(bool fComplete, const CMutableTransaction& tx); bool createRedeemScript(int m, std::vector keys, CScript& redeemRet, std::string& errorRet); - bool createMultisigTransaction(std::vector vUserIn, std::vector vUserOut, string& feeStringRet, string& errorRet); + bool createMultisigTransaction(std::vector vUserIn, std::vector vUserOut, std::string& feeStringRet, std::string& errorRet); bool signMultisigTx(CMutableTransaction& txToSign, std::string& errorMessageRet, QVBoxLayout* keyList = nullptr); bool addMultisig(int m, std::vector keys); bool isFullyVerified(CMutableTransaction& txToVerify); diff --git a/src/qt/obfuscationconfig.cpp b/src/qt/obfuscationconfig.cpp deleted file mode 100644 index b35683536b97..000000000000 --- a/src/qt/obfuscationconfig.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "obfuscationconfig.h" -#include "ui_obfuscationconfig.h" - -#include "bitcoinunits.h" -#include "guiconstants.h" -#include "init.h" -#include "optionsmodel.h" -#include "walletmodel.h" - -#include -#include -#include -#include - -ObfuscationConfig::ObfuscationConfig(QWidget* parent) : QDialog(parent), - ui(new Ui::ObfuscationConfig), - model(0) -{ - ui->setupUi(this); - - connect(ui->buttonBasic, SIGNAL(clicked()), this, SLOT(clickBasic())); - connect(ui->buttonHigh, SIGNAL(clicked()), this, SLOT(clickHigh())); - connect(ui->buttonMax, SIGNAL(clicked()), this, SLOT(clickMax())); -} - -ObfuscationConfig::~ObfuscationConfig() -{ - delete ui; -} - -void ObfuscationConfig::setModel(WalletModel* model) -{ - this->model = model; -} - -void ObfuscationConfig::clickBasic() -{ - configure(true, 1000, 2); - - QString strAmount(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 1000 * COIN)); - QMessageBox::information(this, tr("Obfuscation Configuration"), - tr( - "Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Phore's configuration screen.") - .arg(strAmount)); - - close(); -} - -void ObfuscationConfig::clickHigh() -{ - configure(true, 1000, 8); - - QString strAmount(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 1000 * COIN)); - QMessageBox::information(this, tr("Obfuscation Configuration"), - tr( - "Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Phore's configuration screen.") - .arg(strAmount)); - - close(); -} - -void ObfuscationConfig::clickMax() -{ - configure(true, 1000, 16); - - QString strAmount(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 1000 * COIN)); - QMessageBox::information(this, tr("Obfuscation Configuration"), - tr( - "Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Phore's configuration screen.") - .arg(strAmount)); - - close(); -} - -void ObfuscationConfig::configure(bool enabled, int coins, int rounds) -{ - QSettings settings; - - settings.setValue("nObfuscationRounds", rounds); - settings.setValue("nAnonymizePhoreAmount", coins); - - nZeromintPercentage = rounds; - nAnonymizePhoreAmount = coins; -} diff --git a/src/qt/obfuscationconfig.h b/src/qt/obfuscationconfig.h deleted file mode 100644 index c9236d1ae1ea..000000000000 --- a/src/qt/obfuscationconfig.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef OBFUSCATIONCONFIG_H -#define OBFUSCATIONCONFIG_H - -#include - -namespace Ui -{ -class ObfuscationConfig; -} -class WalletModel; - -/** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase. - */ -class ObfuscationConfig : public QDialog -{ - Q_OBJECT - -public: - ObfuscationConfig(QWidget* parent = 0); - ~ObfuscationConfig(); - - void setModel(WalletModel* model); - - -private: - Ui::ObfuscationConfig* ui; - WalletModel* model; - void configure(bool enabled, int coins, int rounds); - -private slots: - - void clickBasic(); - void clickHigh(); - void clickMax(); -}; - -#endif // OBFUSCATIONCONFIG_H diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index 5846ebba1c01..2e22f2303799 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -13,14 +13,11 @@ #include -OpenURIDialog::OpenURIDialog(QWidget* parent) : QDialog(parent), +OpenURIDialog::OpenURIDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::OpenURIDialog) { ui->setupUi(this); - ui->uriEdit->setAttribute(Qt::WA_MacShowFocusRect, 0); -#if QT_VERSION >= 0x040700 ui->uriEdit->setPlaceholderText("phore:"); -#endif } OpenURIDialog::~OpenURIDialog() diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ba0bf1570e48..8b8a18cf17b0 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -31,7 +31,7 @@ #include #include -OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(parent), +OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::OptionsDialog), model(0), mapper(0), @@ -102,7 +102,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren digits.setNum(index); ui->digits->addItem(digits, digits); } - + /* Theme selector static themes */ ui->theme->addItem(QString("Default"), QVariant("default")); @@ -135,27 +135,18 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren QLocale locale(langStr); /** check if the locale name consists of 2 parts (language_country) */ - if (langStr.contains("_")) { -#if QT_VERSION >= 0x040800 + if(langStr.contains("_")) + { /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */ ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#else - /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */ - ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#endif - } else { -#if QT_VERSION >= 0x040800 + } + else + { /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */ ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#else - /** display language strings as "language (locale name)", e.g. "German (de)" */ - ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#endif } } -#if QT_VERSION >= 0x040700 ui->thirdPartyTxUrls->setPlaceholderText("https://example.com/tx/%s"); -#endif ui->unit->setModel(new BitcoinUnits(this)); @@ -191,6 +182,9 @@ void OptionsDialog::setModel(OptionsModel* model) mapper->setModel(model); setMapper(); mapper->toFirst(); + + /* keep consistency for action triggered elsewhere */ + connect(model, SIGNAL(hideOrphansChanged(bool)), this, SLOT(updateHideOrphans(bool))); } /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */ @@ -251,6 +245,7 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->unit, OptionsModel::DisplayUnit); mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls); mapper->addMapping(ui->checkBoxHideZeroBalances, OptionsModel::HideZeroBalances); + mapper->addMapping(ui->checkBoxHideOrphans, OptionsModel::HideOrphans); /* Masternode Tab */ mapper->addMapping(ui->showMasternodesTab, OptionsModel::ShowMasternodesTab); @@ -293,7 +288,6 @@ void OptionsDialog::on_resetButton_clicked() void OptionsDialog::on_okButton_clicked() { mapper->submit(); - obfuScationPool.cachedNumBlocks = std::numeric_limits::max(); pwalletMain->MarkDirty(); accept(); } @@ -322,6 +316,12 @@ void OptionsDialog::clearStatusLabel() ui->statusLabel->clear(); } +void OptionsDialog::updateHideOrphans(bool fHide) +{ + if(ui->checkBoxHideOrphans->isChecked() != fHide) + ui->checkBoxHideOrphans->setChecked(fHide); +} + void OptionsDialog::doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort) { const std::string strAddrProxy = pUiProxyIp->text().toStdString(); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index de043c857d2a..85c5234620c0 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -46,6 +46,8 @@ private slots: void on_okButton_clicked(); void on_cancelButton_clicked(); + void updateHideOrphans(bool fHide); + void showRestartWarning(bool fPersistent = false); void clearStatusLabel(); void doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 2a75fc613f35..f0d8bef368bd 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -73,6 +73,10 @@ void OptionsModel::Init() settings.setValue("fHideZeroBalances", true); fHideZeroBalances = settings.value("fHideZeroBalances").toBool(); + if (!settings.contains("fHideOrphans")) + settings.setValue("fHideOrphans", false); + fHideOrphans = settings.value("fHideOrphans").toBool(); + if (!settings.contains("fCoinControlFeatures")) settings.setValue("fCoinControlFeatures", false); fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool(); @@ -89,11 +93,6 @@ void OptionsModel::Init() settings.setValue("nPreferredDenom", 0); nPreferredDenom = settings.value("nPreferredDenom", "0").toLongLong(); - if (!settings.contains("nAnonymizePhoreAmount")) - settings.setValue("nAnonymizePhoreAmount", 1000); - - nAnonymizePhoreAmount = settings.value("nAnonymizePhoreAmount").toLongLong(); - if (!settings.contains("fShowMasternodesTab")) settings.setValue("fShowMasternodesTab", masternodeConfig.getCount()); @@ -252,14 +251,14 @@ QVariant OptionsModel::data(const QModelIndex& index, int role) const return settings.value("nThreadsScriptVerif"); case HideZeroBalances: return settings.value("fHideZeroBalances"); + case HideOrphans: + return settings.value("fHideOrphans"); case ZeromintEnable: return QVariant(fEnableZeromint); case ZeromintPercentage: return QVariant(nZeromintPercentage); case ZeromintPrefDenom: return QVariant(nPreferredDenom); - case AnonymizePhoreAmount: - return QVariant(nAnonymizePhoreAmount); case Listen: return settings.value("fListen"); default: @@ -387,11 +386,10 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int settings.setValue("fHideZeroBalances", fHideZeroBalances); emit hideZeroBalancesChanged(fHideZeroBalances); break; - - case AnonymizePhoreAmount: - nAnonymizePhoreAmount = value.toInt(); - settings.setValue("nAnonymizePhoreAmount", nAnonymizePhoreAmount); - emit anonymizePhoreAmountChanged(nAnonymizePhoreAmount); + case HideOrphans: + fHideOrphans = value.toBool(); + settings.setValue("fHideOrphans", fHideOrphans); + emit hideOrphansChanged(fHideOrphans); break; case CoinControlFeatures: fCoinControlFeatures = value.toBool(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index a517d4c7dc37..55a9fb989020 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -47,6 +47,7 @@ class OptionsModel : public QAbstractListModel ZeromintPercentage, // int ZeromintPrefDenom, // int HideZeroBalances, // bool + HideOrphans, // bool AnonymizePhoreAmount, //int ShowMasternodesTab, // bool Listen, // bool @@ -88,6 +89,7 @@ class OptionsModel : public QAbstractListModel QString strThirdPartyTxUrls; bool fCoinControlFeatures; bool fHideZeroBalances; + bool fHideOrphans; /* settings that were overriden by command-line */ QString strOverriddenByCommandLine; @@ -102,6 +104,7 @@ class OptionsModel : public QAbstractListModel void anonymizePhoreAmountChanged(int); void coinControlFeaturesChanged(bool); void hideZeroBalancesChanged(bool); + void hideOrphansChanged(bool); }; #endif // BITCOIN_QT_OPTIONSMODEL_H diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 01f3683074c5..d8607292b53f 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -14,7 +14,6 @@ #include "guiutil.h" #include "init.h" #include "obfuscation.h" -#include "obfuscationconfig.h" #include "optionsmodel.h" #include "transactionfilterproxy.h" #include "transactionrecord.h" @@ -211,13 +210,20 @@ void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmed nLockedBalance = pwalletMain->GetLockedCoins(); nWatchOnlyLockedBalance = pwalletMain->GetLockedWatchOnlyBalance(); } + // PHR Balance CAmount nTotalBalance = balance + unconfirmedBalance; CAmount phrAvailableBalance = balance - immatureBalance - nLockedBalance; - CAmount nTotalWatchBalance = watchOnlyBalance + watchUnconfBalance + watchImmatureBalance; CAmount nUnlockedBalance = nTotalBalance - nLockedBalance; + + // PHR Watch-Only Balance + CAmount nTotalWatchBalance = watchOnlyBalance + watchUnconfBalance; + CAmount nAvailableWatchBalance = watchOnlyBalance - watchImmatureBalance - nWatchOnlyLockedBalance; + // zPHR Balance + CAmount matureZerocoinBalance = zerocoinBalance - unconfirmedZerocoinBalance - immatureZerocoinBalance; + // Percentages QString szPercentage = ""; QString sPercentage = ""; @@ -234,17 +240,17 @@ void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmed ui->labelTotal->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, nTotalBalance, false, BitcoinUnits::separatorAlways)); // Watchonly labels - ui->labelWatchAvailable->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, watchOnlyBalance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchPending->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, watchUnconfBalance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchImmature->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, watchImmatureBalance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchLocked->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, nWatchOnlyLockedBalance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchTotal->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, nTotalWatchBalance, false, BitcoinUnits::separatorAlways)); + ui->labelWatchAvailable->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nAvailableWatchBalance, false, BitcoinUnits::separatorAlways)); + ui->labelWatchPending->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchUnconfBalance, false, BitcoinUnits::separatorAlways)); + ui->labelWatchImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchImmatureBalance, false, BitcoinUnits::separatorAlways)); + ui->labelWatchLocked->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nWatchOnlyLockedBalance, false, BitcoinUnits::separatorAlways)); + ui->labelWatchTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nTotalWatchBalance, false, BitcoinUnits::separatorAlways)); // zPHR labels - ui->labelzBalance->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, zerocoinBalance, false, BitcoinUnits::separatorAlways)); - ui->labelzBalanceUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, unconfirmedZerocoinBalance, false, BitcoinUnits::separatorAlways)); - ui->labelzBalanceMature->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, matureZerocoinBalance, false, BitcoinUnits::separatorAlways)); - ui->labelzBalanceImmature->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, immatureZerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, zerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalanceUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, unconfirmedZerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalanceMature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, matureZerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalanceImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, immatureZerocoinBalance, false, BitcoinUnits::separatorAlways)); // Combined labels ui->labelBalancez->setText(BitcoinUnits::floorHtmlWithUnitComma(nDisplayUnit, availableTotalBalance, false, BitcoinUnits::separatorAlways)); @@ -370,6 +376,7 @@ void OverviewPage::setWalletModel(WalletModel* model) connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); connect(model->getOptionsModel(), SIGNAL(hideZeroBalancesChanged(bool)), this, SLOT(updateDisplayUnit())); + connect(model->getOptionsModel(), SIGNAL(hideOrphansChanged(bool)), this, SLOT(hideOrphans(bool))); updateWatchOnlyLabels(model->haveWatchOnly()); connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool))); @@ -377,6 +384,10 @@ void OverviewPage::setWalletModel(WalletModel* model) // update the display unit, to not use the default ("PHR") updateDisplayUnit(); + + // Hide orphans + QSettings settings; + hideOrphans(settings.value("fHideOrphans", false).toBool()); } void OverviewPage::updateDisplayUnit() @@ -405,3 +416,9 @@ void OverviewPage::showOutOfSyncWarning(bool fShow) ui->labelWalletStatus->setVisible(fShow); ui->labelTransactionsStatus->setVisible(fShow); } + +void OverviewPage::hideOrphans(bool fHide) +{ + if (filter) + filter->setHideOrphans(fHide); +} diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 9f7ea34da44b..33b92ca70da9 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -40,6 +40,7 @@ public slots: void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); + void hideOrphans(bool fHide); signals: void transactionClicked(const QModelIndex& index); diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index b095329e4c9d..a41363d672a2 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -17,8 +17,6 @@ #include #include -using namespace std; - class SSLVerifyError : public std::runtime_error { public: @@ -46,7 +44,7 @@ bool PaymentRequestPlus::parse(const QByteArray& data) return true; } -bool PaymentRequestPlus::SerializeToString(string* output) const +bool PaymentRequestPlus::SerializeToString(std::string* output) const { return paymentRequest.SerializeToString(output); } @@ -99,14 +97,12 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: " << qCert; return false; } -#if QT_VERSION >= 0x050000 if (qCert.isBlacklisted()) { qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate blacklisted: " << qCert; return false; } -#endif - const unsigned char* data = (const unsigned char*)certChain.certificate(i).data(); - X509* cert = d2i_X509(NULL, &data, certChain.certificate(i).size()); + const unsigned char *data = (const unsigned char *)certChain.certificate(i).data(); + X509 *cert = d2i_X509(nullptr, &data, certChain.certificate(i).size()); if (cert) certs.push_back(cert); } @@ -202,7 +198,7 @@ QList > PaymentRequestPlus::getPayTo() const const unsigned char* scriptStr = (const unsigned char*)details.outputs(i).script().data(); CScript s(scriptStr, scriptStr + details.outputs(i).script().size()); - result.append(make_pair(s, details.outputs(i).amount())); + result.append(std::make_pair(s, details.outputs(i).amount())); } return result; } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 2bf774e9f7bf..9e05191178cf 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -41,15 +41,8 @@ #include #include #include - -#if QT_VERSION < 0x050000 -#include -#else #include -#endif -using namespace boost; -using namespace std; const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds const QString BITCOIN_IPC_PREFIX("phore:"); @@ -106,7 +99,7 @@ static QList savedPaymentRequests; static void ReportInvalidCertificate(const QSslCertificate& cert) { - qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); + qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName); } // @@ -146,12 +139,12 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) ReportInvalidCertificate(cert); continue; } -#if QT_VERSION >= 0x050000 + + // Blacklisted certificate if (cert.isBlacklisted()) { ReportInvalidCertificate(cert); continue; } -#endif QByteArray certData = cert.toDer(); const unsigned char* data = (const unsigned char*)certData.data(); @@ -372,11 +365,7 @@ void PaymentServer::handleURIOrFile(const QString& s) if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // phore: URI { -#if QT_VERSION < 0x050000 - QUrl uri(s); -#else QUrlQuery uri((QUrl(s))); -#endif if (uri.hasQueryItem("r")) // payment request URI { QByteArray temp; diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index aa4595963eb5..bbd4c869730f 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -58,9 +58,8 @@ class PeerTablePriv return; } cachedNodeStats.clear(); -#if QT_VERSION >= 0x040700 + cachedNodeStats.reserve(vNodes.size()); -#endif foreach (CNode* pnode, vNodes) { CNodeCombinedStats stats; stats.nodeStateStats.nMisbehavior = 0; @@ -76,7 +75,7 @@ class PeerTablePriv { TRY_LOCK(cs_main, lockMain); if (lockMain) { - BOOST_FOREACH (CNodeCombinedStats& stats, cachedNodeStats) + for (CNodeCombinedStats& stats : cachedNodeStats) stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats); } } diff --git a/src/qt/phore.cpp b/src/qt/phore.cpp index 2f91809505ed..a3eee4171e30 100644 --- a/src/qt/phore.cpp +++ b/src/qt/phore.cpp @@ -30,8 +30,7 @@ #include "init.h" #include "main.h" -#include "rpcserver.h" -#include "scheduler.h" +#include "rpc/server.h" #include "ui_interface.h" #include "util.h" @@ -58,13 +57,6 @@ #if defined(QT_STATICPLUGIN) #include -#if QT_VERSION < 0x050000 -Q_IMPORT_PLUGIN(qcncodecs) -Q_IMPORT_PLUGIN(qjpcodecs) -Q_IMPORT_PLUGIN(qtwcodecs) -Q_IMPORT_PLUGIN(qkrcodecs) -Q_IMPORT_PLUGIN(qtaccessiblewidgets) -#else #if QT_VERSION < 0x050400 Q_IMPORT_PLUGIN(AccessibleFactory) #endif @@ -76,11 +68,6 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif #endif -#endif - -#if QT_VERSION < 0x050000 -#include -#endif // Declare meta types used for QMetaObject::invokeMethod Q_DECLARE_METATYPE(bool*) @@ -153,20 +140,12 @@ static void initTranslations(QTranslator& qtTranslatorBase, QTranslator& qtTrans } /* qDebug() message handler --> debug.log */ -#if QT_VERSION < 0x050000 -void DebugMessageHandler(QtMsgType type, const char* msg) -{ - const char* category = (type == QtDebugMsg) ? "qt" : NULL; - LogPrint(category, "GUI: %s\n", msg); -} -#else void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) { Q_UNUSED(context); const char* category = (type == QtDebugMsg) ? "qt" : NULL; LogPrint(category, "GUI: %s\n", msg.toStdString()); } -#endif /** Class encapsulating Phore Core startup and shutdown. * Allows running startup and shutdown in a different thread from the UI thread. @@ -188,9 +167,6 @@ public slots: void runawayException(const QString& message); private: - boost::thread_group threadGroup; - CScheduler scheduler; - /// Flag indicating a restart bool execute_restart; @@ -279,7 +255,7 @@ void BitcoinCore::initialize() try { qDebug() << __func__ << ": Running AppInit2 in thread"; - int rv = AppInit2(threadGroup, scheduler, words); + int rv = AppInit2(words); emit initializeResult(rv); } catch (std::exception& e) { handleRunawayException(&e); @@ -294,8 +270,7 @@ void BitcoinCore::restart(QStringList args) execute_restart = false; try { qDebug() << __func__ << ": Running Restart in thread"; - Interrupt(threadGroup); - threadGroup.join_all(); + Interrupt(); PrepareShutdown(); qDebug() << __func__ << ": Shutdown finished"; emit shutdownResult(1); @@ -315,8 +290,7 @@ void BitcoinCore::shutdown() { try { qDebug() << __func__ << ": Running Shutdown in thread"; - Interrupt(threadGroup); - threadGroup.join_all(); + Interrupt(); Shutdown(); qDebug() << __func__ << ": Shutdown finished"; emit shutdownResult(1); @@ -554,12 +528,6 @@ int main(int argc, char* argv[]) // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory /// 2. Basic Qt initialization (not dependent on parameters or configuration) -#if QT_VERSION < 0x050000 - // Internal string conversion is all UTF-8 - QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); - QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); -#endif - Q_INIT_RESOURCE(phore_locale); Q_INIT_RESOURCE(phore); @@ -664,17 +632,12 @@ int main(int argc, char* argv[]) /// 9. Main GUI initialization // Install global event filter that makes sure that long tooltips can be word-wrapped app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); -#if QT_VERSION < 0x050000 - // Install qDebug() message handler to route to debug.log - qInstallMsgHandler(DebugMessageHandler); -#else #if defined(Q_OS_WIN) // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION) qApp->installNativeEventFilter(new WinShutdownMonitor()); #endif // Install qDebug() message handler to route to debug.log qInstallMessageHandler(DebugMessageHandler); -#endif // Load GUI settings from QSettings app.createOptionsModel(); @@ -689,7 +652,7 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } app.requestInitialize(); -#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 +#if defined(Q_OS_WIN) WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Phore Core didn't yet exit safely..."), (HWND)app.getMainWinId()); #endif app.exec(); diff --git a/src/qt/phore.qrc b/src/qt/phore.qrc index 5e00f9707734..bdc78d01b6e8 100644 --- a/src/qt/phore.qrc +++ b/src/qt/phore.qrc @@ -66,6 +66,8 @@ res/icons/staking_inactive.png res/icons/hd_enabled.png res/icons/hd_disabled.png + res/icons/explorer.png + res/icons/onion.png res/css/default.css diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp index b92b6d4edde1..1df70161ab53 100644 --- a/src/qt/privacydialog.cpp +++ b/src/qt/privacydialog.cpp @@ -24,7 +24,7 @@ #include #include -PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent), +PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowCloseButtonHint), ui(new Ui::PrivacyDialog), walletModel(0), currentBalance(-1) @@ -198,8 +198,8 @@ void PrivacyDialog::on_pushButtonMintzPHR_clicked() int64_t nTime = GetTimeMillis(); CWalletTx wtx; - vector vMints; - string strError = pwalletMain->MintZerocoin(nAmount, wtx, vMints, CoinControlDialog::coinControl); + std::vector vMints; + std::string strError = pwalletMain->MintZerocoin(nAmount, wtx, vMints, CoinControlDialog::coinControl); // Return if something went wrong during minting if (strError != ""){ @@ -243,7 +243,7 @@ void PrivacyDialog::on_pushButtonMintReset_clicked() ui->TEMintStatus->repaint (); int64_t nTime = GetTimeMillis(); - string strResetMintResult = pwalletMain->ResetMintZerocoin(); // do not do the extended search from GUI + std::string strResetMintResult = pwalletMain->ResetMintZerocoin(); // do not do the extended search from GUI double fDuration = (double)(GetTimeMillis() - nTime)/1000.0; ui->TEMintStatus->setPlainText(QString::fromStdString(strResetMintResult) + tr("Duration: ") + QString::number(fDuration) + tr(" sec.\n")); ui->TEMintStatus->repaint (); @@ -257,7 +257,7 @@ void PrivacyDialog::on_pushButtonSpentReset_clicked() ui->TEMintStatus->setPlainText(tr("Starting ResetSpentZerocoin: ")); ui->TEMintStatus->repaint (); int64_t nTime = GetTimeMillis(); - string strResetSpentResult = pwalletMain->ResetSpentZerocoin(); + std::string strResetSpentResult = pwalletMain->ResetSpentZerocoin(); double fDuration = (double)(GetTimeMillis() - nTime)/1000.0; ui->TEMintStatus->setPlainText(QString::fromStdString(strResetSpentResult) + tr("Duration: ") + QString::number(fDuration) + tr(" sec.\n")); ui->TEMintStatus->repaint (); @@ -413,8 +413,8 @@ void PrivacyDialog::sendzPHR() ui->TEMintStatus->repaint(); // use mints from zPHR selector if applicable - vector vMintsToFetch; - vector vMintsSelected; + std::vector vMintsToFetch; + std::vector vMintsSelected; if (!ZPhrControlDialog::setSelectedMints.empty()) { vMintsToFetch = ZPhrControlDialog::GetSelectedMints(); @@ -616,13 +616,13 @@ void PrivacyDialog::setBalance(const CAmount& balance, const CAmount& unconfirme std::map mapUnconfirmed; std::map mapImmature; for (const auto& denom : libzerocoin::zerocoinDenomList){ - mapDenomBalances.insert(make_pair(denom, 0)); - mapUnconfirmed.insert(make_pair(denom, 0)); - mapImmature.insert(make_pair(denom, 0)); + mapDenomBalances.insert(std::make_pair(denom, 0)); + mapUnconfirmed.insert(std::make_pair(denom, 0)); + mapImmature.insert(std::make_pair(denom, 0)); } std::vector vMints = pwalletMain->zphrTracker->GetMints(false); - map mapMaturityHeights = GetMintMaturityHeight(); + std::map mapMaturityHeights = GetMintMaturityHeight(); for (CMintMeta& meta : vMints){ // All denominations mapUnconfirmed.at(meta.denom)++; diff --git a/src/qt/proposaldialog.cpp b/src/qt/proposaldialog.cpp index 22bf6c091cf4..f4aca0611218 100644 --- a/src/qt/proposaldialog.cpp +++ b/src/qt/proposaldialog.cpp @@ -14,6 +14,7 @@ #include #include #include +#include "chainparams.h" #include #include #include @@ -84,7 +85,7 @@ ProposalDialog::ProposalDialog(Mode mode, QWidget* parent) : QDialog(parent), ui // Load next superblock number. CBlockIndex* pindexPrev = chainActive.Tip(); if (!pindexPrev) return; - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); ui->blockEdit->setText(QString::number(nNext)); // Start periodic updates to handle submit block depth validation. @@ -204,7 +205,7 @@ void ProposalDialog::submitProposal() return; } - budget.mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); + budget.mapSeenMasternodeBudgetProposals.insert(std::make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); budgetProposalBroadcast.Relay(); this->accept(); @@ -228,17 +229,17 @@ bool ProposalDialog::validateProposal() // Start must be in the next budget cycle int nBlockMin = 0; CBlockIndex* pindexPrev = chainActive.Tip(); - if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); int nBlockStart = ui->blockEdit->text().toInt(); if (nBlockStart < nBlockMin) strError = "Invalid block start, must be more than current height."; - if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) + if (nBlockStart % Params().GetBudgetCycleBlocks() != 0) { - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); strError = strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext); } - int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks() * nPaymentCount); // End must be AFTER current cycle + int nBlockEnd = nBlockStart + (Params().GetBudgetCycleBlocks() * nPaymentCount); // End must be AFTER current cycle if (nBlockEnd < pindexPrev->nHeight) strError = "Invalid ending block, starting block + (payment_cycle*payments) must be more than current height."; std::string address = ui->addressEdit->text().toStdString(); @@ -285,7 +286,7 @@ void ProposalDialog::on_acceptButton_clicked() { prepareProposal(); } - else if (mode == SubmitProposal) + else if (mode == SubmitProposal) { submitProposal(); } diff --git a/src/qt/proposallist.cpp b/src/qt/proposallist.cpp index e2e44a257d39..74b11f9f88f6 100644 --- a/src/qt/proposallist.cpp +++ b/src/qt/proposallist.cpp @@ -20,11 +20,11 @@ #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "ui_interface.h" #include "utilmoneystr.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "util.h" #include @@ -468,10 +468,10 @@ void ProposalList::vote_click_handler(const std::string voteString) int success = 0; int failed = 0; - std::string strVote = voteString; - int nVote = VOTE_ABSTAIN; - if (strVote == "yes") nVote = VOTE_YES; - if (strVote == "no") nVote = VOTE_NO; + std::string strVote = voteString; + int nVote = VOTE_ABSTAIN; + if (strVote == "yes") nVote = VOTE_YES; + if (strVote == "no") nVote = VOTE_NO; for (const auto& mne : masternodeConfig.getEntries()) { @@ -506,7 +506,7 @@ void ProposalList::vote_click_handler(const std::string voteString) std::string strError = ""; if (budget.UpdateProposal(vote, NULL, strError)) { - budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); success++; } else { diff --git a/src/qt/proposaltablemodel.cpp b/src/qt/proposaltablemodel.cpp index 77ddb1897d0c..0d81d5fd494f 100644 --- a/src/qt/proposaltablemodel.cpp +++ b/src/qt/proposaltablemodel.cpp @@ -14,7 +14,7 @@ #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "obfuscation.h" //#include "governance-vote.h" @@ -82,7 +82,7 @@ void budgetToST(CBudgetProposal* pbudgetProposal, UniValue& bObj) bObj.push_back(pbudgetProposal->GetNays()); bObj.push_back(pbudgetProposal->GetAbstains()); bObj.push_back(ValueFromAmount(pbudgetProposal->GetAmount() * pbudgetProposal->GetTotalPaymentCount())); - bObj.push_back(pbudgetProposal->GetAmount()); + bObj.push_back(pbudgetProposal->GetAmount()); bObj.push_back(pbudgetProposal->IsEstablished()); std::string strError = ""; @@ -128,8 +128,8 @@ void ProposalTableModel::refreshProposals() //std::vector arr2 = arr1.at( 0 ).getValues(); //dataObj = arr2.at( 1 ); - UniValue bObj(UniValue::VOBJ); - budgetToST(pbudgetProposal, bObj); + UniValue bObj(UniValue::VOBJ); + budgetToST(pbudgetProposal, bObj); int votesNeeded = 0; int voteGap = 0; diff --git a/src/qt/proposaltablemodel.h b/src/qt/proposaltablemodel.h index 8a259e68b3d2..8ccc0fd4740e 100644 --- a/src/qt/proposaltablemodel.h +++ b/src/qt/proposaltablemodel.h @@ -23,7 +23,7 @@ #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "obfuscation.h" diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 9ecfd7df354e..44812be81363 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -22,7 +22,7 @@ #include #include -ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : QDialog(parent), +ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::ReceiveCoinsDialog), model(0) { @@ -53,18 +53,21 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : QDialog(parent), QAction* copyLabelAction = new QAction(tr("Copy label"), this); QAction* copyMessageAction = new QAction(tr("Copy message"), this); QAction* copyAmountAction = new QAction(tr("Copy amount"), this); + QAction* copyAddressAction = new QAction(tr("Copy address"), this); // context menu contextMenu = new QMenu(); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyMessageAction); contextMenu->addAction(copyAmountAction); + contextMenu->addAction(copyAddressAction); // context menu signals connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage())); connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); } @@ -274,3 +277,9 @@ void ReceiveCoinsDialog::copyAmount() { copyColumnToClipboard(RecentRequestsTableModel::Amount); } + +// context menu action: copy address +void ReceiveCoinsDialog::copyAddress() +{ + copyColumnToClipboard(RecentRequestsTableModel::Address); +} diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index fc1def23f9d1..fcbfcf40f257 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -72,6 +72,7 @@ private slots: void copyLabel(); void copyMessage(); void copyAmount(); + void copyAddress(); }; #endif // BITCOIN_QT_RECEIVECOINSDIALOG_H diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index b34f9ecf2fc2..78f846766f3f 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -17,9 +17,6 @@ #include #include #include -#if QT_VERSION < 0x050000 -#include -#endif #if defined(HAVE_CONFIG_H) #include "config/phore-config.h" /* for USE_QRCODE */ @@ -86,7 +83,7 @@ void QRImageWidget::contextMenuEvent(QContextMenuEvent* event) contextMenu->exec(event->globalPos()); } -ReceiveRequestDialog::ReceiveRequestDialog(QWidget* parent) : QDialog(parent), +ReceiveRequestDialog::ReceiveRequestDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::ReceiveRequestDialog), model(0) { diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 96f6881986ad..053d8a44c163 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -10,7 +10,7 @@ #include "optionsmodel.h" #include "streams.h" -#include + RecentRequestsTableModel::RecentRequestsTableModel(CWallet* wallet, WalletModel* parent) : walletModel(parent) { @@ -20,11 +20,11 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet* wallet, WalletModel* // Load entries from wallet std::vector vReceiveRequests; parent->loadReceiveRequests(vReceiveRequests); - BOOST_FOREACH (const std::string& request, vReceiveRequests) + for (const std::string& request : vReceiveRequests) addNewRequest(request); /* These columns must match the indices in the ColumnIndex enumeration */ - columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle(); + columns << tr("Date") << tr("Label") << tr("Address") << tr("Message") << getAmountTitle(); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); } @@ -65,6 +65,8 @@ QVariant RecentRequestsTableModel::data(const QModelIndex& index, int role) cons } else { return rec->recipient.label; } + case Address: + return rec->recipient.address; case Message: if (rec->recipient.message.isEmpty() && role == Qt::DisplayRole) { return tr("(no message)"); @@ -217,6 +219,8 @@ bool RecentRequestEntryLessThan::operator()(RecentRequestEntry& left, RecentRequ return pLeft->date.toTime_t() < pRight->date.toTime_t(); case RecentRequestsTableModel::Label: return pLeft->recipient.label < pRight->recipient.label; + case RecentRequestsTableModel::Address: + return pLeft->recipient.address < pRight->recipient.address; case RecentRequestsTableModel::Message: return pLeft->recipient.message < pRight->recipient.message; case RecentRequestsTableModel::Amount: diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index 6448856ed665..80afb7c3dcfe 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -67,8 +67,9 @@ class RecentRequestsTableModel : public QAbstractTableModel enum ColumnIndex { Date = 0, Label = 1, - Message = 2, - Amount = 3, + Address = 2, + Message = 3, + Amount = 4, NUMBER_OF_COLUMNS }; diff --git a/src/qt/res/icons/onion.png b/src/qt/res/icons/onion.png new file mode 100644 index 000000000000..bc7edfcc7638 Binary files /dev/null and b/src/qt/res/icons/onion.png differ diff --git a/src/qt/res/phore-qt-res.rc b/src/qt/res/phore-qt-res.rc index b8ac1dc74a4f..fdbf8520bfa8 100644 --- a/src/qt/res/phore-qt-res.rc +++ b/src/qt/res/phore-qt-res.rc @@ -2,7 +2,7 @@ IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico" IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico" #include // needed for VERSIONINFO -#include "../../clientversion.h" // holds the needed client version information +#include "../clientversion.h" // holds the needed client version information #define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD #define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 7fbab9ff6979..70a7d4f185f4 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -14,8 +14,8 @@ #include "chainparams.h" #include "main.h" -#include "rpcclient.h" -#include "rpcserver.h" +#include "rpc/client.h" +#include "rpc/server.h" #include "util.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -39,10 +39,6 @@ #include #include -#if QT_VERSION < 0x050000 -#include -#endif - // TODO: add a scrollback limit, as there is currently none // TODO: make it possible to filter out categories (esp debug messages when implemented) // TODO: receive errors and debug messages through ClientModel @@ -258,7 +254,7 @@ void RPCExecutor::request(const QString& command) } } -RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent), +RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::RPCConsole), clientModel(0), historyPtr(0), @@ -323,7 +319,9 @@ RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent), #endif // Register RPC timer interface rpcTimerInterface = new QtRPCTimerInterface(); - RPCRegisterTimerInterface(rpcTimerInterface); + // avoid accidentally overwriting an existing, non QTThread + // based timer interface + RPCSetTimerInterfaceIfUnset(rpcTimerInterface); startExecutor(); setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS); @@ -337,7 +335,7 @@ RPCConsole::~RPCConsole() { GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); emit stopExecutor(); - RPCUnregisterTimerInterface(rpcTimerInterface); + RPCUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete ui; } @@ -493,6 +491,7 @@ void RPCConsole::setClientModel(ClientModel* model) ui->clientVersion->setText(model->formatFullVersion()); ui->clientName->setText(model->clientName()); ui->buildDate->setText(model->formatBuildDate()); + ui->dataDir->setText(model->dataDir()); ui->startupTime->setText(model->formatClientStartupTime()); ui->networkName->setText(QString::fromStdString(Params().NetworkIDString())); @@ -678,8 +677,10 @@ void RPCConsole::setNumConnections(int count) void RPCConsole::setNumBlocks(int count) { ui->numberOfBlocks->setText(QString::number(count)); - if (clientModel) + if (clientModel) { ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString()); + ui->lastBlockHash->setText(clientModel->getLastBlockHash()); + } } void RPCConsole::setMasternodeCount(const QString& strMasternodes) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 3ff1a86725df..76606f10e2be 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -28,7 +28,7 @@ #include #include -SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent), +SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::SendCoinsDialog), clientModel(0), model(0), @@ -137,7 +137,10 @@ SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent), ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool()); ui->checkzPHR->hide(); + minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); + // If SwiftX activated hide button 'Choose'. Show otherwise. + ui->buttonChooseFee->setVisible(!useSwiftTX); } void SendCoinsDialog::setClientModel(ClientModel* clientModel) @@ -581,9 +584,26 @@ void SendCoinsDialog::updateDisplayUnit() void SendCoinsDialog::updateSwiftTX() { + bool useSwiftTX = ui->checkSwiftTX->isChecked(); + QSettings settings; - settings.setValue("bUseSwiftTX", ui->checkSwiftTX->isChecked()); - CoinControlDialog::coinControl->useSwiftTX = ui->checkSwiftTX->isChecked(); + settings.setValue("bUseSwiftTX", useSwiftTX); + CoinControlDialog::coinControl->useSwiftTX = useSwiftTX; + + // If SwiftX activated + if (useSwiftTX) { + // minimize the Fee Section (if open) + minimizeFeeSection(true); + // set the slider to the max + ui->sliderSmartFee->setValue(24); + } + + // If SwiftX activated hide button 'Choose'. Show otherwise. + ui->buttonChooseFee->setVisible(!useSwiftTX); + + // Update labels and controls + updateFeeSectionControls(); + updateSmartFeeLabel(); coinControlUpdateLabels(); } @@ -683,7 +703,7 @@ void SendCoinsDialog::setMinimumFee() void SendCoinsDialog::updateFeeSectionControls() { - ui->sliderSmartFee->setEnabled(ui->radioSmartFee->isChecked()); + ui->sliderSmartFee->setEnabled(ui->radioSmartFee->isChecked() && !ui->checkSwiftTX->isChecked()); ui->labelSmartFee->setEnabled(ui->radioSmartFee->isChecked()); ui->labelSmartFee2->setEnabled(ui->radioSmartFee->isChecked()); ui->labelSmartFee3->setEnabled(ui->radioSmartFee->isChecked()); @@ -716,7 +736,9 @@ void SendCoinsDialog::updateFeeMinimizedLabel() if (!model || !model->getOptionsModel()) return; - if (ui->radioSmartFee->isChecked()) + if (ui->checkSwiftTX->isChecked()) { + ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 1000000)); + } else if (ui->radioSmartFee->isChecked()) ui->labelFeeMinimized->setText(ui->labelSmartFee->text()); else { ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + @@ -737,7 +759,12 @@ void SendCoinsDialog::updateSmartFeeLabel() int nBlocksToConfirm = (int)25 - (int)std::max(0, std::min(24, ui->sliderSmartFee->value())); CFeeRate feeRate = mempool.estimateFee(nBlocksToConfirm); - if (feeRate <= CFeeRate(0)) // not enough data => minfee + // if SwiftX checked, display it in the label + if (ui->checkSwiftTX->isChecked()) + { + ui->labelFeeEstimation->setText(tr("Estimated to get 6 confirmations near instantly with SwiftX!")); + ui->labelSmartFee2->hide(); + } else if (feeRate <= CFeeRate(0)) // not enough data => minfee { ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB"); ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 15b4ab91916b..091fbc0b7313 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -31,9 +31,7 @@ SendCoinsEntry::SendCoinsEntry(QWidget* parent) : QStackedWidget(parent), ui->addAsLabel->setAttribute(Qt::WA_MacShowFocusRect, 0); ui->payAmount->setAttribute(Qt::WA_MacShowFocusRect, 0); #endif -#if QT_VERSION >= 0x040700 ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); -#endif // normal phore address field GUIUtil::setupAddressWidget(ui->payTo, this); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 1293933c5152..cefc0f07055a 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -21,15 +21,13 @@ #include -SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget* parent) : QDialog(parent), +SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::SignVerifyMessageDialog), model(0) { ui->setupUi(this); -#if QT_VERSION >= 0x040700 ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature")); -#endif GUIUtil::setupAddressWidget(ui->addressIn_SM, this); GUIUtil::setupAddressWidget(ui->addressIn_VM, this); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index e9a869fd1911..2efc88aed36a 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -22,13 +22,21 @@ #include -#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000 +#if defined(QT_STATICPLUGIN) #include -Q_IMPORT_PLUGIN(qcncodecs) -Q_IMPORT_PLUGIN(qjpcodecs) -Q_IMPORT_PLUGIN(qtwcodecs) -Q_IMPORT_PLUGIN(qkrcodecs) +#if defined(QT_QPA_PLATFORM_MINIMAL) +Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin); #endif +#if defined(QT_QPA_PLATFORM_XCB) +Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_WINDOWS) +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_COCOA) +Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); +#endif +#endif + +extern void noui_connect(); // This is all you need to run all the tests int main(int argc, char *argv[]) diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 293dfa98bf53..ee018f1dd8a9 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -23,7 +23,6 @@ #include #include -using namespace std; QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) { @@ -159,7 +158,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // Coinbase // CAmount nUnmatured = 0; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) nUnmatured += wallet->GetCredit(txout, ISMINE_ALL); strHTML += "" + tr("Credit") + ": "; if (wtx.IsInMainChain()) @@ -174,13 +173,13 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "
"; } else { isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { isminetype mine = wallet->IsMine(txin); if (fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { isminetype mine = wallet->IsMine(txout); if (fAllToMe > mine) fAllToMe = mine; } @@ -192,7 +191,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // // Debit // - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { // Ignore change isminetype toSelf = wallet->IsMine(txout); if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE)) @@ -234,10 +233,10 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // // Mixed debit transaction // - BOOST_FOREACH (const CTxIn& txin, wtx.vin) + for (const CTxIn& txin : wtx.vin) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (wallet->IsMine(txout)) strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
"; } @@ -257,14 +256,14 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
"; // Message from normal phore:URI (phore:XyZ...?message=example) - foreach (const PAIRTYPE(string, string) & r, wtx.vOrderForm) + foreach (const PAIRTYPE(std::string, std::string) & r, wtx.vOrderForm) if (r.first == "Message") strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(r.second, true) + "
"; // // PaymentRequest info: // - foreach (const PAIRTYPE(string, string) & r, wtx.vOrderForm) { + foreach (const PAIRTYPE(std::string, std::string) & r, wtx.vOrderForm) { if (r.first == "PaymentRequest") { PaymentRequestPlus req; req.parse(QByteArray::fromRawData(r.second.data(), r.second.size())); @@ -284,10 +283,10 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // if (fDebug) { strHTML += "

" + tr("Debug information") + "

"; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) + for (const CTxIn& txin : wtx.vin) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (wallet->IsMine(txout)) strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
"; @@ -297,7 +296,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco strHTML += "
" + tr("Inputs") + ":"; strHTML += "
    "; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { COutPoint prevout = txin.prevout; CCoins prev; diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp index 058369af4239..054a0a6f1ba1 100644 --- a/src/qt/transactiondescdialog.cpp +++ b/src/qt/transactiondescdialog.cpp @@ -12,7 +12,7 @@ #include #include -TransactionDescDialog::TransactionDescDialog(const QModelIndex& idx, QWidget* parent) : QDialog(parent), +TransactionDescDialog::TransactionDescDialog(const QModelIndex& idx, QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::TransactionDescDialog) { ui->setupUi(this); diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 6f3991cb9c92..1ff098453b95 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -24,7 +24,8 @@ TransactionFilterProxy::TransactionFilterProxy(QObject* parent) : QSortFilterPro watchOnlyFilter(WatchOnlyFilter_All), minAmount(0), limitRows(-1), - showInactive(true) + showInactive(true), + fHideOrphans(false) { } @@ -42,6 +43,8 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex& if (!showInactive && status == TransactionStatus::Conflicted) return false; + if (fHideOrphans && isOrphan(status, type)) + return false; if (!(TYPE(type) & typeFilter)) return false; if (involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_No) @@ -100,6 +103,12 @@ void TransactionFilterProxy::setShowInactive(bool showInactive) invalidateFilter(); } +void TransactionFilterProxy::setHideOrphans(bool fHide) +{ + this->fHideOrphans = fHide; + invalidateFilter(); +} + int TransactionFilterProxy::rowCount(const QModelIndex& parent) const { if (limitRows != -1) { @@ -108,3 +117,10 @@ int TransactionFilterProxy::rowCount(const QModelIndex& parent) const return QSortFilterProxyModel::rowCount(parent); } } + +bool TransactionFilterProxy::isOrphan(const int status, const int type) +{ + return ( (type == TransactionRecord::Generated || type == TransactionRecord::StakeMint || + type == TransactionRecord::MNReward) + && (status == TransactionStatus::Conflicted || status == TransactionStatus::NotAccepted) ); +} diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 56824b5f1df8..25db4c325a29 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -50,7 +50,11 @@ class TransactionFilterProxy : public QSortFilterProxyModel /** Set whether to show conflicted transactions. */ void setShowInactive(bool showInactive); + /** Set whether to hide orphan stakes. */ + void setHideOrphans(bool fHide); + int rowCount(const QModelIndex& parent = QModelIndex()) const; + static bool isOrphan(const int status, const int type); protected: bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; @@ -64,6 +68,7 @@ class TransactionFilterProxy : public QSortFilterProxyModel CAmount minAmount; int limitRows; bool showInactive; + bool fHideOrphans; }; #endif // BITCOIN_QT_TRANSACTIONFILTERPROXY_H diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 7399910b6135..46ac18e153c1 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -98,7 +98,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* continue; } - string strAddress = ""; + std::string strAddress = ""; CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) strAddress = EncodeDestination(address); @@ -141,7 +141,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* // // Credit // - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { isminetype mine = wallet->IsMine(txout); if (mine) { TransactionRecord sub(hash, nTime); @@ -171,7 +171,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* int nFromMe = 0; bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { if (wallet->IsMine(txin)) { fAllFromMeDenom = fAllFromMeDenom && wallet->IsDenominated(txin); nFromMe++; @@ -184,7 +184,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* isminetype fAllToMe = ISMINE_SPENDABLE; bool fAllToMeDenom = true; int nToMe = 0; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { if (wallet->IsMine(txout)) { fAllToMeDenom = fAllToMeDenom && wallet->IsDenominatedAmount(txout.nValue); nToMe++; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index e54ab1f3dbfc..d3837451ac75 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -488,7 +488,7 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord* wtx) return QIcon(":/icons/transaction_conflicted"); case TransactionStatus::Immature: { int total = wtx->status.depth + wtx->status.matures_in; - int part = (wtx->status.depth * 4 / total) + 1; + int part = (wtx->status.depth * 5 / total) + 1; return QIcon(QString(":/icons/transaction_%1").arg(part)); } case TransactionStatus::MaturesWarning: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 3ce15267c43d..c77fd281dca4 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -88,7 +88,7 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) | TransactionFilterProxy::TYPE(TransactionRecord::SendToOther)); /* Obsolete Obfuscation entries. Remove once the corresponding TYPES are removed: - * + * typeWidget->addItem(tr("Obfuscated"), TransactionFilterProxy::TYPE(TransactionRecord::Obfuscated)); typeWidget->addItem(tr("Obfuscation Make Collateral Inputs"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationMakeCollaterals)); typeWidget->addItem(tr("Obfuscation Create Denominations"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationCreateDenominations)); @@ -111,17 +111,11 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t hlayout->addWidget(typeWidget); addressWidget = new QLineEdit(this); - addressWidget->setAttribute(Qt::WA_MacShowFocusRect, 0); -#if QT_VERSION >= 0x040700 addressWidget->setPlaceholderText(tr("Enter address or label to search")); -#endif hlayout->addWidget(addressWidget); amountWidget = new QLineEdit(this); - amountWidget->setAttribute(Qt::WA_MacShowFocusRect, 0); -#if QT_VERSION >= 0x040700 amountWidget->setPlaceholderText(tr("Min amount")); -#endif #ifdef Q_OS_MAC amountWidget->setFixedWidth(97); #else @@ -165,6 +159,10 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t QAction* copyTxIDAction = new QAction(tr("Copy transaction ID"), this); QAction* editLabelAction = new QAction(tr("Edit label"), this); QAction* showDetailsAction = new QAction(tr("Show transaction details"), this); + hideOrphansAction = new QAction(tr("Hide orphan stakes"), this); + + hideOrphansAction->setCheckable(true); + hideOrphansAction->setChecked(settings.value("fHideOrphans", false).toBool()); contextMenu = new QMenu(); contextMenu->addAction(copyAddressAction); @@ -173,6 +171,7 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t contextMenu->addAction(copyTxIDAction); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); + contextMenu->addAction(hideOrphansAction); mapperThirdPartyTxUrls = new QSignalMapper(this); @@ -195,6 +194,7 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); + connect(hideOrphansAction, SIGNAL(toggled(bool)), this, SLOT(updateHideOrphans(bool))); } void TransactionView::setModel(WalletModel* model) @@ -244,6 +244,8 @@ void TransactionView::setModel(WalletModel* model) mapperThirdPartyTxUrls->setMapping(thirdPartyTxUrlAction, listUrls[i].trimmed()); } } + + connect(model->getOptionsModel(), SIGNAL(hideOrphansChanged(bool)), this, SLOT(updateHideOrphans(bool))); } // show/hide column Watch-only @@ -255,6 +257,9 @@ void TransactionView::setModel(WalletModel* model) // Update transaction list with persisted settings chooseType(settings.value("transactionType").toInt()); chooseDate(settings.value("transactionDate").toInt()); + + // Hide orphans + hideOrphans(settings.value("fHideOrphans", false).toBool()); } } @@ -321,6 +326,29 @@ void TransactionView::chooseType(int idx) settings.setValue("transactionType", idx); } +void TransactionView::hideOrphans(bool fHide) +{ + if (!transactionProxyModel) + return; + transactionProxyModel->setHideOrphans(fHide); +} + +void TransactionView::updateHideOrphans(bool fHide) +{ + QSettings settings; + if (settings.value("fHideOrphans", false).toBool() != fHide) { + settings.setValue("fHideOrphans", fHide); + if (model && model->getOptionsModel()) + emit model->getOptionsModel()->hideOrphansChanged(fHide); + } + hideOrphans(fHide); + // retain consistency with other checkboxes + if (hideOrphansAction->isChecked() != fHide) + hideOrphansAction->setChecked(fHide); + +} + + void TransactionView::chooseWatchonly(int idx) { if (!transactionProxyModel) @@ -387,7 +415,7 @@ void TransactionView::exportClicked() if (fExport) { emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), CClientUIInterface::MSG_INFORMATION); - } + } else { emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), CClientUIInterface::MSG_ERROR); diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index af667f9f33d4..d69c9619bf23 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -9,6 +9,7 @@ #include #include +#include class TransactionFilterProxy; class WalletModel; @@ -66,6 +67,7 @@ class TransactionView : public QWidget QComboBox* watchOnlyWidget; QLineEdit* addressWidget; QLineEdit* amountWidget; + QAction* hideOrphansAction; QMenu* contextMenu; QSignalMapper* mapperThirdPartyTxUrls; @@ -106,6 +108,8 @@ private slots: public slots: void chooseDate(int idx); void chooseType(int idx); + void hideOrphans(bool fHide); + void updateHideOrphans(bool fHide); void chooseWatchonly(int idx); void changedPrefix(const QString& prefix); void changedAmount(const QString& amount); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 803ced9882cf..e6b56c85afe8 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -28,7 +28,7 @@ #include /** "Help message" or "About" dialog box */ -HelpMessageDialog::HelpMessageDialog(QWidget* parent, bool about) : QDialog(parent), +HelpMessageDialog::HelpMessageDialog(QWidget* parent, bool about) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::HelpMessageDialog) { ui->setupUi(this); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index c453fdaa52cc..1d0a8a32d321 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -13,7 +13,6 @@ class ClientModel; class SendCoinsRecipient; class WalletModel; class WalletView; -class TradingDialog; class BlockExplorer; QT_BEGIN_NAMESPACE diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 011d2db3d348..e5d1d02bbc79 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -26,7 +26,6 @@ #include #include -using namespace std; WalletModel::WalletModel(CWallet* wallet, OptionsModel* optionsModel, QObject* parent) : QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), transactionTableModel(0), @@ -63,7 +62,7 @@ CAmount WalletModel::getBalance(const CCoinControl* coinControl) const CAmount nBalance = 0; std::vector vCoins; wallet->AvailableCoins(vCoins, true, coinControl); - BOOST_FOREACH (const COutput& out, vCoins) + for (const COutput& out : vCoins) if (out.fSpendable) nBalance += out.tx->vout[out.i].nValue; @@ -241,7 +240,7 @@ bool WalletModel::validateAddress(const QString& address) return IsValidDestinationString(address.toStdString()); } -void WalletModel::updateAddressBookLabels(const CTxDestination& dest, const string& strName, const string& strPurpose) +void WalletModel::updateAddressBookLabels(const CTxDestination& dest, const std::string& strName, const std::string& strPurpose) { LOCK(wallet->cs_wallet); @@ -377,10 +376,10 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction& tran std::string key("PaymentRequest"); std::string value; rcp.paymentRequest.SerializeToString(&value); - newTx->vOrderForm.push_back(make_pair(key, value)); + newTx->vOrderForm.push_back(std::make_pair(key, value)); } else if (!rcp.message.isEmpty()) // Message from normal phore:URI (phore:XyZ...?message=example) { - newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); + newTx->vOrderForm.push_back(std::make_pair("Message", rcp.message.toStdString())); } } @@ -527,7 +526,7 @@ static std::vector > vQueueNotifications; static void NotifyTransactionChanged(WalletModel* walletmodel, CWallet* wallet, const uint256& hash, ChangeType status) { if (fQueueNotifications) { - vQueueNotifications.push_back(make_pair(hash, status)); + vQueueNotifications.push_back(std::make_pair(hash, status)); return; } @@ -571,10 +570,10 @@ static void NotifyZerocoinChanged(WalletModel* walletmodel, CWallet* wallet, con Q_ARG(int, status)); } -static void NotifyWalletBacked(WalletModel* model, const bool& fSuccess, const string& filename) +static void NotifyWalletBacked(WalletModel* model, const bool& fSuccess, const std::string& filename) { - string message; - string title = "Backup "; + std::string message; + std::string title = "Backup "; CClientUIInterface::MessageBoxFlags method; if (fSuccess) { @@ -672,7 +671,7 @@ bool WalletModel::getPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const void WalletModel::getOutputs(const std::vector& vOutpoints, std::vector& vOutputs) { LOCK2(cs_main, wallet->cs_wallet); - BOOST_FOREACH (const COutPoint& outpoint, vOutpoints) { + for (const COutPoint& outpoint : vOutpoints) { if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; @@ -698,7 +697,7 @@ void WalletModel::listCoins(std::map >& mapCoins) wallet->ListLockedCoins(vLockedCoins); // add locked coins - BOOST_FOREACH (const COutPoint& outpoint, vLockedCoins) { + for (const COutPoint& outpoint : vLockedCoins) { if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; @@ -707,7 +706,7 @@ void WalletModel::listCoins(std::map >& mapCoins) vCoins.push_back(out); } - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { COutput cout = out; while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0])) { @@ -756,8 +755,8 @@ void WalletModel::listZerocoinMints(std::set& setMints, bool fUnusedO void WalletModel::loadReceiveRequests(std::vector& vReceiveRequests) { LOCK(wallet->cs_wallet); - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, wallet->mapAddressBook) - BOOST_FOREACH (const PAIRTYPE(std::string, std::string) & item2, item.second.destdata) + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : wallet->mapAddressBook) + for (const PAIRTYPE(std::string, std::string) & item2 : item.second.destdata) if (item2.first.size() > 2 && item2.first.substr(0, 2) == "rr") // receive request vReceiveRequests.push_back(item2.second); } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 28aff84b7126..c591cb3e2007 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -143,7 +143,7 @@ class WalletModel : public QObject CAmount getWatchImmatureBalance() const; EncryptionStatus getEncryptionStatus() const; CKey generateNewKey() const; //for temporary paper wallet key generation - bool setAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose); + bool setAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose); void encryptKey(const CKey key, const std::string& pwd, const std::string& slt, std::vector& crypted); void decryptKey(const std::vector& crypted, const std::string& slt, const std::string& pwd, CKey& key); void emitBalanceChanged(); // Force update of UI-elements even when no values have changed @@ -212,7 +212,7 @@ class WalletModel : public QObject void listZerocoinMints(std::set& setMints, bool fUnusedOnly = false, bool fMaturedOnly = false, bool fUpdateStatus = false); - string GetUniqueWalletBackupName(); + std::string GetUniqueWalletBackupName(); void loadReceiveRequests(std::vector& vReceiveRequests); bool saveReceiveRequest(const std::string& sAddress, const int64_t nId, const std::string& sRequest); bool hdEnabled() const; @@ -297,7 +297,7 @@ public slots: /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ void pollBalanceChanged(); /* Update address book labels in the database */ - void updateAddressBookLabels(const CTxDestination& address, const string& strName, const string& strPurpose); + void updateAddressBookLabels(const CTxDestination& address, const std::string& strName, const std::string& strPurpose); }; #endif // BITCOIN_QT_WALLETMODEL_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index dc4ac1e8183d..a74c3ae31d08 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -133,7 +133,7 @@ WalletView::WalletView(QWidget* parent) : QStackedWidget(parent), masternodeListPage = new MasternodeList(); addWidget(masternodeListPage); } - + QVBoxLayout* vbox_2 = new QVBoxLayout(); proposalList = new ProposalList(this); vbox_2->addWidget(proposalList); diff --git a/src/qt/walletview.h b/src/qt/walletview.h index f734db6e2b29..cba714f3ce9d 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -69,7 +69,7 @@ class WalletView : public QStackedWidget SendCoinsDialog* sendCoinsPage; BlockExplorer* explorerWindow; MasternodeList* masternodeListPage; - QWidget* proposalListPage; + QWidget* proposalListPage; TransactionView* transactionView; ProposalList* proposalList; @@ -89,7 +89,7 @@ public slots: /** Switch to privacy page */ void gotoPrivacyPage(); /** Switch to proposal page */ - void gotoProposalPage(); + void gotoProposalPage(); /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 3190d92e22da..e960037ac0dc 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -4,7 +4,7 @@ #include "winshutdownmonitor.h" -#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 +#if defined(Q_OS_WIN) #include "init.h" #include "util.h" diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h index f24f47e80c3c..4d72d0ff784b 100644 --- a/src/qt/winshutdownmonitor.h +++ b/src/qt/winshutdownmonitor.h @@ -9,7 +9,6 @@ #include #include -#if QT_VERSION >= 0x050000 #include // for HWND #include @@ -24,6 +23,5 @@ class WinShutdownMonitor : public QAbstractNativeEventFilter static void registerShutdownBlockReason(const QString& strReason, const HWND& mainWinId); }; #endif -#endif #endif // BITCOIN_QT_WINSHUTDOWNMONITOR_H diff --git a/src/qt/zphrcontroldialog.cpp b/src/qt/zphrcontroldialog.cpp index 39e021ba3582..b317bebf569f 100644 --- a/src/qt/zphrcontroldialog.cpp +++ b/src/qt/zphrcontroldialog.cpp @@ -9,14 +9,12 @@ #include "main.h" #include "walletmodel.h" -using namespace std; -using namespace libzerocoin; std::set ZPhrControlDialog::setSelectedMints; std::set ZPhrControlDialog::setMints; ZPhrControlDialog::ZPhrControlDialog(QWidget *parent) : - QDialog(parent), + QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::ZPhrControlDialog), model(0) { @@ -51,7 +49,7 @@ void ZPhrControlDialog::updateList() // add a top level item for each denomination QFlags flgTristate = Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; - map mapDenomPosition; + std::map mapDenomPosition; for (auto denom : libzerocoin::zerocoinDenomList) { QTreeWidgetItem* itemDenom(new QTreeWidgetItem); ui->treeWidget->addTopLevelItem(itemDenom); @@ -70,7 +68,7 @@ void ZPhrControlDialog::updateList() //populate rows with mint info int nBestHeight = chainActive.Height(); - map mapMaturityHeight = GetMintMaturityHeight(); + std::map mapMaturityHeight = GetMintMaturityHeight(); for(const CMintMeta& mint : setMints) { // assign this mint to the correct denomination in the tree view libzerocoin::CoinDenomination denom = mint.denom; @@ -110,7 +108,7 @@ void ZPhrControlDialog::updateList() if (setSelectedMints.count(strPubCoinHash)) setSelectedMints.erase(strPubCoinHash); - string strReason = ""; + std::string strReason = ""; if(nConfirmations < Params().Zerocoin_MintRequiredConfirmations()) strReason = strprintf("Needs %d more confirmations", Params().Zerocoin_MintRequiredConfirmations() - nConfirmations); else diff --git a/src/random.cpp b/src/random.cpp index 6f4f4153cf42..c2d1f5d6c487 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -11,7 +11,6 @@ #include "compat.h" // for Windows API #include #endif -#include "serialize.h" // for begin_ptr(vec) #include "util.h" // for LogPrint() #include "utilstrencodings.h" // for GetTime() @@ -49,30 +48,31 @@ static void RandAddSeedPerfmon() { RandAddSeed(); +#ifdef WIN32 + // Don't need this on Linux, OpenSSL automatically uses /dev/urandom + // Seed with the entire set of perfmon data + // This can take up to 2 seconds, so only do it every 10 minutes static int64_t nLastPerfmon; if (GetTime() < nLastPerfmon + 10 * 60) return; nLastPerfmon = GetTime(); -#ifdef WIN32 - // Don't need this on Linux, OpenSSL automatically uses /dev/urandom - // Seed with the entire set of perfmon data std::vector vData(250000, 0); long ret = 0; unsigned long nSize = 0; const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data while (true) { nSize = vData.size(); - ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, begin_ptr(vData), &nSize); + ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, vData.data(), &nSize); if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize) break; vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially } RegCloseKey(HKEY_PERFORMANCE_DATA); if (ret == ERROR_SUCCESS) { - RAND_add(begin_ptr(vData), nSize, nSize / 100.0); - memory_cleanse(begin_ptr(vData), nSize); + RAND_add(vData.data(), nSize, nSize / 100.0); + memory_cleanse(vData.data(), nSize); LogPrint("rand", "%s: %lu bytes\n", __func__, nSize); } else { static bool warned = false; // Warn only once diff --git a/src/rest.cpp b/src/rest.cpp index f7fbc63d477e..53b63c23cbc8 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -8,7 +8,7 @@ #include "primitives/transaction.h" #include "main.h" #include "httpserver.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "streams.h" #include "sync.h" #include "txmempool.h" @@ -20,8 +20,6 @@ #include -using namespace std; - static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once enum RetFormat { @@ -64,14 +62,14 @@ extern UniValue mempoolToJSON(bool fVerbose = false); extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); extern UniValue blockheaderToJSON(const CBlockIndex* blockindex); -static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, string message) +static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message) { req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(status, message + "\r\n"); return false; } -static enum RetFormat ParseDataFormat(vector& params, const string& strReq) +static enum RetFormat ParseDataFormat(std::vector& params, const std::string& strReq) { boost::split(params, strReq, boost::is_any_of(".")); if (params.size() > 1) { @@ -83,9 +81,9 @@ static enum RetFormat ParseDataFormat(vector& params, const string& strR return rf_names[0].rf; } -static string AvailableDataFormatsString() +static std::string AvailableDataFormatsString() { - string formats = ""; + std::string formats = ""; for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++) if (strlen(rf_names[i].name) > 0) { formats.append("."); @@ -99,7 +97,7 @@ static string AvailableDataFormatsString() return formats; } -static bool ParseHashStr(const string& strReq, uint256& v) +static bool ParseHashStr(const std::string& strReq, uint256& v) { if (!IsHex(strReq) || (strReq.size() != 64)) return false; @@ -121,9 +119,9 @@ static bool rest_headers(HTTPRequest* req, { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; const RetFormat rf = ParseDataFormat(params, strURIPart); - vector path; + std::vector path; boost::split(path, params[0], boost::is_any_of("/")); if (path.size() != 2) @@ -133,7 +131,7 @@ static bool rest_headers(HTTPRequest* req, if (count < 1 || count > 2000) return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]); - string hashStr = path[1]; + std::string hashStr = path[1]; uint256 hash; if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); @@ -153,30 +151,30 @@ static bool rest_headers(HTTPRequest* req, } CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); - BOOST_FOREACH(const CBlockIndex *pindex, headers) { + for (const CBlockIndex *pindex : headers) { ssHeader << pindex->GetBlockHeader(); } switch (rf) { case RF_BINARY: { - string binaryHeader = ssHeader.str(); + std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryHeader); return true; } case RF_HEX: { - string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n"; + std::string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); return true; } case RF_JSON: { UniValue jsonHeaders(UniValue::VARR); - BOOST_FOREACH(const CBlockIndex *pindex, headers) { + for (const CBlockIndex *pindex : headers) { jsonHeaders.push_back(blockheaderToJSON(pindex)); } - string strJSON = jsonHeaders.write() + "\n"; + std::string strJSON = jsonHeaders.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; @@ -196,10 +194,10 @@ static bool rest_block(HTTPRequest* req, { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; const RetFormat rf = ParseDataFormat(params, strURIPart); - string hashStr = params[0]; + std::string hashStr = params[0]; uint256 hash; if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); @@ -224,14 +222,14 @@ static bool rest_block(HTTPRequest* req, switch (rf) { case RF_BINARY: { - string binaryBlock = ssBlock.str(); + std::string binaryBlock = ssBlock.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryBlock); return true; } case RF_HEX: { - string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n"; + std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); return true; @@ -239,7 +237,7 @@ static bool rest_block(HTTPRequest* req, case RF_JSON: { UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails); - string strJSON = objBlock.write() + "\n"; + std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; @@ -268,14 +266,14 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; const RetFormat rf = ParseDataFormat(params, strURIPart); switch (rf) { case RF_JSON: { UniValue rpcParams(UniValue::VARR); UniValue chainInfoObject = getblockchaininfo(rpcParams, false); - string strJSON = chainInfoObject.write() + "\n"; + std::string strJSON = chainInfoObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; @@ -293,14 +291,14 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; const RetFormat rf = ParseDataFormat(params, strURIPart); switch (rf) { case RF_JSON: { UniValue mempoolInfoObject = mempoolInfoToJSON(); - string strJSON = mempoolInfoObject.write() + "\n"; + std::string strJSON = mempoolInfoObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; @@ -318,14 +316,14 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; const RetFormat rf = ParseDataFormat(params, strURIPart); switch (rf) { case RF_JSON: { UniValue mempoolObject = mempoolToJSON(true); - string strJSON = mempoolObject.write() + "\n"; + std::string strJSON = mempoolObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; @@ -343,10 +341,10 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; const RetFormat rf = ParseDataFormat(params, strURIPart); - string hashStr = params[0]; + std::string hashStr = params[0]; uint256 hash; if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); @@ -361,14 +359,14 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) switch (rf) { case RF_BINARY: { - string binaryTx = ssTx.str(); + std::string binaryTx = ssTx.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryTx); return true; } case RF_HEX: { - string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n"; + std::string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); return true; @@ -377,7 +375,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) case RF_JSON: { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, hashBlock, objTx, true, RPCSerializationFlags()); - string strJSON = objTx.write() + "\n"; + std::string strJSON = objTx.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; @@ -396,10 +394,10 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; - vector params; + std::vector params; enum RetFormat rf = ParseDataFormat(params, strURIPart); - vector uriParts; + std::vector uriParts; if (params.size() > 0 && params[0].length() > 1) { std::string strUriParams = params[0].substr(1); @@ -413,7 +411,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) bool fInputParsed = false; bool fCheckMemPool = false; - vector vOutPoints; + std::vector vOutPoints; // parse/deserialize input // input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ... @@ -486,9 +484,9 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS) return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size())); - // check spentness and form a bitmap (as well as a JSON capable human-readble string representation) - vector bitmap; - vector outs; + // check spentness and form a bitmap (as well as a JSON capable human-readble std::string representation) + std::vector bitmap; + std::vector outs; std::string bitmapStringRepresentation; boost::dynamic_bitset hits(vOutPoints.size()); { @@ -521,7 +519,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) } } - bitmapStringRepresentation.append(hits[i] ? "1" : "0"); // form a binary string representation (human-readable for json output) + bitmapStringRepresentation.append(hits[i] ? "1" : "0"); // form a binary std::string representation (human-readable for json output) } } boost::to_block_range(hits, std::back_inserter(bitmap)); @@ -532,7 +530,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; - string ssGetUTXOResponseString = ssGetUTXOResponse.str(); + std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, ssGetUTXOResponseString); @@ -542,7 +540,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) case RF_HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; - string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; + std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); @@ -559,7 +557,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation)); UniValue utxos(UniValue::VARR); - BOOST_FOREACH (const CCoin& coin, outs) { + for (const CCoin& coin : outs) { UniValue utxo(UniValue::VOBJ); utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer)); utxo.push_back(Pair("height", (int32_t)coin.nHeight)); @@ -574,7 +572,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) objGetUTXOResponse.push_back(Pair("utxos", utxos)); // return json string - string strJSON = objGetUTXOResponse.write() + "\n"; + std::string strJSON = objGetUTXOResponse.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); return true; diff --git a/src/rpcblockchain.cpp b/src/rpc/blockchain.cpp similarity index 89% rename from src/rpcblockchain.cpp rename to src/rpc/blockchain.cpp index 1dc8b39672bf..e9a5595e2d90 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -10,7 +10,7 @@ #include "clientversion.h" #include "consensus/validation.h" #include "main.h" -#include "rpcserver.h" +#include "server.h" #include "sync.h" #include "txdb.h" #include "util.h" @@ -19,7 +19,6 @@ #include #include -using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, bool include_hex, int serialize_flags); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); @@ -65,6 +64,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("version", blockindex->nVersion)); result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -96,7 +96,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("acc_checkpoint", block.nAccumulatorCheckpoint.GetHex())); UniValue txs(UniValue::VARR); - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (txDetails) { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(0), objTx, true, RPCSerializationFlags()); @@ -106,6 +106,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -121,7 +122,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx UniValue zphrObj(UniValue::VOBJ); for (auto denom : libzerocoin::zerocoinDenomList) { - zphrObj.push_back(Pair(to_string(denom), ValueFromAmount(blockindex->mapZerocoinSupply.at(denom) * (denom*COIN)))); + zphrObj.push_back(Pair(std::to_string(denom), ValueFromAmount(blockindex->mapZerocoinSupply.at(denom) * (denom*COIN)))); } zphrObj.push_back(Pair("total", ValueFromAmount(blockindex->GetZerocoinSupply()))); result.push_back(Pair("zPHRsupply", zphrObj)); @@ -132,7 +133,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getblockcount\n" "\nReturns the number of blocks in the longest block chain.\n" "\nResult:\n" @@ -147,7 +148,7 @@ UniValue getblockcount(const UniValue& params, bool fHelp) UniValue getbestblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getbestblockhash\n" "\nReturns the hash of the best (tip) block in the longest block chain.\n" "\nResult\n" @@ -162,7 +163,7 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) UniValue getdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getdifficulty\n" "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n" "\nResult:\n" @@ -180,7 +181,7 @@ UniValue mempoolToJSON(bool fVerbose = false) if (fVerbose) { LOCK(mempool.cs); UniValue o(UniValue::VOBJ); - BOOST_FOREACH (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry, mempool.mapTx) { + for (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry : mempool.mapTx) { const uint256& hash = entry.first; const CTxMemPoolEntry& e = entry.second; UniValue info(UniValue::VOBJ); @@ -191,14 +192,14 @@ UniValue mempoolToJSON(bool fVerbose = false) info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); const CTransaction& tx = e.GetTx(); - set setDepends; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + std::set setDepends; + for (const CTxIn& txin : tx.vin) { if (mempool.exists(txin.prevout.hash)) setDepends.insert(txin.prevout.hash.ToString()); } UniValue depends(UniValue::VARR); - BOOST_FOREACH(const string& dep, setDepends) { + for (const std::string& dep : setDepends) { depends.push_back(dep); } @@ -207,11 +208,11 @@ UniValue mempoolToJSON(bool fVerbose = false) } return o; } else { - vector vtxid; + std::vector vtxid; mempool.queryHashes(vtxid); UniValue a(UniValue::VARR); - BOOST_FOREACH (const uint256& hash, vtxid) + for (const uint256& hash : vtxid) a.push_back(hash.ToString()); return a; @@ -221,7 +222,7 @@ UniValue mempoolToJSON(bool fVerbose = false) UniValue getrawmempool(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getrawmempool ( verbose )\n" "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nArguments:\n" @@ -260,7 +261,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getblockhash index\n" "\nReturns hash of block in best-block-chain at index provided.\n" "\nArguments:\n" @@ -283,7 +284,7 @@ UniValue getblockhash(const UniValue& params, bool fHelp) UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getblock \"hash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbose is true, returns an Object with information about block .\n" @@ -303,6 +304,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " ,...\n" " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" @@ -358,7 +360,7 @@ UniValue getblock(const UniValue& params, bool fHelp) UniValue getblockheader(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getblockheader \"hash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash' header.\n" "If verbose is true, returns an Object with information about block header.\n" @@ -377,8 +379,9 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash' header.\n" @@ -410,7 +413,7 @@ UniValue getblockheader(const UniValue& params, bool fHelp) UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "gettxoutsetinfo\n" "\nReturns statistics about the unspent transaction output set.\n" "Note this call may take some time.\n" @@ -448,7 +451,7 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) UniValue gettxout(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "gettxout \"txid\" n ( includemempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" @@ -466,7 +469,7 @@ UniValue gettxout(const UniValue& params, bool fHelp) " \"reqSigs\" : n, (numeric) Number of required signatures\n" " \"type\" : \"pubkeyhash\", (string) The type, e.g. pubkeyhash\n" " \"addresses\" : [ (array of string) array of phore addresses\n" - " \"phoreaddress\" (string) phore address\n" + " \"phoreaddress\" (string) phore address\n" " ,...\n" " ]\n" " },\n" @@ -524,8 +527,8 @@ UniValue gettxout(const UniValue& params, bool fHelp) UniValue verifychain(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 2) - throw runtime_error( + if (fHelp || params.size() > 1) + throw std::runtime_error( "verifychain ( numblocks )\n" "\nVerifies blockchain database.\n" "\nArguments:\n" @@ -540,7 +543,7 @@ UniValue verifychain(const UniValue& params, bool fHelp) int nCheckLevel = 4; int nCheckDepth = GetArg("-checkblocks", 288); if (params.size() > 0) - nCheckDepth = params[1].get_int(); + nCheckDepth = params[0].get_int(); fVerifyingBlocks = true; @@ -550,10 +553,38 @@ UniValue verifychain(const UniValue& params, bool fHelp) return fVerified; } +/** Implementation of IsSuperMajority with better feedback */ +static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired) +{ + int nFound = 0; + CBlockIndex* pstart = pindex; + for (int i = 0; i < Params().ToCheckBlockUpgradeMajority() && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("status", nFound >= nRequired)); + rv.push_back(Pair("found", nFound)); + rv.push_back(Pair("required", nRequired)); + rv.push_back(Pair("window", Params().ToCheckBlockUpgradeMajority())); + return rv; +} +static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex) +{ + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("id", name)); + rv.push_back(Pair("version", version)); + rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, Params().EnforceBlockUpgradeMajority()))); + rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, Params().RejectBlockOutdatedMajority()))); + return rv; +} + UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getblockchaininfo\n" "Returns an object containing various state info regarding block chain processing.\n" "\nResult:\n" @@ -565,6 +596,19 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" + " \"softforks\": [ (array) status of softforks in progress\n" + " {\n" + " \"id\": \"xxxx\", (string) name of softfork\n" + " \"version\": xx, (numeric) block version\n" + " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n" + " \"status\": xx, (boolean) true if threshold reached\n" + " \"found\": xx, (numeric) number of blocks with the new version found\n" + " \"required\": xx, (numeric) number of blocks required to trigger\n" + " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n" + " },\n" + " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" + " }, ...\n" + " ]\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", "")); @@ -578,7 +622,11 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip()))); - obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); + obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); + CBlockIndex* tip = chainActive.Tip(); + UniValue softforks(UniValue::VARR); + softforks.push_back(SoftForkDesc("bip65", 5, tip)); + obj.push_back(Pair("softforks", softforks)); return obj; } @@ -599,7 +647,7 @@ struct CompareBlocksByHeight { UniValue getchaintips(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getchaintips\n" "Return information about all known tips in the block tree," " including the main chain as well as orphaned branches.\n" @@ -633,9 +681,9 @@ UniValue getchaintips(const UniValue& params, bool fHelp) known blocks, and successively remove blocks that appear as pprev of another block. */ std::set setTips; - BOOST_FOREACH (const PAIRTYPE(const uint256, CBlockIndex*) & item, mapBlockIndex) + for (const PAIRTYPE(const uint256, CBlockIndex*) & item : mapBlockIndex) setTips.insert(item.second); - BOOST_FOREACH (const PAIRTYPE(const uint256, CBlockIndex*) & item, mapBlockIndex) { + for (const PAIRTYPE(const uint256, CBlockIndex*) & item : mapBlockIndex) { const CBlockIndex* pprev = item.second->pprev; if (pprev) setTips.erase(pprev); @@ -646,7 +694,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) /* Construct the output array. */ UniValue res(UniValue::VARR); - BOOST_FOREACH (const CBlockIndex* block, setTips) { + for (const CBlockIndex* block : setTips) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); @@ -654,7 +702,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight; obj.push_back(Pair("branchlen", branchLen)); - string status; + std::string status; if (chainActive.Contains(block)) { // This block is part of the currently active chain. status = "active"; @@ -685,7 +733,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) UniValue getfeeinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getfeeinfo blocks\n" "\nReturns details of transaction fees over the last n blocks.\n" "\nArguments:\n" @@ -776,7 +824,7 @@ UniValue mempoolInfoToJSON() UniValue getmempoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getmempoolinfo\n" "\nReturns details on the active state of the TX memory pool.\n" "\nResult:\n" @@ -793,7 +841,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp) UniValue invalidateblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "invalidateblock \"hash\"\n" "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" "\nArguments:\n" @@ -829,7 +877,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) UniValue reconsiderblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "reconsiderblock \"hash\"\n" "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n" @@ -866,7 +914,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) UniValue findserial(const UniValue& params, bool fHelp) { if(fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "findserial \"serial\"\n" "\nSearches the zerocoin database for a zerocoin spend transaction that contains the specified serial\n" "\nArguments:\n" diff --git a/src/rpcclient.cpp b/src/rpc/client.cpp similarity index 96% rename from src/rpcclient.cpp rename to src/rpc/client.cpp index b11764a60516..59e7ff8182c7 100644 --- a/src/rpcclient.cpp +++ b/src/rpc/client.cpp @@ -5,9 +5,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcclient.h" +#include "rpc/client.h" -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "ui_interface.h" #include "util.h" @@ -17,8 +17,6 @@ #include // for to_lower() #include -using namespace std; - class CRPCConvertParam { public: @@ -104,10 +102,6 @@ static const CRPCConvertParam vRPCConvertParams[] = {"setban", 2}, {"setban", 3}, {"spork", 1}, - {"mnbudget", 3}, - {"mnbudget", 4}, - {"mnbudget", 6}, - {"mnbudget", 8}, {"preparebudget", 2}, {"preparebudget", 3}, {"preparebudget", 5}, @@ -178,7 +172,7 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal) UniValue jVal; if (!jVal.read(std::string("[")+strVal+std::string("]")) || !jVal.isArray() || jVal.size()!=1) - throw runtime_error(string("Error parsing JSON:")+strVal); + throw std::runtime_error(std::string("Error parsing JSON:")+strVal); return jVal[0]; } diff --git a/src/rpcclient.h b/src/rpc/client.h similarity index 100% rename from src/rpcclient.h rename to src/rpc/client.h diff --git a/src/rpcmasternode-budget.cpp b/src/rpc/masternode-budget.cpp similarity index 77% rename from src/rpcmasternode-budget.cpp rename to src/rpc/masternode-budget.cpp index 59c2802d958d..4899cbb0075f 100644 --- a/src/rpcmasternode-budget.cpp +++ b/src/rpc/masternode-budget.cpp @@ -2,6 +2,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "activemasternode.h" +#include "chainparams.h" #include "wallet/db.h" #include "init.h" #include "main.h" @@ -9,7 +10,7 @@ #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "server.h" #include "utilmoneystr.h" #ifdef ENABLE_WALLET @@ -19,7 +20,6 @@ #include #include -using namespace std; void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj) { @@ -49,117 +49,54 @@ void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj) bObj.push_back(Pair("fValid", pbudgetProposal->fValid)); } -// This command is retained for backwards compatibility, but is deprecated. -// Future removal of this command is planned to keep things clean. -UniValue mnbudget(const UniValue& params, bool fHelp) +void checkBudgetInputs(const UniValue& params, std::string &strProposalName, std::string &strURL, + int &nPaymentCount, int &nBlockStart, CAmount &nAmount) { - string strCommand; - if (params.size() >= 1) - strCommand = params[0].get_str(); + int nBlockMin = 0; + CBlockIndex* pindexPrev = chainActive.Tip(); - if (fHelp || - (strCommand != "vote-alias" && strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check" && strCommand != "nextblock")) - throw runtime_error( - "mnbudget \"command\"... ( \"passphrase\" )\n" - "\nVote or show current budgets\n" - "This command is deprecated, please see individual command documentation for future reference\n\n" + strProposalName = SanitizeString(params[0].get_str()); + if (strProposalName.size() > 20) + throw std::runtime_error("Invalid proposal name, limit of 20 characters."); - "\nAvailable commands:\n" - " prepare - Prepare proposal for network by signing and creating tx\n" - " submit - Submit proposal for network\n" - " vote-many - Vote on a Phore initiative\n" - " vote-alias - Vote on a Phore initiative\n" - " vote - Vote on a Phore initiative/budget\n" - " getvotes - Show current masternode budgets\n" - " getinfo - Show current masternode budgets\n" - " show - Show all budgets\n" - " projection - Show the projection of which proposals will be paid the next cycle\n" - " check - Scan proposals and remove invalid\n" - " nextblock - Get next superblock for budget system\n"); - - if (strCommand == "nextblock") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getnextsuperblock(newParams, fHelp); - } + strURL = SanitizeString(params[1].get_str()); - if (strCommand == "prepare") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return preparebudget(newParams, fHelp); - } + std::string strErr; + if (!validateURL(strURL, strErr)) + throw JSONRPCError(RPC_INVALID_PARAMETER, strErr); - if (strCommand == "submit") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return submitbudget(newParams, fHelp); - } + nPaymentCount = params[2].get_int(); + if (nPaymentCount < 1) + throw std::runtime_error("Invalid payment count, must be more than zero."); - if (strCommand == "vote" || strCommand == "vote-many" || strCommand == "vote-alias") { - if (strCommand == "vote-alias") - throw runtime_error( - "vote-alias is not supported with this command\n" - "Please use mnbudgetvote instead.\n" - ); - return mnbudgetvote(params, fHelp); - } + // Start must be in the next budget cycle + if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); - if (strCommand == "projection") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetprojection(newParams, fHelp); + nBlockStart = params[3].get_int(); + if (nBlockStart % Params().GetBudgetCycleBlocks() != 0) { + int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); + throw std::runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext)); } - if (strCommand == "show" || strCommand == "getinfo") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetinfo(newParams, fHelp); - } + int nBlockEnd = nBlockStart + (Params().GetBudgetCycleBlocks() * nPaymentCount); // End must be AFTER current cycle - if (strCommand == "getvotes") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetvotes(newParams, fHelp); - } + if (nBlockStart < nBlockMin) + throw std::runtime_error("Invalid block start, must be more than current height."); - if (strCommand == "check") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return checkbudgets(newParams, fHelp); - } + if (nBlockEnd < pindexPrev->nHeight) + throw std::runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height."); - return NullUniValue; + if (!IsValidDestinationString(params[4].get_str())) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Phore address"); + + nAmount = AmountFromValue(params[5]); } UniValue preparebudget(const UniValue& params, bool fHelp) { - int nBlockMin = 0; - CBlockIndex* pindexPrev = chainActive.Tip(); - if (fHelp || params.size() != 6) - throw runtime_error( - "preparebudget \"proposal-name\" \"url\" payment-count block-start \"phore-address\" monthly-payment\n" + throw std::runtime_error( + "preparebudget \"proposal-name\" \"url\" payment-count block-start \"phore-address\" monthy-payment\n" "\nPrepare proposal for network by signing and creating tx\n" "\nArguments:\n" @@ -167,11 +104,12 @@ UniValue preparebudget(const UniValue& params, bool fHelp) "2. \"url\": (string, required) URL of proposal details (64 character limit)\n" "3. payment-count: (numeric, required) Total number of monthly payments\n" "4. block-start: (numeric, required) Starting super block height\n" - "5. \"phore-address\": (string, required) Phore address to send payments to\n" + "5. \"phore-address\": (string, required) PIVX address to send payments to\n" "6. monthly-payment: (numeric, required) Monthly payment amount\n" "\nResult:\n" "\"xxxx\" (string) proposal fee hash (if successful) or error message (if failed)\n" + "\nExamples:\n" + HelpExampleCli("preparebudget", "\"test-proposal\" \"https://forum.phore.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") + HelpExampleRpc("preparebudget", "\"test-proposal\" \"https://forum.phore.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500")); @@ -180,54 +118,24 @@ UniValue preparebudget(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - std::string strProposalName = SanitizeString(params[0].get_str()); - if (strProposalName.size() > 20) - throw runtime_error("Invalid proposal name, limit of 20 characters."); - - std::string strURL = SanitizeString(params[1].get_str()); - if (strURL.size() > 64) - throw runtime_error("Invalid url, limit of 64 characters."); - - int nPaymentCount = params[2].get_int(); - if (nPaymentCount < 1) - throw runtime_error("Invalid payment count, must be more than zero."); - - // Start must be in the next budget cycle - if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); - - int nBlockStart = params[3].get_int(); - if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) { - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); - throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext)); - } - - int nBlockEnd = nBlockStart + GetBudgetPaymentCycleBlocks() * nPaymentCount; // End must be AFTER current cycle - - if (nBlockStart < nBlockMin) - throw runtime_error("Invalid block start, must be more than current height."); - - if (nBlockEnd < pindexPrev->nHeight) - throw runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height."); - - - if (!IsValidDestinationString(params[4].get_str())) - - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Phore address"); - + std::string strProposalName; + std::string strURL; + int nPaymentCount; + int nBlockStart; CTxDestination address = DecodeDestination(params[4].get_str()); + CAmount nAmount; + + checkBudgetInputs(params, strProposalName, strURL, nPaymentCount, nBlockStart, nAmount); // Parse Phore address CScript scriptPubKey = GetScriptForDestination(address); - CAmount nAmount = AmountFromValue(params[5]); - - //************************************************************************* // create transaction 15 minutes into the future, to allow for confirmation time CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, 0); std::string strError = ""; if (!budgetProposalBroadcast.IsValid(strError, false)) - throw runtime_error("Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError); + throw std::runtime_error("Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError); bool useIX = false; //true; // if (params.size() > 7) { @@ -238,7 +146,7 @@ UniValue preparebudget(const UniValue& params, bool fHelp) CWalletTx wtx; if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, budgetProposalBroadcast.GetHash(), useIX)) { - throw runtime_error("Error making collateral transaction for proposal. Please check your wallet balance."); + throw std::runtime_error("Error making collateral transaction for proposal. Please check your wallet balance."); } // make our change address @@ -251,11 +159,8 @@ UniValue preparebudget(const UniValue& params, bool fHelp) UniValue submitbudget(const UniValue& params, bool fHelp) { - int nBlockMin = 0; - CBlockIndex* pindexPrev = chainActive.Tip(); - if (fHelp || params.size() != 7) - throw runtime_error( + throw std::runtime_error( "submitbudget \"proposal-name\" \"url\" payment-count block-start \"phore-address\" monthly-payment \"fee-tx\"\n" "\nSubmit proposal to the network\n" @@ -274,46 +179,18 @@ UniValue submitbudget(const UniValue& params, bool fHelp) HelpExampleCli("submitbudget", "\"test-proposal\" \"https://forum.phore.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") + HelpExampleRpc("submitbudget", "\"test-proposal\" \"https://forum.phore.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500")); - // Check these inputs the same way we check the vote commands: - // ********************************************************** - - std::string strProposalName = SanitizeString(params[0].get_str()); - if (strProposalName.size() > 20) - throw runtime_error("Invalid proposal name, limit of 20 characters."); - - std::string strURL = SanitizeString(params[1].get_str()); - if (strURL.size() > 64) - throw runtime_error("Invalid url, limit of 64 characters."); - - int nPaymentCount = params[2].get_int(); - if (nPaymentCount < 1) - throw runtime_error("Invalid payment count, must be more than zero."); - - // Start must be in the next budget cycle - if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); - - int nBlockStart = params[3].get_int(); - if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) { - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); - throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext)); - } - - int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks() * nPaymentCount); // End must be AFTER current cycle - - if (nBlockStart < nBlockMin) - throw runtime_error("Invalid block start, must be more than current height."); - - if (nBlockEnd < pindexPrev->nHeight) - throw runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height."); - - if (!IsValidDestinationString(params[4].get_str())) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Phore address"); - + std::string strProposalName; + std::string strURL; + int nPaymentCount; + int nBlockStart; CTxDestination address = DecodeDestination(params[4].get_str()); + CAmount nAmount; + + checkBudgetInputs(params, strProposalName, strURL, nPaymentCount, nBlockStart, nAmount); // Parse Phore address CScript scriptPubKey = GetScriptForDestination(address); - CAmount nAmount = AmountFromValue(params[5]); + uint256 hash = ParseHashV(params[6], "parameter 1"); //create the proposal incase we're the first to make it @@ -322,23 +199,23 @@ UniValue submitbudget(const UniValue& params, bool fHelp) std::string strError = ""; int nConf = 0; if (!IsBudgetCollateralValid(hash, budgetProposalBroadcast.GetHash(), strError, budgetProposalBroadcast.nTime, nConf)) { - throw runtime_error("Proposal FeeTX is not valid - " + hash.ToString() + " - " + strError); + throw std::runtime_error("Proposal FeeTX is not valid - " + hash.ToString() + " - " + strError); } if (!masternodeSync.IsBlockchainSynced()) { - throw runtime_error("Must wait for client to sync with masternode network. Try again in a minute or so."); + throw std::runtime_error("Must wait for client to sync with masternode network. Try again in a minute or so."); } // if(!budgetProposalBroadcast.IsValid(strError)){ // return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError; // } - budget.mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); + budget.mapSeenMasternodeBudgetProposals.insert(std::make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); budgetProposalBroadcast.Relay(); if(budget.AddProposal(budgetProposalBroadcast)) { return budgetProposalBroadcast.GetHash().ToString(); } - throw runtime_error("Invalid proposal, see debug.log for details."); + throw std::runtime_error("Invalid proposal, see debug.log for details."); } UniValue mnbudgetvote(const UniValue& params, bool fHelp) @@ -355,7 +232,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) if (fHelp || (params.size() == 3 && (strCommand != "local" && strCommand != "many")) || (params.size() == 4 && strCommand != "alias") || params.size() > 4 || params.size() < 3) - throw runtime_error( + throw std::runtime_error( "mnbudgetvote \"local|many|alias\" \"votehash\" \"yes|no\" ( \"alias\" )\n" "\nVote on a budget proposal\n" @@ -435,7 +312,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) std::string strError = ""; if (budget.UpdateProposal(vote, NULL, strError)) { success++; - budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); statusObj.push_back(Pair("node", "local")); statusObj.push_back(Pair("result", "success")); @@ -458,7 +335,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) } if (strCommand == "many") { - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; std::vector vchMasterNodeSignature; std::string strMasterNodeSignMessage; @@ -501,7 +378,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) std::string strError = ""; if (budget.UpdateProposal(vote, NULL, strError)) { - budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); success++; statusObj.push_back(Pair("node", mne.getAlias())); @@ -529,7 +406,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); - BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if( strAlias != mne.getAlias()) continue; @@ -576,7 +453,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) std::string strError = ""; if(budget.UpdateProposal(vote, NULL, strError)) { - budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); success++; statusObj.push_back(Pair("node", mne.getAlias())); @@ -605,7 +482,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) UniValue getbudgetvotes(const UniValue& params, bool fHelp) { if (params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getbudgetvotes \"proposal-name\"\n" "\nPrint vote information for a budget proposal\n" @@ -632,7 +509,7 @@ UniValue getbudgetvotes(const UniValue& params, bool fHelp) CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName); - if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name"); + if (pbudgetProposal == NULL) throw std::runtime_error("Unknown proposal name"); std::map::iterator it = pbudgetProposal->mapVotes.begin(); while (it != pbudgetProposal->mapVotes.end()) { @@ -654,7 +531,7 @@ UniValue getbudgetvotes(const UniValue& params, bool fHelp) UniValue getnextsuperblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getnextsuperblock\n" "\nPrint the next super block height\n" @@ -666,14 +543,14 @@ UniValue getnextsuperblock(const UniValue& params, bool fHelp) CBlockIndex* pindexPrev = chainActive.Tip(); if (!pindexPrev) return "unknown"; - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); return nNext; } UniValue getbudgetprojection(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getbudgetprojection\n" "\nShow the projection of which proposals will be paid the next cycle\n" @@ -712,7 +589,7 @@ UniValue getbudgetprojection(const UniValue& params, bool fHelp) CAmount nTotalAllotted = 0; std::vector winningProps = budget.GetBudget(); - BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) { + for (CBudgetProposal* pbudgetProposal : winningProps) { nTotalAllotted += pbudgetProposal->GetAllotted(); UniValue bObj(UniValue::VOBJ); @@ -729,7 +606,7 @@ UniValue getbudgetprojection(const UniValue& params, bool fHelp) UniValue getbudgetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getbudgetinfo ( \"proposal\" )\n" "\nShow current masternode budgets\n" @@ -770,7 +647,7 @@ UniValue getbudgetinfo(const UniValue& params, bool fHelp) if (params.size() == 1) { std::string strProposalName = SanitizeString(params[0].get_str()); CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName); - if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name"); + if (pbudgetProposal == NULL) throw std::runtime_error("Unknown proposal name"); UniValue bObj(UniValue::VOBJ); budgetToJSON(pbudgetProposal, bObj); ret.push_back(bObj); @@ -778,7 +655,7 @@ UniValue getbudgetinfo(const UniValue& params, bool fHelp) } std::vector winningProps = budget.GetAllProposals(); - BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) { + for (CBudgetProposal* pbudgetProposal : winningProps) { if (strShow == "valid" && !pbudgetProposal->fValid) continue; UniValue bObj(UniValue::VOBJ); @@ -793,7 +670,7 @@ UniValue getbudgetinfo(const UniValue& params, bool fHelp) UniValue mnbudgetrawvote(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 6) - throw runtime_error( + throw std::runtime_error( "mnbudgetrawvote \"masternode-tx-hash\" masternode-tx-index \"proposal-hash\" yes|no time \"vote-sig\"\n" "\nCompile and relay a proposal vote with provided external signature instead of signing vote internally\n" @@ -825,7 +702,7 @@ UniValue mnbudgetrawvote(const UniValue& params, bool fHelp) int64_t nTime = params[4].get_int64(); std::string strSig = params[5].get_str(); bool fInvalid = false; - vector vchSig = DecodeBase64(strSig.c_str(), &fInvalid); + std::vector vchSig = DecodeBase64(strSig.c_str(), &fInvalid); if (fInvalid) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); @@ -845,7 +722,7 @@ UniValue mnbudgetrawvote(const UniValue& params, bool fHelp) std::string strError = ""; if (budget.UpdateProposal(vote, NULL, strError)) { - budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); return "Voted successfully"; } else { @@ -855,13 +732,13 @@ UniValue mnbudgetrawvote(const UniValue& params, bool fHelp) UniValue mnfinalbudget(const UniValue& params, bool fHelp) { - string strCommand; + std::string strCommand; if (params.size() >= 1) strCommand = params[0].get_str(); if (fHelp || (strCommand != "suggest" && strCommand != "vote-many" && strCommand != "vote" && strCommand != "show" && strCommand != "getvotes")) - throw runtime_error( + throw std::runtime_error( "mnfinalbudget \"command\"... ( \"passphrase\" )\n" "Vote or show current budgets\n" "\nAvailable commands:\n" @@ -872,7 +749,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) if (strCommand == "vote-many") { if (params.size() != 2) - throw runtime_error("Correct usage is 'mnfinalbudget vote-many BUDGET_HASH'"); + throw std::runtime_error("Correct usage is 'mnfinalbudget vote-many BUDGET_HASH'"); std::string strHash = params[1].get_str(); uint256 hash(strHash); @@ -882,7 +759,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) UniValue resultsObj(UniValue::VOBJ); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; std::vector vchMasterNodeSignature; std::string strMasterNodeSignMessage; @@ -923,7 +800,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) std::string strError = ""; if (budget.UpdateFinalizedBudget(vote, NULL, strError)) { - budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenFinalizedBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); success++; statusObj.push_back(Pair("result", "success")); @@ -944,7 +821,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) if (strCommand == "vote") { if (params.size() != 2) - throw runtime_error("Correct usage is 'mnfinalbudget vote BUDGET_HASH'"); + throw std::runtime_error("Correct usage is 'mnfinalbudget vote BUDGET_HASH'"); std::string strHash = params[1].get_str(); uint256 hash(strHash); @@ -968,7 +845,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) std::string strError = ""; if (budget.UpdateFinalizedBudget(vote, NULL, strError)) { - budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenFinalizedBudgetVotes.insert(std::make_pair(vote.GetHash(), vote)); vote.Relay(); return "success"; } else { @@ -980,11 +857,11 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) UniValue resultObj(UniValue::VOBJ); std::vector winningFbs = budget.GetFinalizedBudgets(); - BOOST_FOREACH(CFinalizedBudget* finalizedBudget, winningFbs) + for (CFinalizedBudget* finalizedBudget : winningFbs) { // Ignore old finalized budgets to avoid displaying misleading error // messages about missing proposals. Include the previous final budget cycle. - if (finalizedBudget->GetBlockStart() < (chainActive.Tip()->nHeight - GetBudgetPaymentCycleBlocks())) continue; + if (finalizedBudget->GetBlockStart() < (chainActive.Tip()->nHeight - Params().GetBudgetCycleBlocks())) continue; UniValue bObj(UniValue::VOBJ); bObj.push_back(Pair("FeeTX", finalizedBudget->nFeeTXHash.ToString())); @@ -1007,7 +884,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) if (strCommand == "getvotes") { if (params.size() != 2) - throw runtime_error("Correct usage is 'mnbudget getvotes budget-hash'"); + throw std::runtime_error("Correct usage is 'mnbudget getvotes budget-hash'"); std::string strHash = params[1].get_str(); uint256 hash(strHash); @@ -1039,7 +916,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) UniValue checkbudgets(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "checkbudgets\n" "\nInitiates a buddget check cycle manually\n" "\nExamples:\n" + diff --git a/src/rpcmasternode.cpp b/src/rpc/masternode.cpp similarity index 81% rename from src/rpcmasternode.cpp rename to src/rpc/masternode.cpp index 3c14f744465b..fee5af0dda50 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpc/masternode.cpp @@ -11,7 +11,7 @@ #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "server.h" #include "utilmoneystr.h" #ifdef ENABLE_WALLET @@ -20,14 +20,13 @@ #include -#include #include #include UniValue getpoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getpoolinfo\n" "\nReturns anonymous pool-related information\n" @@ -50,147 +49,6 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp) return obj; } -// This command is retained for backwards compatibility, but is deprecated. -// Future removal of this command is planned to keep things clean. -UniValue masternode(const UniValue& params, bool fHelp) -{ - string strCommand; - if (params.size() >= 1) - strCommand = params[0].get_str(); - - if (fHelp || - (strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "start-all" && strCommand != "start-missing" && - strCommand != "start-disabled" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" && - strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" && - strCommand != "outputs" && strCommand != "status" && strCommand != "calcscore")) - throw runtime_error( - "masternode \"command\"...\n" - "\nSet of commands to execute masternode related actions\n" - "This command is deprecated, please see individual command documentation for future reference\n\n" - - "\nArguments:\n" - "1. \"command\" (string or set of strings, required) The command to execute\n" - - "\nAvailable commands:\n" - " count - Print count information of all known masternodes\n" - " current - Print info on current masternode winner\n" - " debug - Print masternode status\n" - " genkey - Generate new masternodeprivkey\n" - " outputs - Print masternode compatible outputs\n" - " start - Start masternode configured in phore.conf\n" - " start-alias - Start single masternode by assigned alias configured in masternode.conf\n" - " start- - Start masternodes configured in masternode.conf (: 'all', 'missing', 'disabled')\n" - " status - Print masternode status information\n" - " list - Print list of all known masternodes (see masternodelist for more info)\n" - " list-conf - Print masternode.conf in JSON format\n" - " winners - Print list of masternode winners\n"); - - if (strCommand == "list") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return listmasternodes(newParams, fHelp); - } - - if (strCommand == "connect") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodeconnect(newParams, fHelp); - } - - if (strCommand == "count") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodecount(newParams, fHelp); - } - - if (strCommand == "current") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodecurrent(newParams, fHelp); - } - - if (strCommand == "debug") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodedebug(newParams, fHelp); - } - - if (strCommand == "start" || strCommand == "start-alias" || strCommand == "start-many" || strCommand == "start-all" || strCommand == "start-missing" || strCommand == "start-disabled") { - return startmasternode(params, fHelp); - } - - if (strCommand == "genkey") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return createmasternodekey(newParams, fHelp); - } - - if (strCommand == "list-conf") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return listmasternodeconf(newParams, fHelp); - } - - if (strCommand == "outputs") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodeoutputs(newParams, fHelp); - } - - if (strCommand == "status") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodestatus(newParams, fHelp); - } - - if (strCommand == "winners") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodewinners(newParams, fHelp); - } - - if (strCommand == "calcscore") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodescores(newParams, fHelp); - } - - return NullUniValue; -} - UniValue listmasternodes(const UniValue& params, bool fHelp) { std::string strFilter = ""; @@ -198,7 +56,7 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) if (params.size() == 1) strFilter = params[0].get_str(); if (fHelp || (params.size() > 1)) - throw runtime_error( + throw std::runtime_error( "listmasternodes ( \"filter\" )\n" "\nGet a ranked list of masternodes\n" @@ -211,6 +69,7 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) " \"rank\": n, (numeric) Masternode Rank (or 0 if not enabled)\n" " \"txhash\": \"hash\", (string) Collateral transaction hash\n" " \"outidx\": n, (numeric) Collateral transaction output index\n" + " \"pubkey\": \"key\", (string) Masternode public key used for message broadcasting\n" " \"status\": s, (string) Status (ENABLED/EXPIRED/REMOVE/etc)\n" " \"addr\": \"addr\", (string) Masternode phore address\n" " \"version\": v, (numeric) Masternode protocol version\n" @@ -231,8 +90,8 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) if(!pindex) return 0; nHeight = pindex->nHeight; } - std::vector > vMasternodeRanks = mnodeman.GetMasternodeRanks(nHeight); - BOOST_FOREACH (PAIRTYPE(int, CMasternode) & s, vMasternodeRanks) { + std::vector > vMasternodeRanks = mnodeman.GetMasternodeRanks(nHeight); + for (PAIRTYPE(int, CMasternode) & s : vMasternodeRanks) { UniValue obj(UniValue::VOBJ); std::string strVin = s.second.vin.prevout.ToStringShort(); std::string strTxHash = s.second.vin.prevout.hash.ToString(); @@ -241,9 +100,9 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) CMasternode* mn = mnodeman.Find(s.second.vin); if (mn != NULL) { - if (strFilter != "" && strTxHash.find(strFilter) == string::npos && - mn->Status().find(strFilter) == string::npos && - EncodeDestination(CTxDestination(mn->pubKeyCollateralAddress.GetID())).find(strFilter) == string::npos) continue; + if (strFilter != "" && strTxHash.find(strFilter) == std::string::npos && + mn->Status().find(strFilter) == std::string::npos && + EncodeDestination(CTxDestination(mn->pubKeyCollateralAddress.GetID())).find(strFilter) == std::string::npos) continue; std::string strStatus = mn->Status(); std::string strHost; @@ -256,6 +115,7 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) obj.push_back(Pair("network", strNetwork)); obj.push_back(Pair("txhash", strTxHash)); obj.push_back(Pair("outidx", (uint64_t)oIdx)); + obj.push_back(Pair("pubkey", HexStr(mn->pubKeyMasternode))); obj.push_back(Pair("status", strStatus)); obj.push_back(Pair("addr", EncodeDestination(mn->pubKeyCollateralAddress.GetID()))); obj.push_back(Pair("version", mn->protocolVersion)); @@ -273,7 +133,7 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) UniValue masternodeconnect(const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 1)) - throw runtime_error( + throw std::runtime_error( "masternodeconnect \"address\"\n" "\nAttempts to connect to specified masternode address\n" @@ -292,14 +152,14 @@ UniValue masternodeconnect(const UniValue& params, bool fHelp) pnode->Release(); return NullUniValue; } else { - throw runtime_error("error connecting\n"); + throw std::runtime_error("error connecting\n"); } } UniValue getmasternodecount (const UniValue& params, bool fHelp) { if (fHelp || (params.size() > 0)) - throw runtime_error( + throw std::runtime_error( "getmasternodecount\n" "\nGet masternode count values\n" @@ -338,7 +198,7 @@ UniValue getmasternodecount (const UniValue& params, bool fHelp) UniValue masternodecurrent (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) - throw runtime_error( + throw std::runtime_error( "masternodecurrent\n" "\nGet current masternode winner\n" @@ -365,13 +225,13 @@ UniValue masternodecurrent (const UniValue& params, bool fHelp) return obj; } - throw runtime_error("unknown"); + throw std::runtime_error("unknown"); } UniValue masternodedebug (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) - throw runtime_error( + throw std::runtime_error( "masternodedebug\n" "\nPrint masternode status\n" @@ -384,10 +244,10 @@ UniValue masternodedebug (const UniValue& params, bool fHelp) return activeMasternode.GetStatus(); CTxIn vin = CTxIn(); - CPubKey pubkey = CScript(); + CPubKey pubkey; CKey key; if (!activeMasternode.GetMasterNodeVin(vin, pubkey, key)) - throw runtime_error("Missing masternode input, please look at the documentation for instructions on masternode creation\n"); + throw std::runtime_error("Missing masternode input, please look at the documentation for instructions on masternode creation\n"); else return activeMasternode.GetStatus(); } @@ -410,7 +270,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) if (fHelp || params.size() < 2 || params.size() > 3 || (params.size() == 2 && (strCommand != "local" && strCommand != "all" && strCommand != "many" && strCommand != "missing" && strCommand != "disabled")) || (params.size() == 3 && strCommand != "alias")) - throw runtime_error( + throw std::runtime_error( "startmasternode \"local|all|many|missing|disabled|alias\" lockwallet ( \"alias\" )\n" "\nAttempts to start one or more masternode(s)\n" @@ -441,7 +301,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); if (strCommand == "local") { - if (!fMasterNode) throw runtime_error("you must set masternode=1 in the configuration\n"); + if (!fMasterNode) throw std::runtime_error("you must set masternode=1 in the configuration\n"); if (activeMasternode.status != ACTIVE_MASTERNODE_STARTED) { activeMasternode.status = ACTIVE_MASTERNODE_INITIAL; // TODO: consider better way @@ -457,7 +317,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) if ((strCommand == "missing" || strCommand == "disabled") && (masternodeSync.RequestedMasternodeAssets <= MASTERNODE_SYNC_LIST || masternodeSync.RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED)) { - throw runtime_error("You can't use this command until masternode list is synced\n"); + throw std::runtime_error("You can't use this command until masternode list is synced\n"); } std::vector mnEntries; @@ -468,7 +328,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) UniValue resultsObj(UniValue::VARR); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; int nIndex; if(!mne.castOutputIndex(nIndex)) @@ -519,7 +379,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", alias)); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if (mne.getAlias() == alias) { found = true; std::string errorMessage; @@ -564,7 +424,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) UniValue createmasternodekey (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) - throw runtime_error( + throw std::runtime_error( "createmasternodekey\n" "\nCreate a new masternode private key\n" @@ -582,7 +442,7 @@ UniValue createmasternodekey (const UniValue& params, bool fHelp) UniValue getmasternodeoutputs (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) - throw runtime_error( + throw std::runtime_error( "getmasternodeoutputs\n" "\nPrint all masternode transaction outputs\n" @@ -599,10 +459,10 @@ UniValue getmasternodeoutputs (const UniValue& params, bool fHelp) HelpExampleCli("getmasternodeoutputs", "") + HelpExampleRpc("getmasternodeoutputs", "")); // Find possible candidates - vector possibleCoins = activeMasternode.SelectCoinsMasternode(); + std::vector possibleCoins = activeMasternode.SelectCoinsMasternode(); UniValue ret(UniValue::VARR); - BOOST_FOREACH (COutput& out, possibleCoins) { + for (COutput& out : possibleCoins) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txhash", out.tx->GetHash().ToString())); obj.push_back(Pair("outputidx", out.i)); @@ -619,7 +479,7 @@ UniValue listmasternodeconf (const UniValue& params, bool fHelp) if (params.size() == 1) strFilter = params[0].get_str(); if (fHelp || (params.size() > 1)) - throw runtime_error( + throw std::runtime_error( "listmasternodeconf ( \"filter\" )\n" "\nPrint masternode.conf in JSON format\n" @@ -647,7 +507,7 @@ UniValue listmasternodeconf (const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { int nIndex; if(!mne.castOutputIndex(nIndex)) continue; @@ -656,10 +516,10 @@ UniValue listmasternodeconf (const UniValue& params, bool fHelp) std::string strStatus = pmn ? pmn->Status() : "MISSING"; - if (strFilter != "" && mne.getAlias().find(strFilter) == string::npos && - mne.getIp().find(strFilter) == string::npos && - mne.getTxHash().find(strFilter) == string::npos && - strStatus.find(strFilter) == string::npos) continue; + if (strFilter != "" && mne.getAlias().find(strFilter) == std::string::npos && + mne.getIp().find(strFilter) == std::string::npos && + mne.getTxHash().find(strFilter) == std::string::npos && + strStatus.find(strFilter) == std::string::npos) continue; UniValue mnObj(UniValue::VOBJ); mnObj.push_back(Pair("alias", mne.getAlias())); @@ -677,7 +537,7 @@ UniValue listmasternodeconf (const UniValue& params, bool fHelp) UniValue getmasternodestatus (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) - throw runtime_error( + throw std::runtime_error( "getmasternodestatus\n" "\nPrint masternode status\n" @@ -694,7 +554,7 @@ UniValue getmasternodestatus (const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getmasternodestatus", "") + HelpExampleRpc("getmasternodestatus", "")); - if (!fMasterNode) throw runtime_error("This is not a masternode"); + if (!fMasterNode) throw std::runtime_error("This is not a masternode"); CMasternode* pmn = mnodeman.Find(activeMasternode.vin); @@ -708,14 +568,14 @@ UniValue getmasternodestatus (const UniValue& params, bool fHelp) mnObj.push_back(Pair("message", activeMasternode.GetStatus())); return mnObj; } - throw runtime_error("Masternode not found in the list of available masternodes. Current status: " + throw std::runtime_error("Masternode not found in the list of available masternodes. Current status: " + activeMasternode.GetStatus()); } UniValue getmasternodewinners (const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "getmasternodewinners ( blocks \"filter\" )\n" "\nPrint the masternode winners for the last n blocks\n" @@ -782,7 +642,7 @@ UniValue getmasternodewinners (const UniValue& params, bool fHelp) UniValue winner(UniValue::VARR); boost::char_separator sep(","); boost::tokenizer< boost::char_separator > tokens(strPayment, sep); - BOOST_FOREACH (const string& t, tokens) { + for (const std::string& t : tokens) { UniValue addr(UniValue::VOBJ); std::size_t pos = t.find(":"); std::string strAddress = t.substr(0,pos); @@ -816,7 +676,7 @@ UniValue getmasternodewinners (const UniValue& params, bool fHelp) UniValue getmasternodescores (const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getmasternodescores ( blocks )\n" "\nPrint list of winning masternode by score\n" @@ -836,8 +696,8 @@ UniValue getmasternodescores (const UniValue& params, bool fHelp) if (params.size() == 1) { try { nLast = std::stoi(params[0].get_str()); - } catch (const boost::bad_lexical_cast &) { - throw runtime_error("Exception on param 2"); + } catch (const std::invalid_argument&) { + throw std::runtime_error("Exception on param 2"); } } UniValue obj(UniValue::VOBJ); @@ -846,7 +706,7 @@ UniValue getmasternodescores (const UniValue& params, bool fHelp) for (int nHeight = chainActive.Tip()->nHeight - nLast; nHeight < chainActive.Tip()->nHeight + 20; nHeight++) { uint256 nHigh = 0; CMasternode* pBestMasternode = NULL; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { uint256 n = mn.CalculateScore(1, nHeight - 100); if (n > nHigh) { nHigh = n; @@ -866,7 +726,7 @@ bool DecodeHexMnb(CMasternodeBroadcast& mnb, std::string strHexMnb) { if (!IsHex(strHexMnb)) return false; - vector mnbData(ParseHex(strHexMnb)); + std::vector mnbData(ParseHex(strHexMnb)); CDataStream ssData(mnbData, SER_NETWORK, PROTOCOL_VERSION); try { ssData >> mnb; @@ -879,11 +739,11 @@ bool DecodeHexMnb(CMasternodeBroadcast& mnb, std::string strHexMnb) { } UniValue createmasternodebroadcast(const UniValue& params, bool fHelp) { - string strCommand; + std::string strCommand; if (params.size() >= 1) strCommand = params[0].get_str(); if (fHelp || (strCommand != "alias" && strCommand != "all") || (strCommand == "alias" && params.size() < 2)) - throw runtime_error( + throw std::runtime_error( "createmasternodebroadcast \"command\" ( \"alias\")\n" "\nCreates a masternode broadcast message for one or all masternodes configured in masternode.conf\n" + HelpRequiringPassphrase() + "\n" @@ -931,7 +791,7 @@ UniValue createmasternodebroadcast(const UniValue& params, bool fHelp) UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", alias)); - BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if(mne.getAlias() == alias) { found = true; std::string errorMessage; @@ -974,7 +834,7 @@ UniValue createmasternodebroadcast(const UniValue& params, bool fHelp) UniValue resultsObj(UniValue::VARR); - BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); @@ -1011,7 +871,7 @@ UniValue createmasternodebroadcast(const UniValue& params, bool fHelp) UniValue decodemasternodebroadcast(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "decodemasternodebroadcast \"hexstring\"\n" "\nCommand to decode masternode broadcast messages\n" @@ -1071,7 +931,7 @@ UniValue decodemasternodebroadcast(const UniValue& params, bool fHelp) UniValue relaymasternodebroadcast(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "relaymasternodebroadcast \"hexstring\"\n" "\nCommand to relay masternode broadcast messages\n" diff --git a/src/rpcmining.cpp b/src/rpc/mining.cpp similarity index 97% rename from src/rpcmining.cpp rename to src/rpc/mining.cpp index a5876dfa0650..272b3703be6b 100644 --- a/src/rpcmining.cpp +++ b/src/rpc/mining.cpp @@ -15,7 +15,7 @@ #include "miner.h" #include "net.h" #include "pow.h" -#include "rpcserver.h" +#include "server.h" #include "util.h" #include "validationinterface.h" #ifdef ENABLE_WALLET @@ -29,7 +29,6 @@ #include -using namespace std; /** * Return average network hashes per second based on the last 'lookup' blocks, @@ -77,7 +76,7 @@ UniValue GetNetworkHashPS(int lookup, int height) UniValue getnetworkhashps(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getnetworkhashps ( blocks height )\n" "\nReturns the estimated network hashes per second based on the last n blocks.\n" "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" @@ -98,7 +97,7 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp) UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getgenerate\n" "\nReturn if the server is set to generate coins or not. The default is false.\n" "It is set with the command line argument -gen (or phore.conf setting gen)\n" @@ -116,7 +115,7 @@ UniValue getgenerate(const UniValue& params, bool fHelp) UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "setgenerate generate ( genproclimit )\n" "\nSet 'generate' true or false to turn generation on or off.\n" "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n" @@ -206,7 +205,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) UniValue gethashespersec(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "gethashespersec\n" "\nReturns a recent hashes per second performance measurement while generating.\n" "See the getgenerate and setgenerate calls to turn generation on and off.\n" @@ -225,7 +224,7 @@ UniValue gethashespersec(const UniValue& params, bool fHelp) UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getmininginfo\n" "\nReturns a json object containing mining-related information." "\nResult:\n" @@ -270,7 +269,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) UniValue prioritisetransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) - throw runtime_error( + throw std::runtime_error( "prioritisetransaction \n" "Accepts the transaction into mined blocks at a higher (or lower) priority\n" "\nArguments:\n" @@ -317,7 +316,7 @@ static UniValue BIP22ValidationResult(const CValidationState& state) UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getblocktemplate ( \"jsonrequestobject\" )\n" "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" "It returns data needed to construct a block to work on.\n" @@ -446,7 +445,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; - boost::system_time checktxtime; + std::chrono::steady_clock::time_point checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) { @@ -464,15 +463,16 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) // Release the wallet and main lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { - checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); + checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - boost::unique_lock lock(csBestBlock); + WaitableLock lock(csBestBlock); while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { - if (!cvBlockChange.timed_wait(lock, checktxtime)) { + if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout) + { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; - checktxtime += boost::posix_time::seconds(10); + checktxtime += std::chrono::seconds(10); } } } @@ -519,9 +519,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); - map setTxIndex; + std::map setTxIndex; int i = 0; - BOOST_FOREACH (CTransaction& tx, pblock->vtx) { + for (CTransaction& tx : pblock->vtx) { uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; @@ -535,7 +535,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex())); UniValue deps(UniValue::VARR); - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); } @@ -626,7 +626,7 @@ class submitblock_StateCatcher : public CValidationInterface UniValue submitblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n" "\nAttempts to submit new block to network.\n" "The 'jsonparametersobject' parameter is currently ignored.\n" @@ -691,7 +691,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) UniValue estimatefee(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "estimatefee nblocks\n" "\nEstimates the approximate fee per kilobyte\n" "needed for a transaction to begin confirmation\n" @@ -722,7 +722,7 @@ UniValue estimatefee(const UniValue& params, bool fHelp) UniValue estimatepriority(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "estimatepriority nblocks\n" "\nEstimates the approximate priority\n" "a zero-fee transaction needs to begin confirmation\n" diff --git a/src/rpcmisc.cpp b/src/rpc/misc.cpp similarity index 94% rename from src/rpcmisc.cpp rename to src/rpc/misc.cpp index a709ff1e6138..df002b74e068 100644 --- a/src/rpcmisc.cpp +++ b/src/rpc/misc.cpp @@ -13,7 +13,7 @@ #include "masternode-sync.h" #include "net.h" #include "netbase.h" -#include "rpcserver.h" +#include "server.h" #include "spork.h" #include "timedata.h" #include "util.h" @@ -28,9 +28,6 @@ #include -using namespace boost; -using namespace boost::assign; -using namespace std; /** * @note Do not add or change anything in the information returned by this @@ -48,7 +45,7 @@ using namespace std; UniValue getinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getinfo\n" "Returns an object containing various state info.\n" "\nResult:\n" @@ -110,7 +107,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); - obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); + obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); @@ -123,7 +120,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("moneysupply",ValueFromAmount(chainActive.Tip()->nMoneySupply))); UniValue zphrObj(UniValue::VOBJ); for (auto denom : libzerocoin::zerocoinDenomList) { - zphrObj.push_back(Pair(to_string(denom), ValueFromAmount(chainActive.Tip()->mapZerocoinSupply.at(denom) * (denom*COIN)))); + zphrObj.push_back(Pair(std::to_string(denom), ValueFromAmount(chainActive.Tip()->mapZerocoinSupply.at(denom) * (denom*COIN)))); } zphrObj.push_back(Pair("total", ValueFromAmount(chainActive.Tip()->GetZerocoinSupply()))); obj.push_back(Pair("zPHRsupply", zphrObj)); @@ -155,7 +152,7 @@ UniValue mnsync(const UniValue& params, bool fHelp) strMode = params[0].get_str(); if (fHelp || params.size() != 1 || (strMode != "status" && strMode != "reset")) { - throw runtime_error( + throw std::runtime_error( "mnsync \"status|reset\"\n" "\nReturns the sync status or resets sync.\n" @@ -343,7 +340,7 @@ UniValue spork(const UniValue& params, bool fHelp) } } - throw runtime_error( + throw std::runtime_error( "spork []\n" " is the corresponding spork name, or 'show' to show all current spork settings, active to show which sporks are active" " is a epoch datetime to enable or disable spork" + @@ -353,7 +350,7 @@ UniValue spork(const UniValue& params, bool fHelp) UniValue validateaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "validateaddress \"bitcoinaddress\"\n" "\nReturn information about the given bitcoin address.\n" "\nArguments:\n" @@ -390,7 +387,7 @@ UniValue validateaddress(const UniValue& params, bool fHelp) if (isValid) { CTxDestination dest = DecodeDestination(params[0].get_str()); - string currentAddress = EncodeDestination(dest); + std::string currentAddress = EncodeDestination(dest); ret.push_back(Pair("address", currentAddress)); CScript scriptPubKey = GetScriptForDestination(dest); @@ -426,13 +423,13 @@ CScript _createmultisig_redeemScript(const UniValue& params) // Gather public keys if (nRequired < 1) - throw runtime_error("a multisignature address must require at least one key to redeem"); + throw std::runtime_error("a multisignature address must require at least one key to redeem"); if ((int)keys.size() < nRequired) - throw runtime_error( + throw std::runtime_error( strprintf("not enough keys supplied " "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); if (keys.size() > 16) - throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); + throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) @@ -448,10 +445,10 @@ CScript _createmultisig_redeemScript(const UniValue& params) CKeyID keyID = GetKeyForDestination(keystore, dest); CPubKey vchPubKey; if (!pwalletMain->GetPubKey(keyID, vchPubKey)) - throw runtime_error( + throw std::runtime_error( strprintf("no full public key for address %s",ks)); if (!vchPubKey.IsFullyValid()) - throw runtime_error(" Invalid public key: "+ks); + throw std::runtime_error(" Invalid public key: "+ks); pubkeys[i] = vchPubKey; } @@ -462,18 +459,18 @@ CScript _createmultisig_redeemScript(const UniValue& params) { CPubKey vchPubKey(ParseHex(ks)); if (!vchPubKey.IsFullyValid()) - throw runtime_error("Invalid public key: "+ks); + throw std::runtime_error("Invalid public key: "+ks); pubkeys[i] = vchPubKey; } else { - throw runtime_error("Invalid public key: "+ks); + throw std::runtime_error("Invalid public key: "+ks); } } CScript result = GetScriptForMultisig(nRequired, pubkeys); if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) - throw runtime_error( + throw std::runtime_error( strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)); return result; @@ -482,7 +479,7 @@ CScript _createmultisig_redeemScript(const UniValue& params) UniValue createmultisig(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 2) { - string msg = "createmultisig nrequired [\"key\",...]\n" + std::string msg = "createmultisig nrequired [\"key\",...]\n" "\nCreates a multi-signature address with n signature of m keys required.\n" "It returns a json object with the address and redeemScript.\n" @@ -504,7 +501,7 @@ UniValue createmultisig(const UniValue& params, bool fHelp) "\nCreate a multisig address from 2 addresses\n" + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + "\nAs a json rpc call\n" + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\""); - throw runtime_error(msg); + throw std::runtime_error(msg); } // Construct using pay-to-script-hash: @@ -522,7 +519,7 @@ UniValue createwitnessaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 1) { - string msg = "createwitnessaddress \"script\"\n" + std::string msg = "createwitnessaddress \"script\"\n" "\nCreates a witness address for a particular script.\n" "It returns a json object with the address and witness script.\n" @@ -536,7 +533,7 @@ UniValue createwitnessaddress(const UniValue& params, bool fHelp) " \"witnessScript\":\"script\" (string) The string value of the hex-encoded witness script.\n" "}\n" ; - throw runtime_error(msg); + throw std::runtime_error(msg); } if (!IsHex(params[0].get_str())) @@ -557,7 +554,7 @@ UniValue createwitnessaddress(const UniValue& params, bool fHelp) UniValue verifymessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) - throw runtime_error( + throw std::runtime_error( "verifymessage \"phoreaddress\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" @@ -575,9 +572,9 @@ UniValue verifymessage(const UniValue& params, bool fHelp) LOCK(cs_main); - string strAddress = params[0].get_str(); - string strSign = params[1].get_str(); - string strMessage = params[2].get_str(); + std::string strAddress = params[0].get_str(); + std::string strSign = params[1].get_str(); + std::string strMessage = params[2].get_str(); if (!IsValidDestinationString(strAddress)) @@ -591,7 +588,7 @@ UniValue verifymessage(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); bool fInvalid = false; - vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); + std::vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); if (fInvalid) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); @@ -610,7 +607,7 @@ UniValue verifymessage(const UniValue& params, bool fHelp) UniValue setmocktime(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "setmocktime timestamp\n" "\nSet the local time to given timestamp (-regtest only)\n" "\nArguments:\n" @@ -618,7 +615,7 @@ UniValue setmocktime(const UniValue& params, bool fHelp) " Pass 0 to go back to using the system time."); if (!Params().MineBlocksOnDemand()) - throw runtime_error("setmocktime for regression testing (-regtest mode) only"); + throw std::runtime_error("setmocktime for regression testing (-regtest mode) only"); LOCK(cs_main); @@ -632,7 +629,7 @@ UniValue setmocktime(const UniValue& params, bool fHelp) UniValue getstakingstatus(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getstakingstatus\n" "Returns an object containing various staking information.\n" "\nResult:\n" diff --git a/src/rpcnet.cpp b/src/rpc/net.cpp similarity index 92% rename from src/rpcnet.cpp rename to src/rpc/net.cpp index 3a93b2815790..84e300fa25f2 100644 --- a/src/rpcnet.cpp +++ b/src/rpc/net.cpp @@ -4,7 +4,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "server.h" #include "clientversion.h" #include "main.h" @@ -17,16 +17,14 @@ #include "util.h" #include "version.h" -#include -#include -using namespace std; +#include UniValue getconnectioncount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getconnectioncount\n" "\nReturns the number of connections to other nodes.\n" "\nbResult:\n" @@ -42,7 +40,7 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp) UniValue ping(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "ping\n" "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" @@ -53,7 +51,7 @@ UniValue ping(const UniValue& params, bool fHelp) // Request that each node send a ping during next message processing pass LOCK2(cs_main, cs_vNodes); - BOOST_FOREACH (CNode* pNode, vNodes) { + for (CNode* pNode : vNodes) { pNode->fPingQueued = true; } @@ -66,7 +64,7 @@ static void CopyNodeStats(std::vector& vstats) LOCK(cs_vNodes); vstats.reserve(vNodes.size()); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { CNodeStats stats; pnode->copyStats(stats); vstats.push_back(stats); @@ -76,7 +74,7 @@ static void CopyNodeStats(std::vector& vstats) UniValue getpeerinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getpeerinfo\n" "\nReturns data about each connected network node as a json array of objects.\n" "\nbResult:\n" @@ -113,12 +111,12 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) LOCK(cs_main); - vector vstats; + std::vector vstats; CopyNodeStats(vstats); UniValue ret(UniValue::VARR); - BOOST_FOREACH (const CNodeStats& stats, vstats) { + for (const CNodeStats& stats : vstats) { UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); @@ -148,7 +146,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("synced_headers", statestats.nSyncHeight)); obj.push_back(Pair("synced_blocks", statestats.nCommonHeight)); UniValue heights(UniValue::VARR); - BOOST_FOREACH (int height, statestats.vHeightInFlight) { + for (int height : statestats.vHeightInFlight) { heights.push_back(height); } obj.push_back(Pair("inflight", heights)); @@ -163,12 +161,12 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) UniValue addnode(const UniValue& params, bool fHelp) { - string strCommand; + std::string strCommand; if (params.size() == 2) strCommand = params[1].get_str(); if (fHelp || params.size() != 2 || (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) - throw runtime_error( + throw std::runtime_error( "addnode \"node\" \"add|remove|onetry\"\n" "\nAttempts add or remove a node from the addnode list.\n" "Or try a connection to a node once.\n" @@ -178,7 +176,7 @@ UniValue addnode(const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("addnode", "\"192.168.0.6:11771\" \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:11771\", \"onetry\"")); - string strNode = params[0].get_str(); + std::string strNode = params[0].get_str(); if (strCommand == "onetry") { CAddress addr; @@ -187,7 +185,7 @@ UniValue addnode(const UniValue& params, bool fHelp) } LOCK(cs_vAddedNodes); - vector::iterator it = vAddedNodes.begin(); + std::vector::iterator it = vAddedNodes.begin(); for (; it != vAddedNodes.end(); it++) if (strNode == *it) break; @@ -208,7 +206,7 @@ UniValue addnode(const UniValue& params, bool fHelp) UniValue disconnectnode(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "disconnectnode \"node\" \n" "\nImmediately disconnects from the specified node.\n" "\nArguments:\n" @@ -230,7 +228,7 @@ UniValue disconnectnode(const UniValue& params, bool fHelp) UniValue getaddednodeinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getaddednodeinfo dns ( \"node\" )\n" "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n" @@ -259,15 +257,15 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) bool fDns = params[0].get_bool(); - list laddedNodes(0); + std::list laddedNodes(0); if (params.size() == 1) { LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (std::string& strAddNode : vAddedNodes) laddedNodes.push_back(strAddNode); } else { - string strNode = params[1].get_str(); + std::string strNode = params[1].get_str(); LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (std::string& strAddNode : vAddedNodes) if (strAddNode == strNode) { laddedNodes.push_back(strAddNode); break; @@ -278,7 +276,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); if (!fDns) { - BOOST_FOREACH (string& strAddNode, laddedNodes) { + for (std::string& strAddNode : laddedNodes) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); ret.push_back(obj); @@ -286,11 +284,11 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) return ret; } - list > > laddedAddreses(0); - BOOST_FOREACH (string& strAddNode, laddedNodes) { - vector vservNode(0); + std::list > > laddedAddreses(0); + for (std::string& strAddNode : laddedNodes) { + std::vector vservNode(0); if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) - laddedAddreses.push_back(make_pair(strAddNode, vservNode)); + laddedAddreses.push_back(std::make_pair(strAddNode, vservNode)); else { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); @@ -301,17 +299,17 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) } LOCK(cs_vNodes); - for (list > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) { + for (std::list > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", it->first)); UniValue addresses(UniValue::VARR); bool fConnected = false; - BOOST_FOREACH (CService& addrNode, it->second) { + for (CService& addrNode : it->second) { bool fFound = false; UniValue node(UniValue::VOBJ); node.push_back(Pair("address", addrNode.ToString())); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->addr == addrNode) { fFound = true; fConnected = true; @@ -333,7 +331,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) UniValue getnettotals(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) - throw runtime_error( + throw std::runtime_error( "getnettotals\n" "\nReturns information about network traffic, including bytes in, bytes out,\n" "and current time.\n" @@ -366,7 +364,7 @@ static UniValue GetNetworksInfo() obj.push_back(Pair("name", GetNetworkName(network))); obj.push_back(Pair("limited", IsLimited(network))); obj.push_back(Pair("reachable", IsReachable(network))); - obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())); + obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string())); obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials)); networks.push_back(obj); } @@ -376,7 +374,7 @@ static UniValue GetNetworksInfo() UniValue getnetworkinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getnetworkinfo\n" "Returns an object containing various state info regarding P2P networking.\n" "\nResult:\n" @@ -413,8 +411,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); - obj.push_back(Pair("subversion", - FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()))); + obj.push_back(Pair("subversion", strSubVersion)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); obj.push_back(Pair("timeoffset", GetTimeOffset())); @@ -424,7 +421,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) UniValue localAddresses(UniValue::VARR); { LOCK(cs_mapLocalHost); - BOOST_FOREACH (const PAIRTYPE(CNetAddr, LocalServiceInfo) & item, mapLocalHost) { + for (const PAIRTYPE(CNetAddr, LocalServiceInfo) & item : mapLocalHost) { UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", item.first.ToString())); rec.push_back(Pair("port", item.second.nPort)); @@ -438,12 +435,12 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) UniValue setban(const UniValue& params, bool fHelp) { - string strCommand; + std::string strCommand; if (params.size() >= 2) strCommand = params[1].get_str(); if (fHelp || params.size() < 2 || (strCommand != "add" && strCommand != "remove")) - throw runtime_error( + throw std::runtime_error( "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n" "\nAttempts add or remove a IP/Subnet from the banned list.\n" "\nArguments:\n" @@ -461,7 +458,7 @@ UniValue setban(const UniValue& params, bool fHelp) CNetAddr netAddr; bool isSubnet = false; - if (params[0].get_str().find("/") != string::npos) + if (params[0].get_str().find("/") != std::string::npos) isSubnet = true; if (!isSubnet) @@ -506,7 +503,7 @@ UniValue setban(const UniValue& params, bool fHelp) UniValue listbanned(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "listbanned\n" "\nList all banned IPs/Subnets.\n" "\nExamples:\n" @@ -536,7 +533,7 @@ UniValue listbanned(const UniValue& params, bool fHelp) UniValue clearbanned(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "clearbanned\n" "\nClear all banned IPs.\n" "\nExamples:\n" diff --git a/src/rpcprotocol.cpp b/src/rpc/protocol.cpp similarity index 93% rename from src/rpcprotocol.cpp rename to src/rpc/protocol.cpp index 57752b3d47f2..bb3afc8db5c5 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpc/protocol.cpp @@ -7,7 +7,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "httpserver.h" -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "random.h" #include "tinyformat.h" #include "primitives/transaction.h" @@ -19,7 +19,6 @@ #include #include -using namespace std; /** * JSON-RPC protocol. Phore speaks version 1.0 for maximum compatibility, @@ -31,7 +30,7 @@ using namespace std; * http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx */ -string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id) +std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id) { UniValue request(UniValue::VOBJ); request.push_back(Pair("method", strMethod)); @@ -52,13 +51,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un return reply; } -string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) +std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) { UniValue reply = JSONRPCReplyObj(result, error, id); return reply.write() + "\n"; } -UniValue JSONRPCError(int code, const string& message) +UniValue JSONRPCError(int code, const std::string& message) { UniValue error(UniValue::VOBJ); error.push_back(Pair("code", code)); diff --git a/src/rpcprotocol.h b/src/rpc/protocol.h similarity index 100% rename from src/rpcprotocol.h rename to src/rpc/protocol.h diff --git a/src/rpcrawtransaction.cpp b/src/rpc/rawtransaction.cpp similarity index 92% rename from src/rpcrawtransaction.cpp rename to src/rpc/rawtransaction.cpp index 1a295598735d..b0771b65b511 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -14,7 +14,7 @@ #include "main.h" #include "net.h" #include "primitives/transaction.h" -#include "rpcserver.h" +#include "server.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" @@ -32,14 +32,11 @@ #include -using namespace boost; -using namespace boost::assign; -using namespace std; void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; - vector addresses; + std::vector addresses; int nRequired; out.push_back(Pair("asm", scriptPubKey.ToString())); @@ -55,7 +52,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud out.push_back(Pair("type", GetTxnOutputType(type))); UniValue a(UniValue::VARR); - BOOST_FOREACH (const CTxDestination& addr, addresses) + for (const CTxDestination& addr : addresses) a.push_back(EncodeDestination(addr)); out.push_back(Pair("addresses", a)); } @@ -133,7 +130,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, UniValue searchrawtransactions(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) - throw runtime_error("searchrawtransactions
    [verbose=1] [skip=0] [count=100]\n"); + throw std::runtime_error("searchrawtransactions
    [verbose=1] [skip=0] [count=100]\n"); if (!fAddrIndex) throw JSONRPCError(RPC_MISC_ERROR, "Address index not enabled"); @@ -180,7 +177,7 @@ UniValue searchrawtransactions(const UniValue& params, bool fHelp) } else { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ssTx << tx; - string strHex = HexStr(ssTx.begin(), ssTx.end()); + std::string strHex = HexStr(ssTx.begin(), ssTx.end()); result.push_back(strHex); } it++; @@ -191,7 +188,7 @@ UniValue searchrawtransactions(const UniValue& params, bool fHelp) UniValue getrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getrawtransaction \"txid\" ( verbose )\n" "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n" "or there is an unspent output in the utxo for this transaction. To make it always work,\n" @@ -269,7 +266,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); if (!fVerbose) { - string strHex = EncodeHexTx(tx, PROTOCOL_VERSION | RPCSerializationFlags()); + std::string strHex = EncodeHexTx(tx, PROTOCOL_VERSION | RPCSerializationFlags()); return strHex; } @@ -282,13 +279,13 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) UniValue listunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 4) - throw runtime_error( - "listunspent ( minconf maxconf [\"address\",...] )\n" + throw std::runtime_error( + "listunspent ( minconf maxconf [\"address\",...] watchonlyconfig )\n" "\nReturns array of unspent transaction outputs\n" "with between minconf and maxconf (inclusive) confirmations.\n" "Optionally filter to only include txouts paid to specified addresses.\n" "Results are an array of Objects, each of which has:\n" - "{txid, vout, scriptPubKey, amount, confirmations}\n" + "{txid, vout, scriptPubKey, amount, confirmations, spendable}\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" @@ -297,17 +294,19 @@ UniValue listunspent(const UniValue& params, bool fHelp) " \"address\" (string) phore address\n" " ,...\n" " ]\n" - "4. watchonlyconfig (numberic, optional, default=1) 1 = list regular unspent transactions, 2 = list only watchonly transactions, 3 = list all unspent transactions (including watchonly)\n" + "4. watchonlyconfig (numeric, optional, default=1) 1 = list regular unspent transactions, 2 = list only watchonly transactions, 3 = list all unspent transactions (including watchonly)\n" "\nResult\n" "[ (array of json object)\n" " {\n" - " \"txid\" : \"txid\", (string) the transaction id \n" + " \"txid\" : \"txid\", (string) the transaction id\n" " \"vout\" : n, (numeric) the vout value\n" " \"address\" : \"address\", (string) the phore address\n" " \"account\" : \"account\", (string) The associated account, or \"\" for the default account\n" " \"scriptPubKey\" : \"key\", (string) the script key\n" - " \"amount\" : x.xxx, (numeric) the transaction amount in phore\n" - " \"confirmations\" : n (numeric) The number of confirmations\n" + " \"redeemScript\" : \"key\", (string) the redeemscript key\n" + " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" + " \"confirmations\" : n, (numeric) The number of confirmations\n" + " \"spendable\" : true|false (boolean) Whether we have the private keys to spend this output\n" " }\n" " ,...\n" "]\n" @@ -325,17 +324,17 @@ UniValue listunspent(const UniValue& params, bool fHelp) if (params.size() > 1) nMaxDepth = params[1].get_int(); - set setAddress; + std::set setAddress; if (params.size() > 2) { UniValue inputs = params[2].get_array(); for (unsigned int inx = 0; inx < inputs.size(); inx++) { const UniValue& input = inputs[inx]; if (!IsValidDestinationString(input.get_str())) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Phore address: ") + input.get_str()); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Phore address: ") + input.get_str()); CTxDestination address = DecodeDestination(input.get_str()); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + input.get_str()); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str()); setAddress.insert(address); } } @@ -348,11 +347,11 @@ UniValue listunspent(const UniValue& params, bool fHelp) } UniValue results(UniValue::VARR); - vector vecOutputs; + std::vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, false, ALL_COINS, false, nWatchonlyConfig); - BOOST_FOREACH (const COutput& out, vecOutputs) { + for (const COutput& out : vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) continue; @@ -399,7 +398,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) UniValue createrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n" "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" "Returns hex-encoded raw transaction.\n" @@ -452,16 +451,16 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) rawTx.vin.push_back(in); } - set setAddress; - vector addrList = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, addrList) { + std::set setAddress; + std::vector addrList = sendTo.getKeys(); + for (const std::string& name_ : addrList) { if (!IsValidDestinationString(name_)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Phore address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Phore address: ")+name_); CTxDestination address = DecodeDestination(name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address); @@ -477,7 +476,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) UniValue decoderawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "decoderawtransaction \"hexstring\"\n" "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" @@ -544,7 +543,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp) UniValue decodescript(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "decodescript \"hex\"\n" "\nDecode a hex-encoded script.\n" "\nArguments:\n" @@ -570,7 +569,7 @@ UniValue decodescript(const UniValue& params, bool fHelp) UniValue r(UniValue::VOBJ); CScript script; if (params[0].get_str().size() > 0) { - vector scriptData(ParseHexV(params[0], "argument")); + std::vector scriptData(ParseHexV(params[0], "argument")); script = CScript(scriptData.begin(), scriptData.end()); } else { // Empty scripts are valid @@ -596,7 +595,7 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: UniValue signrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" "\nSign inputs for raw transaction (serialized, hex-encoded).\n" "The second optional argument (may be null) is an array of previous transaction outputs that\n" @@ -661,9 +660,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) #endif RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true); - vector txData(ParseHexV(params[0], "argument 1")); + std::vector txData(ParseHexV(params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); - vector txVariants; + std::vector txVariants; while (!ssData.empty()) { try { CMutableTransaction tx; @@ -691,7 +690,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { + for (const CTxIn& txin : mergedTx.vin) { const uint256& prevHash = txin.prevout.hash; CCoins coins; view.AccessCoins(prevHash); // this is certainly allowed to fail @@ -745,13 +744,13 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) if (nOut < 0) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); - vector pkData(ParseHexO(prevOut, "scriptPubKey")); + std::vector pkData(ParseHexO(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); { CCoinsModifier coins = view.ModifyCoins(txid); if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { - string err("Previous output scriptPubKey mismatch:\n"); + std::string err("Previous output scriptPubKey mismatch:\n"); err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n" + scriptPubKey.ToString(); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); @@ -777,7 +776,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) }); UniValue v = find_value(prevOut, "redeemScript"); if (!v.isNull()) { - vector rsData(ParseHexV(v, "redeemScript")); + std::vector rsData(ParseHexV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); } @@ -793,16 +792,16 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) int nHashType = SIGHASH_ALL; if (params.size() > 3 && !params[3].isNull()) { - static map mapSigHashValues = + static std::map mapSigHashValues = boost::assign::map_list_of - (string("ALL"), int(SIGHASH_ALL)) - (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) - (string("NONE"), int(SIGHASH_NONE)) - (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) - (string("SINGLE"), int(SIGHASH_SINGLE)) - (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) + (std::string("ALL"), int(SIGHASH_ALL)) + (std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) + (std::string("NONE"), int(SIGHASH_NONE)) + (std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) + (std::string("SINGLE"), int(SIGHASH_SINGLE)) + (std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) ; - string strHashType = params[3].get_str(); + std::string strHashType = params[3].get_str(); if (mapSigHashValues.count(strHashType)) nHashType = mapSigHashValues[strHashType]; else @@ -834,7 +833,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); // ... and merge in other signatures: - BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { + for (const CMutableTransaction& txv : txVariants) { sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i)); } @@ -860,7 +859,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) UniValue sendrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "sendrawtransaction \"hexstring\" ( allowhighfees )\n" "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" "\nAlso see createrawtransaction and signrawtransaction calls.\n" @@ -901,7 +900,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets if (fSwiftX) { - mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); + mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx)); CreateNewLock(tx); RelayTransactionLockReq(tx, true); } @@ -923,7 +922,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) UniValue getspentzerocoinamount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "getspentzerocoinamount hexstring index\n" "\nReturns value of spent zerocoin output designated by transaction hash and input index.\n" "\nArguments:\n" diff --git a/src/rpcserver.cpp b/src/rpc/server.cpp similarity index 90% rename from src/rpcserver.cpp rename to src/rpc/server.cpp index 3e7368c82749..dd274fb617c0 100644 --- a/src/rpcserver.cpp +++ b/src/rpc/server.cpp @@ -6,7 +6,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "server.h" #include "base58.h" #include "init.h" @@ -23,7 +23,7 @@ #include #include -#include + #include #include #include @@ -33,16 +33,13 @@ #include -using namespace RPCServer; -using namespace std; - static bool fRPCRunning = false; static bool fRPCInWarmup = true; static std::string rpcWarmupStatus("RPC server started"); static CCriticalSection cs_rpcWarmup; /* Timer-creating functions */ -static std::vector timerInterfaces; +static RPCTimerInterface* timerInterface = NULL; /* Map of name to timer. * @note Can be changed to std::unique_ptr when C++11 */ static std::map > deadlineTimers; @@ -76,17 +73,17 @@ void RPCServer::OnPostCommand(boost::function slot) } void RPCTypeCheck(const UniValue& params, - const list& typesExpected, + const std::list& typesExpected, bool fAllowNull) { unsigned int i = 0; - BOOST_FOREACH(UniValue::VType t, typesExpected) { + for (UniValue::VType t : typesExpected) { if (params.size() <= i) break; const UniValue& v = params[i]; if (!((v.type() == t) || (fAllowNull && (v.isNull())))) { - string err = strprintf("Expected type %s, got %s", + std::string err = strprintf("Expected type %s, got %s", uvTypeName(t), uvTypeName(v.type())); throw JSONRPCError(RPC_TYPE_ERROR, err); } @@ -95,16 +92,16 @@ void RPCTypeCheck(const UniValue& params, } void RPCTypeCheckObj(const UniValue& o, - const map& typesExpected, + const std::map& typesExpected, bool fAllowNull) { - BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected) { + for (const PAIRTYPE(std::string, UniValue::VType)& t : typesExpected) { const UniValue& v = find_value(o, t.first); if (!fAllowNull && v.isNull()) throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); if (!((v.type() == t.second) || (fAllowNull && (v.isNull())))) { - string err = strprintf("Expected type %s for %s, got %s", + std::string err = strprintf("Expected type %s for %s, got %s", uvTypeName(t.second), t.first, uvTypeName(v.type())); throw JSONRPCError(RPC_TYPE_ERROR, err); } @@ -138,9 +135,9 @@ UniValue ValueFromAmount(const CAmount& amount) strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder)); } -uint256 ParseHashV(const UniValue& v, string strName) +uint256 ParseHashV(const UniValue& v, std::string strName) { - string strHex; + std::string strHex; if (v.isStr()) strHex = v.get_str(); if (!IsHex(strHex)) // Note: IsHex("") is false @@ -149,25 +146,25 @@ uint256 ParseHashV(const UniValue& v, string strName) result.SetHex(strHex); return result; } -uint256 ParseHashO(const UniValue& o, string strKey) +uint256 ParseHashO(const UniValue& o, std::string strKey) { return ParseHashV(find_value(o, strKey), strKey); } -vector ParseHexV(const UniValue& v, string strName) +std::vector ParseHexV(const UniValue& v, std::string strName) { - string strHex; + std::string strHex; if (v.isStr()) strHex = v.get_str(); if (!IsHex(strHex)) throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')"); return ParseHex(strHex); } -vector ParseHexO(const UniValue& o, string strKey) +std::vector ParseHexO(const UniValue& o, std::string strKey) { return ParseHexV(find_value(o, strKey), strKey); } -int ParseInt(const UniValue& o, string strKey) +int ParseInt(const UniValue& o, std::string strKey) { const UniValue& v = find_value(o, strKey); if (v.isNum()) @@ -176,7 +173,7 @@ int ParseInt(const UniValue& o, string strKey) return v.get_int(); } -bool ParseBool(const UniValue& o, string strKey) +bool ParseBool(const UniValue& o, std::string strKey) { const UniValue& v = find_value(o, strKey); if (v.isBool()) @@ -190,22 +187,22 @@ bool ParseBool(const UniValue& o, string strKey) * Note: This interface may still be subject to change. */ -string CRPCTable::help(string strCommand) const +std::string CRPCTable::help(std::string strCommand) const { - string strRet; - string category; - set setDone; - vector > vCommands; + std::string strRet; + std::string category; + std::set setDone; + std::vector > vCommands; - for (map::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi) - vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second)); - sort(vCommands.begin(), vCommands.end()); + for (std::map::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi) + vCommands.push_back(std::make_pair(mi->second->category + mi->first, mi->second)); + std::sort(vCommands.begin(), vCommands.end()); - BOOST_FOREACH (const PAIRTYPE(string, const CRPCCommand*) & command, vCommands) { + for (const PAIRTYPE(std::string, const CRPCCommand*) & command : vCommands) { const CRPCCommand* pcmd = command.second; - string strMethod = pcmd->name; + std::string strMethod = pcmd->name; // We already filter duplicates, but these deprecated screw up the sort order - if (strMethod.find("label") != string::npos) + if (strMethod.find("label") != std::string::npos) continue; if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand) continue; @@ -221,16 +218,16 @@ string CRPCTable::help(string strCommand) const (*pfn)(params, true); } catch (std::exception& e) { // Help text is returned in an exception - string strHelp = string(e.what()); + std::string strHelp = std::string(e.what()); if (strCommand == "") { - if (strHelp.find('\n') != string::npos) + if (strHelp.find('\n') != std::string::npos) strHelp = strHelp.substr(0, strHelp.find('\n')); if (category != pcmd->category) { if (!category.empty()) strRet += "\n"; category = pcmd->category; - string firstLetter = category.substr(0, 1); + std::string firstLetter = category.substr(0, 1); boost::to_upper(firstLetter); strRet += "== " + firstLetter + category.substr(1) + " ==\n"; } @@ -247,7 +244,7 @@ string CRPCTable::help(string strCommand) const UniValue help(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "help ( \"command\" )\n" "\nList all commands, or get help for a specified command.\n" "\nArguments:\n" @@ -255,7 +252,7 @@ UniValue help(const UniValue& params, bool fHelp) "\nResult:\n" "\"text\" (string) The help text\n"); - string strCommand; + std::string strCommand; if (params.size() > 0) strCommand = params[0].get_str(); @@ -267,7 +264,7 @@ UniValue stop(const UniValue& params, bool fHelp) { // Accept the deprecated and ignored 'detach' boolean argument if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "stop\n" "\nStop Phore server."); // Shutdown will take long enough that the response should get back @@ -357,7 +354,6 @@ static const CRPCCommand vRPCCommands[] = {"hidden", "setmocktime", &setmocktime, true, false, false}, /* Phore features */ - {"phore", "masternode", &masternode, true, true, false}, {"phore", "listmasternodes", &listmasternodes, true, true, false}, {"phore", "createmasternodebroadcast", &createmasternodebroadcast, true, true, false}, {"phore", "decodemasternodebroadcast", &decodemasternodebroadcast, true, true, false}, @@ -373,7 +369,6 @@ static const CRPCCommand vRPCCommands[] = {"phore", "getmasternodestatus", &getmasternodestatus, true, true, false}, {"phore", "getmasternodewinners", &getmasternodewinners, true, true, false}, {"phore", "getmasternodescores", &getmasternodescores, true, true, false}, - {"phore", "mnbudget", &mnbudget, true, true, false}, {"phore", "preparebudget", &preparebudget, true, true, false}, {"phore", "submitbudget", &submitbudget, true, true, false}, {"phore", "mnbudgetvote", &mnbudgetvote, true, true, false}, @@ -474,7 +469,7 @@ CRPCTable::CRPCTable() const CRPCCommand *CRPCTable::operator[](const std::string &name) const { - map::const_iterator it = mapCommands.find(name); + std::map::const_iterator it = mapCommands.find(name); if (it == mapCommands.end()) return NULL; return (*it).second; @@ -625,36 +620,40 @@ std::vector CRPCTable::listCommands() const return commandList; } -std::string HelpExampleCli(string methodname, string args) +std::string HelpExampleCli(std::string methodname, std::string args) { return "> phore-cli " + methodname + " " + args + "\n"; } -std::string HelpExampleRpc(string methodname, string args) +std::string HelpExampleRpc(std::string methodname, std::string args) { return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:11772/\n"; } -void RPCRegisterTimerInterface(RPCTimerInterface *iface) +void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface) +{ + if (!timerInterface) + timerInterface = iface; +} + +void RPCSetTimerInterface(RPCTimerInterface *iface) { - timerInterfaces.push_back(iface); + timerInterface = iface; } -void RPCUnregisterTimerInterface(RPCTimerInterface *iface) +void RPCUnsetTimerInterface(RPCTimerInterface *iface) { - std::vector::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface); - assert(i != timerInterfaces.end()); - timerInterfaces.erase(i); + if (timerInterface == iface) + timerInterface = NULL; } void RPCRunLater(const std::string& name, boost::function func, int64_t nSeconds) { - if (timerInterfaces.empty()) + if (!timerInterface) throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); deadlineTimers.erase(name); - RPCTimerInterface* timerInterface = timerInterfaces[0]; LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); deadlineTimers.insert(std::make_pair(name, boost::shared_ptr(timerInterface->NewTimer(func, nSeconds*1000)))); } diff --git a/src/rpcserver.h b/src/rpc/server.h similarity index 96% rename from src/rpcserver.h rename to src/rpc/server.h index 7f36578114d2..de9fc6670537 100644 --- a/src/rpcserver.h +++ b/src/rpc/server.h @@ -8,7 +8,7 @@ #define BITCOIN_RPCSERVER_H #include "amount.h" -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "uint256.h" #include @@ -101,10 +101,12 @@ class RPCTimerInterface virtual RPCTimerBase* NewTimer(boost::function& func, int64_t millis) = 0; }; -/** Register factory function for timers */ -void RPCRegisterTimerInterface(RPCTimerInterface *iface); -/** Unregister factory function for timers */ -void RPCUnregisterTimerInterface(RPCTimerInterface *iface); +/** Set factory function for timers */ +void RPCSetTimerInterface(RPCTimerInterface *iface); +/** Set factory function for timers, but only if unset */ +void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface); +/** Unset factory function for timers */ +void RPCUnsetTimerInterface(RPCTimerInterface *iface); /** * Run func nSeconds from now. @@ -177,7 +179,7 @@ extern std::string HelpExampleRpc(std::string methodname, std::string args); extern void EnsureWalletIsUnlocked(bool fAllowAnonOnly = false); -extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp +extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpc/net.cpp extern UniValue getpeerinfo(const UniValue& params, bool fHelp); extern UniValue ping(const UniValue& params, bool fHelp); extern UniValue addnode(const UniValue& params, bool fHelp); @@ -188,7 +190,7 @@ extern UniValue setban(const UniValue& params, bool fHelp); extern UniValue listbanned(const UniValue& params, bool fHelp); extern UniValue clearbanned(const UniValue& params, bool fHelp); -extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpc/dump.cpp extern UniValue importprivkey(const UniValue& params, bool fHelp); extern UniValue importpubkey(const UniValue& params, bool fHelp); extern UniValue importaddress(const UniValue& params, bool fHelp); @@ -199,7 +201,7 @@ extern UniValue importwallet(const UniValue& params, bool fHelp); extern UniValue bip38encrypt(const UniValue& params, bool fHelp); extern UniValue bip38decrypt(const UniValue& params, bool fHelp); -extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp +extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpc/mining.cpp extern UniValue setgenerate(const UniValue& params, bool fHelp); extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); extern UniValue gethashespersec(const UniValue& params, bool fHelp); @@ -210,7 +212,7 @@ extern UniValue submitblock(const UniValue& params, bool fHelp); extern UniValue estimatefee(const UniValue& params, bool fHelp); extern UniValue estimatepriority(const UniValue& params, bool fHelp); -extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp +extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpc/wallet.cpp extern UniValue getaccountaddress(const UniValue& params, bool fHelp); extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp); extern UniValue setaccount(const UniValue& params, bool fHelp); @@ -278,7 +280,7 @@ extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); extern UniValue searchrawtransactions(const UniValue& params, bool fHelp); -extern UniValue findserial(const UniValue& params, bool fHelp); // in rpcblockchain.cpp +extern UniValue findserial(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp extern UniValue getblockcount(const UniValue& params, bool fHelp); extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); @@ -296,9 +298,8 @@ extern UniValue getchaintips(const UniValue& params, bool fHelp); extern UniValue invalidateblock(const UniValue& params, bool fHelp); extern UniValue reconsiderblock(const UniValue& params, bool fHelp); -extern UniValue obfuscation(const UniValue& params, bool fHelp); // in rpcmasternode.cpp +extern UniValue obfuscation(const UniValue& params, bool fHelp); // in rpc/masternode.cpp extern UniValue getpoolinfo(const UniValue& params, bool fHelp); -extern UniValue masternode(const UniValue& params, bool fHelp); extern UniValue listmasternodes(const UniValue& params, bool fHelp); extern UniValue getmasternodecount(const UniValue& params, bool fHelp); extern UniValue createmasternodebroadcast(const UniValue& params, bool fHelp); @@ -315,8 +316,7 @@ extern UniValue getmasternodestatus(const UniValue& params, bool fHelp); extern UniValue getmasternodewinners(const UniValue& params, bool fHelp); extern UniValue getmasternodescores(const UniValue& params, bool fHelp); -extern UniValue mnbudget(const UniValue& params, bool fHelp); // in rpcmasternode-budget.cpp -extern UniValue preparebudget(const UniValue& params, bool fHelp); +extern UniValue preparebudget(const UniValue& params, bool fHelp); // in rpc/budget.cpp extern UniValue submitbudget(const UniValue& params, bool fHelp); extern UniValue mnbudgetvote(const UniValue& params, bool fHelp); extern UniValue getbudgetvotes(const UniValue& params, bool fHelp); @@ -327,7 +327,7 @@ extern UniValue mnbudgetrawvote(const UniValue& params, bool fHelp); extern UniValue mnfinalbudget(const UniValue& params, bool fHelp); extern UniValue checkbudgets(const UniValue& params, bool fHelp); -extern UniValue getinfo(const UniValue& params, bool fHelp); // in rpcmisc.cpp +extern UniValue getinfo(const UniValue& params, bool fHelp); // in rpc/misc.cpp extern UniValue mnsync(const UniValue& params, bool fHelp); extern UniValue spork(const UniValue& params, bool fHelp); extern UniValue validateaddress(const UniValue& params, bool fHelp); diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index e926746b6d0a..752643d87b90 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -60,6 +60,13 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) return 0; } +struct ECCryptoClosure +{ + ECCVerifyHandle handle; +}; + +ECCryptoClosure instance_of_eccryptoclosure; + } // anon namespace int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 0b319536790c..96f90ebdeb79 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -10,14 +10,12 @@ #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "eccryptoverify.h" #include "pubkey.h" #include "script/script.h" #include "uint256.h" -using namespace std; -typedef vector valtype; +typedef std::vector valtype; namespace { @@ -58,10 +56,10 @@ bool CastToBool(const valtype& vch) */ #define stacktop(i) (stack.at(stack.size()+(i))) #define altstacktop(i) (altstack.at(altstack.size()+(i))) -static inline void popstack(vector& stack) +static inline void popstack(std::vector& stack) { if (stack.empty()) - throw runtime_error("popstack() : stack empty"); + throw std::runtime_error("popstack() : stack empty"); stack.pop_back(); } @@ -178,13 +176,14 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { if (!IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } - unsigned int nLenR = vchSig[3]; - unsigned int nLenS = vchSig[5+nLenR]; - const unsigned char *S = &vchSig[6+nLenR]; + // https://bitcoin.stackexchange.com/a/12556: + // Also note that inside transaction signatures, an extra hashtype byte + // follows the actual signature data. + std::vector vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1); // If the S value is above the order of the curve divided by two, its // complement modulo the order could have been used instead, which is // one byte shorter when encoded correctly. - if (!eccrypto::CheckSignatureElement(S, nLenS, true)) + if (!CPubKey::CheckLowS(vchSigCopy)) return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); return true; @@ -252,7 +251,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { return true; } -bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) +bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -267,8 +266,8 @@ bool EvalScript(vector >& stack, const CScript& script, un CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; - vector vfExec; - vector altstack; + std::vector vfExec; + std::vector altstack; set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if (script.size() > 10000) return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); @@ -857,15 +856,15 @@ bool EvalScript(vector >& stack, const CScript& script, un valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) - CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); + CRIPEMD160().Write(vch.data(), vch.size()).Finalize(vchHash.data()); else if (opcode == OP_SHA1) - CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); + CSHA1().Write(vch.data(), vch.size()).Finalize(vchHash.data()); else if (opcode == OP_SHA256) - CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); + CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data()); else if (opcode == OP_HASH160) - CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); + CHash160().Write(vch.data(), vch.size()).Finalize(vchHash.data()); else if (opcode == OP_HASH256) - CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); + CHash256().Write(vch.data(), vch.size()).Finalize(vchHash.data()); popstack(stack); stack.push_back(vchHash); } @@ -1218,14 +1217,14 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool TransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; // Hash type is one byte tacked on to the end of the signature - vector vchSig(vchSigIn); + std::vector vchSig(vchSigIn); if (vchSig.empty()) return false; int nHashType = vchSig.back(); @@ -1323,7 +1322,7 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { - vector > stack; + std::vector > stack; CScript scriptPubKey; if (witversion == 0) { @@ -1388,7 +1387,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } - vector > stack, stackCopy; + std::vector > stack, stackCopy; if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) // serror is set return false; @@ -1527,7 +1526,7 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) { CScript::const_iterator pc = scriptSig.begin(); - vector data; + std::vector data; while (pc < scriptSig.end()) { opcodetype opcode; scriptSig.GetOp(pc, opcode, data); diff --git a/src/script/script.cpp b/src/script/script.cpp index 57aa98d49a17..7ea1813f088b 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -17,7 +17,6 @@ inline std::string ValueString(const std::vector& vch) } } // anon namespace -using namespace std; const char* GetOpName(opcodetype opcode) { @@ -199,7 +198,7 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const // get the last item that the scriptSig // pushes onto the stack: const_iterator pc = scriptSig.begin(); - vector data; + std::vector data; while (pc < scriptSig.end()) { opcodetype opcode; diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 2c4c14ac26ed..ee6176455018 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -59,9 +59,7 @@ class CSignatureCache // and re-use a set of valid signatures just-slightly-greater // than our cache size. uint256 randomHash = GetRandHash(); - std::vector unused; - std::set::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); + std::set::iterator it = setValid.lower_bound(sigdata_type(randomHash)); if (it == setValid.end()) it = setValid.begin(); setValid.erase(*it); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index ba0860887716..99769e1ede66 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -12,11 +12,9 @@ #include "uint256.h" #include "util.h" -#include -using namespace std; -typedef vector valtype; +typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} @@ -41,14 +39,14 @@ extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR; static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) { - vector vchSig; + std::vector vchSig; if (!creator.CreateSig(vchSig, address, scriptCode, sigversion)) return false; ret.push_back(vchSig); return true; } -static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) +static bool SignN(const std::vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -75,7 +73,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP uint160 h160; ret.clear(); - vector vSolutions; + std::vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; @@ -129,10 +127,10 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP } } -static CScript PushAll(const vector& values) +static CScript PushAll(const std::vector& values) { CScript result; - BOOST_FOREACH(const valtype& v, values) { + for (const valtype& v : values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { @@ -237,18 +235,18 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); } -static vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const vector& vSolutions, - const vector& sigs1, const vector& sigs2, SigVersion sigversion) +static std::vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, + const std::vector& vSolutions, + const std::vector& sigs1, const std::vector& sigs2, SigVersion sigversion) { // Combine all the signatures we've got: - set allsigs; - BOOST_FOREACH(const valtype& v, sigs1) + std::set allsigs; + for (const valtype& v : sigs1) { if (!v.empty()) allsigs.insert(v); } - BOOST_FOREACH(const valtype& v, sigs2) + for (const valtype& v : sigs2) { if (!v.empty()) allsigs.insert(v); @@ -258,8 +256,8 @@ static vector CombineMultisig(const CScript& scriptPubKey, const BaseSi assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size()-2; - map sigs; - BOOST_FOREACH(const valtype& sig, allsigs) + std::map sigs; + for (const valtype& sig : allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { @@ -315,7 +313,7 @@ struct Stacks } static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const txnouttype txType, const vector& vSolutions, + const txnouttype txType, const std::vector& vSolutions, Stacks sigs1, Stacks sigs2, SigVersion sigversion) { switch (txType) @@ -351,7 +349,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; - vector > vSolutions2; + std::vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); @@ -371,7 +369,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature // Recur to combine: CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end()); txnouttype txType2; - vector vSolutions2; + std::vector vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.witness.pop_back(); sigs1.script = sigs1.witness; @@ -394,7 +392,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature const SignatureData& scriptSig1, const SignatureData& scriptSig2) { txnouttype txType; - vector > vSolutions; + std::vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 8441560d2c43..d93416a2303f 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -13,11 +13,10 @@ #include "util.h" #include "utilstrencodings.h" -#include -using namespace std; -typedef vector valtype; + +typedef std::vector valtype; unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; @@ -44,20 +43,20 @@ const char* GetTxnOutputType(txnouttype t) /** * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. */ -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutionsRet) +bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet) { // Templates - static multimap mTemplates; + static std::multimap mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature - mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); + mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey - mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); + mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); // Sender provides N pubkeys, receivers provides M signatures - mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); + mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); } vSolutionsRet.clear(); @@ -67,7 +66,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } @@ -76,7 +75,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 150) return false; - vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.end()); + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.end()); vSolutionsRet.push_back(hashBytes); return true; } @@ -115,13 +114,13 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector vch1, vch2; + std::vector vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); @@ -226,7 +225,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector vSolutions; + std::vector vSolutions; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; @@ -300,7 +299,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { - vector vSolutions; + std::vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; @@ -345,11 +344,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) return false; } -bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector& addressRet, int& nRequiredRet) +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; - vector vSolutions; + std::vector vSolutions; if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; if (typeRet == TX_NULL_DATA){ @@ -448,7 +447,7 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys) CScript script; script << CScript::EncodeOP_N(nRequired); - BOOST_FOREACH(const CPubKey& key, keys) + for (const CPubKey& key : keys) script << ToByteVector(key); script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; return script; diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index f0a54077a540..55d325aeefa9 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -1,7 +1,14 @@ bench_inv +bench_ecdh +bench_ecmult bench_sign bench_verify +bench_schnorr_verify +bench_recover +bench_internal tests +exhaustive_tests +gen_context *.exe *.so *.a @@ -20,16 +27,24 @@ config.status libtool .deps/ .dirstamp -build-aux/ *.lo *.o *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in -m4/libtool.m4 -m4/ltoptions.m4 -m4/ltsugar.m4 -m4/ltversion.m4 -m4/lt~obsolete.m4 +src/ecmult_static_context.h +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver src/stamp-h1 libsecp256k1.pc diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index 3a85e8cba0db..c4154e9a898c 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -1,27 +1,69 @@ -language: cpp -compiler: gcc -install: - - sudo apt-get install -qq libssl-dev - - if [ "$BIGNUM" = "gmp" -o "$BIGNUM" = "auto" -o "$FIELD" = "gmp" ]; then sudo apt-get install -qq libgmp-dev; fi - - if [ "$FIELD" = "64bit_asm" ]; then sudo apt-get install -qq yasm; fi +language: c +sudo: false +addons: + apt: + packages: libgmp-dev +compiler: + - clang + - gcc +cache: + directories: + - src/java/guava/ env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no BUILD=check EXTRAFLAGS= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no + - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar matrix: - - SCALAR=32bit + - SCALAR=32bit RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes - SCALAR=64bit - - FIELD=gmp - - FIELD=gmp ENDOMORPHISM=yes - - FIELD=64bit_asm - - FIELD=64bit_asm ENDOMORPHISM=yes - - FIELD=64bit + - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes - - FIELD=32bit + - 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=none - - BIGNUM=none ENDOMORPHISM=yes + - BIGNUM=no + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java JNI=yes ECDH=yes EXPERIMENTAL=yes +matrix: + fast_finish: true + include: + - compiler: clang + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 + - compiler: clang + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 +before_install: mkdir -p `dirname $GUAVA_JAR` +install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi before_script: ./autogen.sh -script: ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS && make -j2 $BUILD +script: + - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi + - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index dbf1790f3419..01fd0cd6de39 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -1,20 +1,22 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 lib_LTLIBRARIES = libsecp256k1.la -if USE_ASM -COMMON_LIB = libsecp256k1_common.la +if USE_JNI +JNI_LIB = libsecp256k1_jni.la +noinst_LTLIBRARIES = $(JNI_LIB) else -COMMON_LIB = +JNI_LIB = endif -noinst_LTLIBRARIES = $(COMMON_LIB) include_HEADERS = include/secp256k1.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 @@ -25,6 +27,8 @@ 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 @@ -36,54 +40,144 @@ 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/field_gmp.h -noinst_HEADERS += src/field_gmp_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_ASM -libsecp256k1_common_la_SOURCES = src/field_5x52_asm.asm +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 = -I$(top_srcdir)/include $(SECP_INCLUDES) -libsecp256k1_la_LIBADD = $(COMMON_LIB) $(SECP_LIBS) +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_LIBADD = $(JNI_LIB) $(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) noinst_PROGRAMS = if USE_BENCHMARK -noinst_PROGRAMS += bench_verify bench_sign bench_inv +noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult bench_verify_SOURCES = src/bench_verify.c -bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_verify_LDFLAGS = -static +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) -bench_sign_LDFLAGS = -static -bench_inv_SOURCES = src/bench_inv.c -bench_inv_LDADD = $(COMMON_LIB) $(SECP_LIBS) -bench_inv_LDFLAGS = -static -bench_inv_CPPFLAGS = $(SECP_INCLUDES) +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 $(SECP_INCLUDES) +bench_ecmult_SOURCES = src/bench_ecmult.c +bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) endif +TESTS = if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) -tests_LDADD = $(COMMON_LIB) $(SECP_LIBS) $(SECP_TEST_LIBS) +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 +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) +exhaustive_tests_LDFLAGS = -static +TESTS += exhaustive_tests +endif + +JAVAROOT=src/java +JAVAORG=org/bitcoin +JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar +CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) +JAVA_FILES= \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java + +if USE_JNI + +$(JAVA_GUAVA): + @echo Guava is missing. Fetch it via: \ + wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) + @false -EXTRA_DIST = autogen.sh nasm_lt.sh +.stamp-java: $(JAVA_FILES) + @echo Compiling $^ + $(AM_V_at)$(CLASSPATH_ENV) javac $^ + @touch $@ + +if USE_TESTS + +check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif +endif + +if USE_ECMULT_STATIC_PRECOMPUTATION +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) +CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function + +gen_context_OBJECTS = gen_context.o +gen_context_BIN = gen_context$(BUILD_EXEEXT) +gen_%.o: src/gen_%.c + $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + +$(gen_context_BIN): $(gen_context_OBJECTS) + $(CC_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 $(JAVAROOT)/$(JAVAORG)/*.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 -#x86_64 only -if USE_ASM -.asm.lo: - $(LIBTOOL) --mode=compile --tag YASM $(srcdir)/nasm_lt.sh $(YASM) -f $(YASM_BINFMT) $(YAFLAGS) -I$(srcdir) -I. $< -o $@ +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include endif diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index 1e49f4941660..8cd344ea8123 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -1,29 +1,33 @@ libsecp256k1 ============ -[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1) +[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) Optimized C library for EC operations on curve secp256k1. -This library is experimental, so use at your own risk. +This library is a work in progress and is being used to research best practices. Use at your own risk. Features: -* Low-level field and group operations on secp256k1. -* ECDSA signing/verification and key generation. +* secp256k1 ECDSA signing/verification and key generation. * 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 - * Avoid dynamic memory usage almost everywhere. + * 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. + * 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. - * Using GMP. * 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. @@ -33,14 +37,15 @@ Implementation details * 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 use secp256k1's efficiently-computable endomorphism to split the multiplicands into 4 half-sized ones first. + * 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. - * Slice the precomputed table in memory per byte, so memory access to the table becomes uniform. + * Access the table with branch-free conditional moves so memory access is uniform. * No data-dependent branches * 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. @@ -52,4 +57,5 @@ libsecp256k1 is built using autotools: $ ./autogen.sh $ ./configure $ make + $ ./tests $ sudo make install # optional diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 000000000000..cdc78d87d48b --- /dev/null +++ b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,145 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_JNI_INCLUDE_DIR +# +# DESCRIPTION +# +# AX_JNI_INCLUDE_DIR finds include directories needed for compiling +# programs using the JNI interface. +# +# JNI include directories are usually in the Java distribution. This is +# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in +# that order. When this macro completes, a list of directories is left in +# the variable JNI_INCLUDE_DIRS. +# +# Example usage follows: +# +# AX_JNI_INCLUDE_DIR +# +# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +# do +# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +# done +# +# If you want to force a specific compiler: +# +# - at the configure.in level, set JAVAC=yourcompiler before calling +# AX_JNI_INCLUDE_DIR +# +# - at the configure level, setenv JAVAC +# +# Note: This macro can work with the autoconf M4 macros for Java programs. +# This particular macro is not part of the original set of macros. +# +# LICENSE +# +# Copyright (c) 2008 Don Anderson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 14 + +AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) +AC_DEFUN([AX_JNI_INCLUDE_DIR],[ + +JNI_INCLUDE_DIRS="" + +if test "x$JAVA_HOME" != x; then + _JTOPDIR="$JAVA_HOME" +else + if test "x$JAVAC" = x; then + JAVAC=javac + fi + AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) + if test "x$_ACJNI_JAVAC" = xno; then + AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + fi + _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") + _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +fi + +case "$host_os" in + darwin*) # Apple Java headers are inside the Xcode bundle. + macos_version=$(sw_vers -productVersion | sed -n -e 's/^@<:@0-9@:>@*.\(@<:@0-9@:>@*\).@<:@0-9@:>@*/\1/p') + if @<:@ "$macos_version" -gt "7" @:>@; then + _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework" + _JINC="$_JTOPDIR/Headers" + else + _JTOPDIR="/System/Library/Frameworks/JavaVM.framework" + _JINC="$_JTOPDIR/Headers" + fi + ;; + *) _JINC="$_JTOPDIR/include";; +esac +_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) +_AS_ECHO_LOG([_JINC=$_JINC]) + +# On Mac OS X 10.6.4, jni.h is a symlink: +# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h +# -> ../../CurrentJDK/Headers/jni.h. +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ + if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi + fi +]) + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +freebsd*) _JNI_INC_SUBDIRS="freebsd";; +darwin*) _JNI_INC_SUBDIRS="darwin";; +linux*) _JNI_INC_SUBDIRS="linux genunix";; +osf*) _JNI_INC_SUBDIRS="alpha";; +solaris*) _JNI_INC_SUBDIRS="solaris";; +mingw*) _JNI_INC_SUBDIRS="win32";; +cygwin*) _JNI_INC_SUBDIRS="win32";; +*) _JNI_INC_SUBDIRS="genunix";; +esac + +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do + if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" + fi + done +fi +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# finally setting variable _ACJNI_FOLLOWED +# ---------------------------------------- +AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 000000000000..77fd346a79a6 --- /dev/null +++ b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 new file mode 100644 index 000000000000..3b3975cbdda8 --- /dev/null +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -0,0 +1,68 @@ +dnl libsecp25k1 helper checks +AC_DEFUN([SECP_INT128_CHECK],[ +has_int128=$ac_cv_type___int128 +]) + +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. +AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_MSG_CHECKING(for x86_64 assembly availability) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include ]],[[ + uint64_t a = 11, tmp; + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) +AC_MSG_RESULT([$has_64bit_asm]) +]) + +dnl +AC_DEFUN([SECP_OPENSSL_CHECK],[ + has_libcrypto=no + m4_ifdef([PKG_CHECK_MODULES],[ + PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) + if test x"$has_libcrypto" = x"yes"; then + TEMP_LIBS="$LIBS" + LIBS="$LIBS $CRYPTO_LIBS" + AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) + LIBS="$TEMP_LIBS" + fi + ]) + if test x$has_libcrypto = xno; then + AC_CHECK_HEADER(openssl/crypto.h,[ + AC_CHECK_LIB(crypto, main,[ + has_libcrypto=yes + CRYPTO_LIBS=-lcrypto + AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) + ]) + ]) + LIBS= + fi +if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then + AC_MSG_CHECKING(for EC functions in libcrypto) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include ]],[[ + EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); + ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); + ECDSA_verify(0, NULL, 0, NULL, 0, eckey); + EC_KEY_free(eckey); + ECDSA_SIG *sig_openssl; + sig_openssl = ECDSA_SIG_new(); + ECDSA_SIG_free(sig_openssl); + ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) + AC_MSG_RESULT([$has_openssl_ec]) +fi +]) + +dnl +AC_DEFUN([SECP_GMP_CHECK],[ +if test x"$has_gmp" != x"yes"; then + CPPFLAGS_TEMP="$CPPFLAGS" + CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" + LIBS_TEMP="$LIBS" + LIBS="$GMP_LIBS $LIBS" + AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) + CPPFLAGS="$CPPFLAGS_TEMP" + LIBS="$LIBS_TEMP" +fi +]) diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 017fd4e1d471..68c45a56f0aa 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -5,8 +5,8 @@ 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]) +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 @@ -17,20 +17,19 @@ PKG_PROG_PKG_CONFIG AC_PATH_TOOL(AR, ar) AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) +AX_PROG_CC_FOR_BUILD -AC_PROG_CC_C99 -if test x"$ac_cv_prog_cc_c99" == x"no"; then - AC_MSG_ERROR([c99 compiler support required]) +if test "x$CFLAGS" = "x"; then + CFLAGS="-g" fi -case $host in - *mingw*) - use_pkgconfig=no - ;; - *) - use_pkgconfig=yes - ;; -esac +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*) @@ -66,7 +65,7 @@ esac CFLAGS="$CFLAGS -W" -warn_CFLAGS="-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function" +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}]) @@ -76,62 +75,176 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], 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 is yes)]), [use_benchmark=$enableval], [use_benchmark=yes]) +AC_ARG_ENABLE(coverage, + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), + [enable_coverage=$enableval], + [enable_coverage=no]) + AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), [use_tests=$enableval], [use_tests=yes]) +AC_ARG_ENABLE(openssl_tests, + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), + [enable_openssl_tests=$enableval], + [enable_openssl_tests=auto]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), + [use_experimental=$enableval], + [use_experimental=no]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), + [use_exhaustive_tests=$enableval], + [use_exhaustive_tests=yes]) + AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), [use_endomorphism=$enableval], [use_endomorphism=no]) -AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=gmp|64bit|64bit_asm|32bit|auto], +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + [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_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), + [enable_module_recovery=$enableval], + [enable_module_recovery=no]) + +AC_ARG_ENABLE(jni, + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is no)]), + [use_jni=$enableval], + [use_jni=no]) + +AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) -AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|none|auto], +AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], [Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], [Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] +[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) + AC_CHECK_TYPES([__int128]) -AC_CHECK_DECL(__builtin_expect,AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]),,) +AC_MSG_CHECKING([for __builtin_expect]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], + [ AC_MSG_RESULT([no]) + ]) -if test x"$req_field" = x"auto"; then +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="--coverage" +else + CFLAGS="$CFLAGS -O3" +fi + +if test x"$use_ecmult_static_precomputation" != x"no"; then + save_cross_compiling=$cross_compiling + cross_compiling=no + TEMP_CC="$CC" + CC="$CC_FOR_BUILD" + AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], [return 0])], + [working_native_cc=yes], + [working_native_cc=no],[dnl]) + CC="$TEMP_CC" + cross_compiling=$save_cross_compiling + + if test x"$working_native_cc" = x"no"; then + set_precomp=no + if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + else + AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + fi + else + AC_MSG_RESULT([ok]) + 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_field=64bit_asm + 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_asm) - SECP_64BIT_ASM_CHECK - ;; 64bit) - SECP_INT128_CHECK - ;; - gmp) - SECP_GMP_CHECK + 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) ;; @@ -142,11 +255,9 @@ else fi if test x"$req_scalar" = x"auto"; then - if test x"$set_scalar" = x; then - SECP_INT128_CHECK - if test x"$has_int128" = x"yes"; then - set_scalar=64bit - fi + 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 @@ -156,6 +267,9 @@ else 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) ;; @@ -166,16 +280,24 @@ else 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=none + 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 ;; - none) + no) ;; *) AC_MSG_ERROR([invalid bignum implementation selection]) @@ -183,20 +305,28 @@ else 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_asm) - AC_DEFINE(USE_FIELD_5X52_ASM, 1, [Define this symbol to use the assembly version for the 5x52 field implementation]) - AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) - ;; 64bit) - AC_DEFINE(USE_FIELD_5X52_INT128, 1, [Define this symbol to use the __int128 version for the 5x52 field implementation]) AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) ;; -gmp) - AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed]) - AC_DEFINE(USE_FIELD_GMP, 1, [Define this symbol to use the FIELD_GMP implementation]) - ;; 32bit) AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) ;; @@ -213,7 +343,7 @@ gmp) 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]) ;; -none) +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]) @@ -238,21 +368,53 @@ esac if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK - if test x"$has_openssl_ec" == x"yes"; 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 + 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_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then +if test x"$set_bignum" = x"gmp"; then SECP_LIBS="$SECP_LIBS $GMP_LIBS" SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" fi @@ -261,20 +423,68 @@ 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_recovery" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery 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 + +AC_MSG_NOTICE([Using static precomputation: $set_precomp]) +AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) +AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) +AC_MSG_NOTICE([Building benchmarks: $use_benchmark]) +AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage]) +AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) +AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) +AC_MSG_NOTICE([Using jni: $use_jni]) + +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) -AC_SUBST(YASM_BINFMT) -AM_CONDITIONAL([USE_ASM], [test x"$set_field" == x"64bit_asm"]) +AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) -AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" != 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_RECOVERY], [test x"$enable_module_recovery" = 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" diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c new file mode 100644 index 000000000000..5b141a99481c --- /dev/null +++ b/src/secp256k1/contrib/lax_der_parsing.c @@ -0,0 +1,150 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_parsing.h" + +int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} + diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h new file mode 100644 index 000000000000..7eaf63bf6a0e --- /dev/null +++ b/src/secp256k1/contrib/lax_der_parsing.h @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file defines a function that parses DER with various errors and + * violations. This is not a part of the library itself, because the allowed + * violations are chosen arbitrarily and do not follow or establish any + * standard. + * + * In many places it matters that different implementations do not only accept + * the same set of valid signatures, but also reject the same set of signatures. + * The only means to accomplish that is by strictly obeying a standard, and not + * accepting anything else. + * + * Nonetheless, sometimes there is a need for compatibility with systems that + * use signatures which do not strictly obey DER. The snippet below shows how + * certain violations are easily supported. You may need to adapt it. + * + * Do not use this for new systems. Use well-defined DER or compact signatures + * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and + * secp256k1_ecdsa_signature_parse_compact). + * + * The supported violations are: + * - All numbers are parsed as nonnegative integers, even though X.609-0207 + * section 8.3.3 specifies that integers are always encoded as two's + * complement. + * - Integers can have length 0, even though section 8.3.1 says they can't. + * - Integers with overly long padding are accepted, violation section + * 8.3.2. + * - 127-byte long length descriptors are accepted, even though section + * 8.1.3.5.c says that they are not. + * - Trailing garbage data inside or after the signature is ignored. + * - The length descriptor of the sequence is ignored. + * + * Compared to for example OpenSSL, many violations are NOT supported: + * - Using overly long tag descriptors for the sequence or integers inside, + * violating section 8.1.2.2. + * - Encoding primitive integers as constructed values, violating section + * 8.3.1. + */ + +#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H +#define SECP256K1_CONTRIB_LAX_DER_PARSING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Parse a signature in "lax DER" format + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. In addition, it will accept signatures + * which violate the DER spec in various ways. Its purpose is to allow + * validation of the Bitcoin blockchain, which includes non-DER signatures + * from before the network rules were updated to enforce DER. Note that + * the set of supported violations is a strict subset of what OpenSSL will + * accept. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +int ecdsa_signature_parse_der_lax( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/secp256k1/contrib/lax_der_privatekey_parsing.c new file mode 100644 index 000000000000..c2e63b4b8d7b --- /dev/null +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.c @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_privatekey_parsing.h" + +int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h new file mode 100644 index 000000000000..fece261fb9ed --- /dev/null +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -0,0 +1,90 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file contains code snippets that parse DER private keys with + * various errors and violations. This is not a part of the library + * itself, because the allowed violations are chosen arbitrarily and + * do not follow or establish any standard. + * + * It also contains code to serialize private keys in a compatible + * manner. + * + * These functions are meant for compatibility with applications + * that require BER encoded keys. When working with secp256k1-specific + * code, the simple 32-byte private keys normally used by the + * library are sufficient. + */ + +#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H +#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Export a private key in DER format. + * + * Returns: 1 if the private key was valid. + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: privkey: pointer to an array for storing the private key in BER. + * Should have space for 279 bytes, and cannot be NULL. + * privkeylen: Pointer to an int where the length of the private key in + * privkey will be stored. + * In: seckey: pointer to a 32-byte secret key to export. + * compressed: 1 if the key should be exported in + * compressed format, 0 otherwise + * + * This function is purely meant for compatibility with applications that + * require BER encoded keys. When working with secp256k1-specific code, the + * simple 32-byte private keys are sufficient. + * + * Note that this function does not guarantee correct DER output. It is + * guaranteed to be parsable by secp256k1_ec_privkey_import_der + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( + const secp256k1_context* ctx, + unsigned char *privkey, + size_t *privkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. + * Returns: 1 if a private key was extracted. + * Args: ctx: pointer to a context object (cannot be NULL). + * Out: seckey: pointer to a 32-byte array for storing the private key. + * (cannot be NULL). + * In: privkey: pointer to a private key in DER format (cannot be NULL). + * privkeylen: length of the DER private key pointed to be privkey. + * + * This function will accept more than just strict DER, and even allow some BER + * violations. The public key stored inside the DER-encoded private key is not + * verified for correctness, nor are the curve parameters. Use this function + * only if you know in advance it is supposed to contain a secp256k1 private + * key. + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *privkey, + size_t privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index 94a6ef483f32..3c4a311a0568 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -1,9 +1,109 @@ -#ifndef _SECP256K1_ -# define _SECP256K1_ +#ifndef SECP256K1_H +#define SECP256K1_H -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif + +#include + +/* These rules specify the order of arguments in API calls: + * + * 1. Context pointers go first, followed by output arguments, combined + * output/input arguments, and finally input-only arguments. + * 2. Array lengths always immediately the follow the argument whose length + * they describe, even if this violates rule 1. + * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated + * later go first. This means: signatures, public nonces, private nonces, + * messages, public keys, secret keys, tweaks. + * 4. Arguments that are not data pointers go last, from more complex to less + * complex: function pointers, algorithm names, messages, void pointers, + * counts, flags, booleans. + * 5. Opaque data pointers follow the function pointer they are to be passed to. + */ + +/** Opaque data structure that holds context information (precomputed tables etc.). + * + * The purpose of context structures is to cache large precomputed data tables + * that are expensive to construct, and also to maintain the randomization data + * for blinding. + * + * Do not create a new context object for each operation, as construction is + * far slower than all other API calls (~100 times slower than an ECDSA + * verification). + * + * A constructed context can safely be used from multiple threads + * simultaneously, but API call that take a non-const pointer to a context + * need exclusive access to it. In particular this is the case for + * secp256k1_context_destroy and secp256k1_context_randomize. + * + * Regarding randomization, either do it once at creation time (in which case + * you do not need any locking for the other calls), or use a read-write lock. + */ +typedef struct secp256k1_context_struct secp256k1_context; + +/** Opaque data structure that holds rewriteable "scratch space" + * + * The purpose of this structure is to replace dynamic memory allocations, + * because we target architectures where this may not be available. It is + * essentially a resizable (within specified parameters) block of bytes, + * which is initially created either by memory allocation or TODO as a pointer + * into some fixed rewritable space. + * + * Unlike the context object, this cannot safely be shared between threads + * without additional synchronization logic. + */ +typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space; + +/** Opaque data structure that holds a parsed and valid public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_pubkey; + +/** Opaque data structured that holds a parsed ECDSA signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_ecdsa_signature; + +/** A pointer to a function to deterministically generate a nonce. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). + * data: Arbitrary data pointer that is passed through. + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the algorithm, the key and the attempt. + */ +typedef int (*secp256k1_nonce_function)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *algo16, + void *data, + unsigned int attempt +); # if !defined(SECP256K1_GNUC_PREREQ) # if defined(__GNUC__)&&defined(__GNUC_MINOR__) @@ -26,6 +126,20 @@ extern "C" { # define SECP256K1_INLINE inline # endif +#ifndef SECP256K1_API +# if defined(_WIN32) +# ifdef SECP256K1_BUILD +# define SECP256K1_API __declspec(dllexport) +# else +# define SECP256K1_API +# endif +# elif defined(__GNUC__) && defined(SECP256K1_BUILD) +# define SECP256K1_API __attribute__ ((visibility ("default"))) +# else +# define SECP256K1_API +# endif +#endif + /**Warning attributes * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out * some paranoid null checks. */ @@ -40,201 +154,501 @@ extern "C" { # define SECP256K1_ARG_NONNULL(_x) # endif +/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/** The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) -/** Flags to pass to secp256k1_start. */ -# define SECP256K1_START_VERIFY (1 << 0) -# define SECP256K1_START_SIGN (1 << 1) +/** Flags to pass to secp256k1_context_create. */ +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) -/** Initialize the library. This may take some time (10-100 ms). - * You need to call this before calling any other function. - * It cannot run in parallel with any other functions, but once - * secp256k1_start() returns, all other functions are thread-safe. +/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) + +/** Prefix byte used to tag various encoded curvepoints for specific purposes */ +#define SECP256K1_TAG_PUBKEY_EVEN 0x02 +#define SECP256K1_TAG_PUBKEY_ODD 0x03 +#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 +#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 +#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 + +/** Create a secp256k1 context object. + * + * Returns: a newly created context object. + * In: flags: which parts of the context to initialize. + * + * See also secp256k1_context_randomize. + */ +SECP256K1_API secp256k1_context* secp256k1_context_create( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copies a secp256k1 context object. + * + * Returns: a newly created context object. + * Args: ctx: an existing context to copy (cannot be NULL) + */ +SECP256K1_API secp256k1_context* secp256k1_context_clone( + const secp256k1_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object. + * + * The context pointer may not be used afterwards. + * Args: ctx: an existing context to destroy (cannot be NULL) */ -void secp256k1_start(unsigned int flags); +SECP256K1_API void secp256k1_context_destroy( + secp256k1_context* ctx +); -/** Free all memory associated with this library. After this, no - * functions can be called anymore, except secp256k1_start() +/** Set a callback function to be called when an illegal argument is passed to + * an API call. It will only trigger for violations that are mentioned + * explicitly in the header. + * + * The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer + * (NULL restores a default handler that calls abort). + * data: the opaque pointer to pass to fun above. */ -void secp256k1_stop(void); +SECP256K1_API void secp256k1_context_set_illegal_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Set a callback function to be called when an internal consistency check + * fails. The default is crashing. + * + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores a default + * handler that calls abort). + * data: the opaque pointer to pass to fun above. + */ +SECP256K1_API void secp256k1_context_set_error_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Create a secp256k1 scratch space object. + * + * Returns: a newly created scratch space. + * Args: ctx: an existing context object (cannot be NULL) + * In: max_size: maximum amount of memory to allocate + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create( + const secp256k1_context* ctx, + size_t max_size +) SECP256K1_ARG_NONNULL(1); + +/** Destroy a secp256k1 scratch space. + * + * The pointer may not be used afterwards. + * Args: scratch: space to destroy + */ +SECP256K1_API void secp256k1_scratch_space_destroy( + secp256k1_scratch_space* scratch +); + +/** Parse a variable-length public key into the pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * Args: ctx: a secp256k1 context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( + const secp256k1_context* ctx, + secp256k1_pubkey* pubkey, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. + */ +SECP256K1_API int secp256k1_ec_pubkey_serialize( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_pubkey* pubkey, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail validation for any + * message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a DER ECDSA signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_der( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: output: a pointer to an array to store the DER serialization + * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + * In: sig: a pointer to an initialized signature object + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array to store the compact serialization + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Verify an ECDSA signature. + * * Returns: 1: correct signature - * 0: incorrect signature - * -1: invalid public key - * -2: invalid signature - * In: msg: the message being verified (cannot be NULL) - * msglen: the length of the message (at most 32) - * sig: the signature being verified (cannot be NULL) - * siglen: the length of the signature - * pubkey: the public key to verify with (cannot be NULL) - * pubkeylen: the length of pubkey - * Requires starting using SECP256K1_START_VERIFY. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const unsigned char *msg, - int msglen, - const unsigned char *sig, - int siglen, - const unsigned char *pubkey, - int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context* ctx, + const secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); + +/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; + +/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. + * * Returns: 1: signature created - * 0: nonce invalid, try another one - * In: msg: the message being signed (cannot be NULL) - * msglen: the length of the message being signed (at most 32) - * seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid) - * nonce: pointer to a 32-byte nonce (cannot be NULL, generated with a cryptographic PRNG) + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In/Out: siglen: pointer to an int with the length of sig, which will be updated - * to contain the actual signature length (<=72). - * Requires starting using SECP256K1_START_SIGN. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_sign( - const unsigned char *msg, - int msglen, - unsigned char *sig, - int *siglen, - const unsigned char *seckey, - const unsigned char *nonce -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Create a compact ECDSA signature (64 byte + recovery id). - * Returns: 1: signature created - * 0: nonce invalid, try another one - * In: msg: the message being signed (cannot be NULL) - * msglen: the length of the message being signed (at most 32) - * seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid) - * nonce: pointer to a 32-byte nonce (cannot be NULL, generated with a cryptographic PRNG) - * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) - * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) - * Requires starting using SECP256K1_START_SIGN. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_sign_compact( - const unsigned char *msg, - int msglen, - unsigned char *sig64, - const unsigned char *seckey, - const unsigned char *nonce, - int *recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Recover an ECDSA public key from a compact signature. - * Returns: 1: public key successfully recovered (which guarantees a correct signature). - * 0: otherwise. - * In: msg: the message assumed to be signed (cannot be NULL) - * msglen: the length of the message (at most 32) - * sig64: signature as 64 byte array (cannot be NULL) - * compressed: whether to recover a compressed or uncompressed pubkey - * recid: the recovery id (0-3, as returned by ecdsa_sign_compact) - * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL) - * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL) - * Requires starting using SECP256K1_START_VERIFY. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( - const unsigned char *msg, - int msglen, - const unsigned char *sig64, - unsigned char *pubkey, - int *pubkeylen, - int compressed, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. + */ +SECP256K1_API int secp256k1_ecdsa_sign( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Verify an ECDSA secret key. + * * Returns: 1: secret key is valid * 0: secret key is invalid + * Args: ctx: pointer to a context object (cannot be NULL) * In: seckey: pointer to a 32-byte secret key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(const unsigned char *seckey) SECP256K1_ARG_NONNULL(1); - -/** Just validate a public key. - * Returns: 1: valid public key - * 0: invalid public key - * In: pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). - * pubkeylen: length of pubkey - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify(const unsigned char *pubkey, int pubkeylen) SECP256K1_ARG_NONNULL(1); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context* ctx, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Compute the public key for a secret key. - * In: compressed: whether the computed public key should be compressed - * seckey: pointer to a 32-byte private key (cannot be NULL) - * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) - * area to store the public key (cannot be NULL) - * pubkeylen: pointer to int that will be updated to contains the pubkey's - * length (cannot be NULL) + * * Returns: 1: secret was valid, public key stores - * 0: secret was invalid, try again. - * Requires starting using SECP256K1_START_SIGN. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - unsigned char *pubkey, - int *pubkeylen, - const unsigned char *seckey, - int compressed + * 0: secret was invalid, try again + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: pubkey: pointer to the created public key (cannot be NULL) + * In: seckey: pointer to a 32-byte private key (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Decompress a public key. - * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. - It must contain a 33-byte or 65-byte public key already (cannot be NULL) - * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) - It will be updated to reflect the new size. - * Returns: 0 if the passed public key was invalid, 1 otherwise. If 1 is returned, the - pubkey is replaced with its decompressed version. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( - unsigned char *pubkey, - int *pubkeylen +/** Negates a private key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: seckey: pointer to the 32-byte private key to be negated (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( + const secp256k1_context* ctx, + unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Export a private key in DER format. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( - const unsigned char *seckey, - unsigned char *privkey, - int *privkeylen, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Import a private key in DER format. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( - unsigned char *seckey, - const unsigned char *privkey, - int privkeylen +/** Negates a public key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Tweak a private key by adding tweak to it. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - unsigned char *seckey, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +/** Tweak a private key by adding tweak to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting private key + * would be invalid (only when the tweak is the complement of the + * private key). 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a public key by adding tweak times the generator to it. - * Requires starting with SECP256K1_START_VERIFY. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting public key + * would be invalid (only when the tweak is the complement of the + * corresponding private key). 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key object. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak a private key by multiplying it with tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - unsigned char *seckey, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +/** Tweak a private key by multiplying it by a tweak. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak a public key by multiplying it with tweak. - * Requires starting with SECP256K1_START_VERIFY. +/** Tweak a public key by multiplying it by a tweak value. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key obkect. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -# ifdef __cplusplus -} -# endif +/** Updates the context randomization to protect against side-channel leakage. + * Returns: 1: randomization successfully updated + * 0: error + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * + * While secp256k1 code is written to be constant-time no matter what secret + * values are, it's possible that a future compiler may output code which isn't, + * and also that the CPU may not emit the same radio frequencies or draw the same + * amount power for all values. + * + * This function provides a seed which is combined into the blinding value: that + * blinding value is added before each multiplication (and removed afterwards) so + * that it does not affect function results, but shields against attacks which + * rely on any input-dependent behaviour. + * + * You should call this after secp256k1_context_create or + * secp256k1_context_clone, and may call this repeatedly afterwards. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context* ctx, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1); + +/** Add a number of public keys together. + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * Args: ctx: pointer to a context object + * Out: out: pointer to a public key object for placing the resulting public key + * (cannot be NULL) + * In: ins: pointer to array of pointers to public keys (cannot be NULL) + * n: the number of public keys to add together (must be at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( + const secp256k1_context* ctx, + secp256k1_pubkey *out, + const secp256k1_pubkey * const * ins, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +#ifdef __cplusplus +} #endif + +#endif /* SECP256K1_H */ diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 000000000000..df5fde235c7b --- /dev/null +++ b/src/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,55 @@ +#ifndef SECP256K1_ECDH_H +#define SECP256K1_ECDH_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A pointer to a function that applies hash function to a point + * + * Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail + * Out: output: pointer to an array to be filled by the function + * In: x: pointer to a 32-byte x coordinate + * y: pointer to a 32-byte y coordinate + * data: Arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ecdh_hash_function)( + unsigned char *output, + const unsigned char *x, + const unsigned char *y, + void *data +); + +/** An implementation of SHA256 hash function that applies to compressed public key. */ +SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; + +/** A default ecdh hash function (currently equal to secp256k1_ecdh_hash_function_sha256). */ +SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; + +/** Compute an EC Diffie-Hellman secret in constant time + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: output: pointer to an array to be filled by the function + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point + * hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used + * data: Arbitrary data pointer that is passed through + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context* ctx, + unsigned char *output, + const secp256k1_pubkey *pubkey, + const unsigned char *privkey, + secp256k1_ecdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ECDH_H */ diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h new file mode 100644 index 000000000000..cf6c5ed7f5e3 --- /dev/null +++ b/src/secp256k1/include/secp256k1_recovery.h @@ -0,0 +1,110 @@ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structured that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct { + unsigned char data[65]; +} secp256k1_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature* sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Out: sig: a pointer to a normal signature (cannot be NULL). + * In: sigin: a pointer to a recoverable signature (cannot be NULL). + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const secp256k1_ecdsa_recoverable_signature* sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) + * recid: a pointer to an integer to hold the recovery id (can be NULL). + * In: sig: a pointer to an initialized signature object (cannot be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_recoverable_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_sign_recoverable( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Out: pubkey: pointer to the recovered public key (cannot be NULL) + * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_RECOVERY_H */ diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in index 1c72dd00037b..a0d006f1131f 100644 --- a/src/secp256k1/libsecp256k1.pc.in +++ b/src/secp256k1/libsecp256k1.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: libsecp256k1 Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin/secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs.private: @SECP_LIBS@ diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage new file mode 100644 index 000000000000..8521f0799932 --- /dev/null +++ b/src/secp256k1/sage/group_prover.sage @@ -0,0 +1,322 @@ +# This code supports verifying group implementations which have branches +# or conditional statements (like cmovs), by allowing each execution path +# to independently set assumptions on input or intermediary variables. +# +# The general approach is: +# * A constraint is a tuple of two sets of symbolic expressions: +# the first of which are required to evaluate to zero, the second of which +# are required to evaluate to nonzero. +# - A constraint is said to be conflicting if any of its nonzero expressions +# is in the ideal with basis the zero expressions (in other words: when the +# zero expressions imply that one of the nonzero expressions are zero). +# * There is a list of laws that describe the intended behaviour, including +# laws for addition and doubling. Each law is called with the symbolic point +# coordinates as arguments, and returns: +# - A constraint describing the assumptions under which it is applicable, +# called "assumeLaw" +# - A constraint describing the requirements of the law, called "require" +# * Implementations are transliterated into functions that operate as well on +# algebraic input points, and are called once per combination of branches +# executed. Each execution returns: +# - A constraint describing the assumptions this implementation requires +# (such as Z1=1), called "assumeFormula" +# - A constraint describing the assumptions this specific branch requires, +# but which is by construction guaranteed to cover the entire space by +# merging the results from all branches, called "assumeBranch" +# - The result of the computation +# * All combinations of laws with implementation branches are tried, and: +# - If the combination of assumeLaw, assumeFormula, and assumeBranch results +# in a conflict, it means this law does not apply to this branch, and it is +# skipped. +# - For others, we try to prove the require constraints hold, assuming the +# information in assumeLaw + assumeFormula + assumeBranch, and if this does +# not succeed, we fail. +# + To prove an expression is zero, we check whether it belongs to the +# ideal with the assumed zero expressions as basis. This test is exact. +# + To prove an expression is nonzero, we check whether each of its +# factors is contained in the set of nonzero assumptions' factors. +# This test is not exact, so various combinations of original and +# reduced expressions' factors are tried. +# - If we succeed, we print out the assumptions from assumeFormula that +# weren't implied by assumeLaw already. Those from assumeBranch are skipped, +# as we assume that all constraints in it are complementary with each other. +# +# Based on the sage verification scripts used in the Explicit-Formulas Database +# by Tanja Lange and others, see http://hyperelliptic.org/EFD + +class fastfrac: + """Fractions over rings.""" + + def __init__(self,R,top,bot=1): + """Construct a fractional, given a ring, a numerator, and denominator.""" + self.R = R + if parent(top) == ZZ or parent(top) == R: + self.top = R(top) + self.bot = R(bot) + elif top.__class__ == fastfrac: + self.top = top.top + self.bot = top.bot * bot + else: + self.top = R(numerator(top)) + self.bot = R(denominator(top)) * bot + + def iszero(self,I): + """Return whether this fraction is zero given an ideal.""" + return self.top in I and self.bot not in I + + def reduce(self,assumeZero): + zero = self.R.ideal(map(numerator, assumeZero)) + return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) + + def __add__(self,other): + """Add two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top + self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __sub__(self,other): + """Subtract two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top - self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __neg__(self): + """Return the negation of a fraction.""" + return fastfrac(self.R,-self.top,self.bot) + + def __mul__(self,other): + """Multiply two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.top,self.bot * other.bot) + return NotImplemented + + def __rmul__(self,other): + """Multiply something else with a fraction.""" + return self.__mul__(other) + + def __div__(self,other): + """Divide two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top,self.bot * other) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot,self.bot * other.top) + return NotImplemented + + def __pow__(self,other): + """Compute a power of a fraction.""" + if parent(other) == ZZ: + if other < 0: + # Negative powers require flipping top and bottom + return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) + else: + return fastfrac(self.R,self.top ^ other,self.bot ^ other) + return NotImplemented + + def __str__(self): + return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" + def __repr__(self): + return "%s" % self + + def numerator(self): + return self.top + +class constraints: + """A set of constraints, consisting of zero and nonzero expressions. + + Constraints can either be used to express knowledge or a requirement. + + Both the fields zero and nonzero are maps from expressions to description + strings. The expressions that are the keys in zero are required to be zero, + and the expressions that are the keys in nonzero are required to be nonzero. + + Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in + nonzero could be multiplied into a single key. This is often much less + efficient to work with though, so we keep them separate inside the + constraints. This allows higher-level code to do fast checks on the individual + nonzero elements, or combine them if needed for stronger checks. + + We can't multiply the different zero elements, as it would suffice for one of + the factors to be zero, instead of all of them. Instead, the zero elements are + typically combined into an ideal first. + """ + + def __init__(self, **kwargs): + if 'zero' in kwargs: + self.zero = dict(kwargs['zero']) + else: + self.zero = dict() + if 'nonzero' in kwargs: + self.nonzero = dict(kwargs['nonzero']) + else: + self.nonzero = dict() + + def negate(self): + return constraints(zero=self.nonzero, nonzero=self.zero) + + def __add__(self, other): + zero = self.zero.copy() + zero.update(other.zero) + nonzero = self.nonzero.copy() + nonzero.update(other.nonzero) + return constraints(zero=zero, nonzero=nonzero) + + def __str__(self): + return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) + + def __repr__(self): + return "%s" % self + + +def conflicts(R, con): + """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" + zero = R.ideal(map(numerator, con.zero)) + if 1 in zero: + return True + # First a cheap check whether any of the individual nonzero terms conflict on + # their own. + for nonzero in con.nonzero: + if nonzero.iszero(zero): + return True + # It can be the case that entries in the nonzero set do not individually + # conflict with the zero set, but their combination does. For example, knowing + # that either x or y is zero is equivalent to having x*y in the zero set. + # Having x or y individually in the nonzero set is not a conflict, but both + # simultaneously is, so that is the right thing to check for. + if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): + return True + return False + + +def get_nonzero_set(R, assume): + """Calculate a simple set of nonzero expressions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = set() + for nz in map(numerator, assume.nonzero): + for (f,n) in nz.factor(): + nonzero.add(f) + rnz = zero.reduce(nz) + for (f,n) in rnz.factor(): + nonzero.add(f) + return nonzero + + +def prove_nonzero(R, exprs, assume): + """Check whether an expression is provably nonzero, given assumptions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = get_nonzero_set(R, assume) + expl = set() + ok = True + for expr in exprs: + if numerator(expr) in zero: + return (False, [exprs[expr]]) + allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) + for (f, n) in allexprs.factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for (f, n) in zero.reduce(numerator(allexprs)).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in numerator(expr).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in zero.reduce(numerator(expr)).factor(): + if f not in nonzero: + expl.add(exprs[expr]) + if expl: + return (False, list(expl)) + else: + return (True, None) + + +def prove_zero(R, exprs, assume): + """Check whether all of the passed expressions are provably zero, given assumptions""" + r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) + if not r: + return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) + zero = R.ideal(map(numerator, assume.zero)) + nonzero = prod(x for x in assume.nonzero) + expl = [] + for expr in exprs: + if not expr.iszero(zero): + expl.append(exprs[expr]) + if not expl: + return (True, None) + return (False, expl) + + +def describe_extra(R, assume, assumeExtra): + """Describe what assumptions are added, given existing assumptions""" + zerox = assume.zero.copy() + zerox.update(assumeExtra.zero) + zero = R.ideal(map(numerator, assume.zero)) + zeroextra = R.ideal(map(numerator, zerox)) + nonzero = get_nonzero_set(R, assume) + ret = set() + # Iterate over the extra zero expressions + for base in assumeExtra.zero: + if base not in zero: + add = [] + for (f, n) in numerator(base).factor(): + if f not in nonzero: + add += ["%s" % f] + if add: + ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) + # Iterate over the extra nonzero expressions + for nz in assumeExtra.nonzero: + nzr = zeroextra.reduce(numerator(nz)) + if nzr not in zeroextra: + for (f,n) in nzr.factor(): + if zeroextra.reduce(f) not in nonzero: + ret.add("%s != 0" % zeroextra.reduce(f)) + return ", ".join(x for x in ret) + + +def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): + """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" + assume = assumeLaw + assumeAssert + assumeBranch + + if conflicts(R, assume): + # This formula does not apply + return None + + describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + + ok, msg = prove_zero(R, require.zero, assume) + if not ok: + return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + + res, expl = prove_nonzero(R, require.nonzero, assume) + if not res: + return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + + if describe != "": + return "OK (assuming %s)" % describe + else: + return "OK" + + +def concrete_verify(c): + for k in c.zero: + if k != 0: + return (False, c.zero[k]) + for k in c.nonzero: + if k == 0: + return (False, c.nonzero[k]) + return (True, None) diff --git a/src/secp256k1/sage/secp256k1.sage b/src/secp256k1/sage/secp256k1.sage new file mode 100644 index 000000000000..a97e732f7fa3 --- /dev/null +++ b/src/secp256k1/sage/secp256k1.sage @@ -0,0 +1,306 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_gej_double_var(a): + """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + rz = rz * 2 + t1 = a.X^2 + t1 = t1 * 3 + t2 = t1^2 + t3 = a.Y^2 + t3 = t3 * 2 + t4 = t3^2 + t4 = t4 * 2 + t3 = t3 * a.X + rx = t3 + rx = rx * 4 + rx = -rx + rx = rx + t2 + t2 = -t2 + t3 = t3 * 6 + t3 = t3 + t2 + ry = t1 * t3 + t2 = -t4 + ry = ry + t2 + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h2 * h + h = h * b.Z + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if (branch == 2): + r = formula_secp256k1_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) + if branch == 1: + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z + rz = rz * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 4) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 3) == 3 + if (branch & 1) != 0: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + if (branch & 2) != 0: + zeroes.update({rr : 'rr_zero'}) + else: + nonzeroes.update({rr : 'rr_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = n * t + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + infinity = False + if (branch & 8) != 0: + if not a_infinity: + infinity = True + zeroes.update({rz : 'r.z=0'}) + else: + nonzeroes.update({rz : 'r.z!=0'}) + rz = rz * 2 + q = -q + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + rx = rx * 4 + ry = ry * 4 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage new file mode 100644 index 000000000000..03ef2ec901ea --- /dev/null +++ b/src/secp256k1/sage/weierstrass_prover.sage @@ -0,0 +1,264 @@ +# Prover implementation for Weierstrass curves of the form +# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws +# operating on affine and Jacobian coordinates, including the point at infinity +# represented by a 4th variable in coordinates. + +load("group_prover.sage") + + +class affinepoint: + def __init__(self, x, y, infinity=0): + self.x = x + self.y = y + self.infinity = infinity + def __str__(self): + return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) + + +class jacobianpoint: + def __init__(self, x, y, z, infinity=0): + self.X = x + self.Y = y + self.Z = z + self.Infinity = infinity + def __str__(self): + return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) + + +def point_at_infinity(): + return jacobianpoint(1, 1, 1, 1) + + +def negate(p): + if p.__class__ == affinepoint: + return affinepoint(p.x, -p.y) + if p.__class__ == jacobianpoint: + return jacobianpoint(p.X, -p.Y, p.Z) + assert(False) + + +def on_weierstrass_curve(A, B, p): + """Return a set of zero-expressions for an affine point to be on the curve""" + return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) + + +def tangential_to_weierstrass_curve(A, B, p12, p3): + """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" + return constraints(zero={ + (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' + }) + + +def colinear(p1, p2, p3): + """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" + return constraints(zero={ + (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', + (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', + (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' + }) + + +def good_affine_point(p): + return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) + + +def good_jacobian_point(p): + return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) + + +def good_point(p): + return constraints(nonzero={p.Z^6 : 'nonzero_X'}) + + +def finite(p, *affine_fns): + con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) + if p.Z != 0: + return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) + else: + return con + +def infinite(p): + return constraints(nonzero={p.Infinity : 'infinite_point'}) + + +def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(nonzero={pa.x - pb.x : 'different_x'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + colinear(pa, pb, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) + require = infinite(pC) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pb) + + infinite(pA) + + finite(pB)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + infinite(pB) + + finite(pA)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + infinite(pA) + + infinite(pB)) + require = infinite(pC) + return (assumeLaw, require) + + +laws_jacobian_weierstrass = { + 'add': law_jacobian_weierstrass_add, + 'double': law_jacobian_weierstrass_double, + 'add_opposite': law_jacobian_weierstrass_add_opposites, + 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, + 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, + 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab +} + + +def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" + F = Integers(p) + print "Formula %s on Z%i:" % (name, p) + points = [] + for x in xrange(0, p): + for y in xrange(0, p): + point = affinepoint(F(x), F(y)) + r, e = concrete_verify(on_weierstrass_curve(A, B, point)) + if r: + points.append(point) + + for za in xrange(1, p): + for zb in xrange(1, p): + for pa in points: + for pb in points: + for ia in xrange(2): + for ib in xrange(2): + pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) + pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) + for branch in xrange(0, branches): + assumeAssert, assumeBranch, pC = formula(branch, pA, pB) + pC.X = F(pC.X) + pC.Y = F(pC.Y) + pC.Z = F(pC.Z) + pC.Infinity = F(pC.Infinity) + r, e = concrete_verify(assumeAssert + assumeBranch) + if r: + match = False + for key in laws_jacobian_weierstrass: + assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) + r, e = concrete_verify(assumeLaw) + if r: + if match: + print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + else: + match = True + r, e = concrete_verify(require) + if not r: + print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) + print + + +def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): + assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) + return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) + +def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" + R. = PolynomialRing(QQ,8,order='invlex') + lift = lambda x: fastfrac(R,x) + ax = lift(ax) + ay = lift(ay) + Az = lift(Az) + bx = lift(bx) + by = lift(by) + Bz = lift(Bz) + Ai = lift(Ai) + Bi = lift(Bi) + + pa = affinepoint(ax, ay, Ai) + pb = affinepoint(bx, by, Bi) + pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) + pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) + + res = {} + + for key in laws_jacobian_weierstrass: + res[key] = [] + + print ("Formula " + name + ":") + count = 0 + for branch in xrange(branches): + assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + pC.X = lift(pC.X) + pC.Y = lift(pC.Y) + pC.Z = lift(pC.Z) + pC.Infinity = lift(pC.Infinity) + + for key in laws_jacobian_weierstrass: + res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + + for key in res: + print " %s:" % key + val = res[key] + for x in val: + if x[0] is not None: + print " branch %i: %s" % (x[1], x[0]) + + print diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s new file mode 100644 index 000000000000..5a9cc3ffcfda --- /dev/null +++ b/src/secp256k1/src/asm/field_10x26_arm.s @@ -0,0 +1,919 @@ +@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: +/********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +/* +ARM implementation of field_10x26 inner loops. + +Note: + +- To avoid unnecessary loads and make use of available registers, two + 'passes' have every time been interleaved, with the odd passes accumulating c' and d' + which will be added to c and d respectively in the even passes + +*/ + + .syntax unified + .arch armv7-a + @ eabi attributes - see readelf -A + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes + .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no + .eabi_attribute 10, 0 @ Tag_FP_arch = none + .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 + .text + + @ Field constants + .set field_R0, 0x3d10 + .set field_R1, 0x400 + .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff + + .align 2 + .global secp256k1_fe_mul_inner + .type secp256k1_fe_mul_inner, %function + @ Arguments: + @ r0 r Restrict: can overlap with a, not with b + @ r1 a + @ r2 b + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_mul_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r7,r8 scratch + r1 a (pointer) + r2 b (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + + /* A - interleaved with B */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #9*4] @ b[9] + ldr r0, [r1, #1*4] @ a[1] + umull r5, r6, r7, r8 @ d = a[0] * b[9] + ldr r14, [r2, #8*4] @ b[8] + umull r9, r10, r0, r8 @ d' = a[1] * b[9] + ldr r7, [r1, #2*4] @ a[2] + umlal r5, r6, r0, r14 @ d += a[1] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r14 @ d' += a[2] * b[8] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r8 @ d += a[2] * b[7] + ldr r14, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r8 @ d' += a[3] * b[7] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r14 @ d += a[3] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r14 @ d' += a[4] * b[6] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r8 @ d += a[4] * b[5] + ldr r14, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r8 @ d' += a[5] * b[5] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r14 @ d += a[5] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r14 @ d' += a[6] * b[4] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[3] + ldr r14, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r8 @ d' += a[7] * b[3] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[7] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r9, r10, r7, r14 @ d' += a[8] * b[2] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r8 @ d += a[8] * b[1] + ldr r14, [r2, #0*4] @ b[0] + umlal r9, r10, r0, r8 @ d' += a[9] * b[1] + ldr r7, [r1, #0*4] @ a[0] + umlal r5, r6, r0, r14 @ d += a[9] * b[0] + @ r7,r14 used in B + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 4*9] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + umull r3, r4, r7, r14 @ c = a[0] * b[0] + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C - interleaved with D */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #2*4] @ b[2] + ldr r14, [r2, #1*4] @ b[1] + umull r11, r12, r7, r8 @ c' = a[0] * b[2] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[1] * b[1] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[2] * b[0] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r14 @ d += a[2] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[3] * b[9] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r8 @ d += a[3] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[4] * b[8] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r14 @ d += a[4] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[5] * b[7] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r8 @ d += a[5] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r8 @ d' += a[6] * b[6] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r14 @ d' += a[7] * b[5] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r8 @ d' += a[8] * b[4] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r14 @ d' += a[9] * b[3] + umlal r5, r6, r0, r8 @ d += a[9] * b[2] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E - interleaved with F */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #4*4] @ b[4] + umull r11, r12, r7, r8 @ c' = a[0] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r3, r4, r7, r8 @ c += a[0] * b[3] + ldr r7, [r1, #1*4] @ a[1] + umlal r11, r12, r7, r8 @ c' += a[1] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r3, r4, r7, r8 @ c += a[1] * b[2] + ldr r7, [r1, #2*4] @ a[2] + umlal r11, r12, r7, r8 @ c' += a[2] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r3, r4, r7, r8 @ c += a[2] * b[1] + ldr r7, [r1, #3*4] @ a[3] + umlal r11, r12, r7, r8 @ c' += a[3] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r3, r4, r7, r8 @ c += a[3] * b[0] + ldr r7, [r1, #4*4] @ a[4] + umlal r11, r12, r7, r8 @ c' += a[4] * b[0] + ldr r8, [r2, #9*4] @ b[9] + umlal r5, r6, r7, r8 @ d += a[4] * b[9] + ldr r7, [r1, #5*4] @ a[5] + umull r9, r10, r7, r8 @ d' = a[5] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umlal r5, r6, r7, r8 @ d += a[5] * b[8] + ldr r7, [r1, #6*4] @ a[6] + umlal r9, r10, r7, r8 @ d' += a[6] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[7] + ldr r7, [r1, #7*4] @ a[7] + umlal r9, r10, r7, r8 @ d' += a[7] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r5, r6, r7, r8 @ d += a[7] * b[6] + ldr r7, [r1, #8*4] @ a[8] + umlal r9, r10, r7, r8 @ d' += a[8] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r5, r6, r7, r8 @ d += a[8] * b[5] + ldr r7, [r1, #9*4] @ a[9] + umlal r9, r10, r7, r8 @ d' += a[9] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r5, r6, r7, r8 @ d += a[9] * b[4] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G - interleaved with H */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #6*4] @ b[6] + ldr r14, [r2, #5*4] @ b[5] + umull r11, r12, r7, r8 @ c' = a[0] * b[6] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[1] * b[5] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[2] * b[4] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[3] * b[3] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[4] * b[2] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[5] * b[1] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[6] * b[0] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[7] * b[9] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[8] * b[8] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[9] * b[7] + umlal r5, r6, r0, r8 @ d += a[9] * b[6] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I - interleaved with J */ + ldr r8, [r2, #8*4] @ b[8] + ldr r7, [r1, #0*4] @ a[0] + ldr r14, [r2, #7*4] @ b[7] + umull r11, r12, r7, r8 @ c' = a[0] * b[8] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r11, r12, r0, r14 @ c' += a[1] * b[7] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r11, r12, r7, r8 @ c' += a[2] * b[6] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[3] * b[5] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[4] * b[4] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[5] * b[3] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[6] * b[2] + ldr r0, [r1, #7*4] @ a[7] + umlal r3, r4, r7, r14 @ c += a[6] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[7] * b[1] + ldr r7, [r1, #8*4] @ a[8] + umlal r3, r4, r0, r8 @ c += a[7] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[8] * b[0] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[9] * b[9] + umlal r5, r6, r0, r8 @ d += a[9] * b[8] + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner + + .align 2 + .global secp256k1_fe_sqr_inner + .type secp256k1_fe_sqr_inner, %function + @ Arguments: + @ r0 r Can overlap with a + @ r1 a + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_sqr_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r2,r7,r8 scratch + r1 a (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + /* A interleaved with B */ + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r7, [r1, #0*4] @ a[0] + mov r0, r0, asl #1 + ldr r14, [r1, #9*4] @ a[9] + umull r3, r4, r7, r7 @ c = a[0] * a[0] + ldr r8, [r1, #8*4] @ a[8] + mov r7, r7, asl #1 + umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] + ldr r7, [r1, #2*4] @ a[2]*2 + umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #3*4] @ a[3]*2 + umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] + ldr r14, [r1, #5*4] @ a[5] + mov r7, r7, asl #1 + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] + umlal r9, r10, r14, r14 @ d' += a[5] * a[5] + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 9*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C interleaved with D */ + ldr r0, [r1, #0*4] @ a[0]*2 + ldr r14, [r1, #1*4] @ a[1] + mov r0, r0, asl #1 + ldr r8, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] + mov r7, r8, asl #1 @ a[2]*2 + umull r11, r12, r14, r14 @ c' = a[1] * a[1] + ldr r14, [r1, #9*4] @ a[9] + umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] + ldr r0, [r1, #3*4] @ a[3]*2 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] + umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] + umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] + umlal r9, r10, r8, r8 @ d' += a[6] * a[6] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E interleaved with F */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r14, [r1, #2*4] @ a[2] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + ldr r2, [r1, #4*4] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] + mov r2, r2, asl #1 @ a[4]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] + ldr r8, [r1, #9*4] @ a[9] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r11, r12, r14, r14 @ c' += a[2] * a[2] + ldr r14, [r1, #8*4] @ a[8] + mov r0, r0, asl #1 + umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] + ldr r7, [r1, #6*4] @ a[6]*2 + umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] + umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] + umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] + umlal r9, r10, r8, r8 @ d' += a[7] * a[7] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G interleaved with H */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #5*4] @ a[5] + ldr r2, [r1, #6*4] @ a[6] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] + mov r0, r2, asl #1 @ a[6]*2 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] + ldr r14, [r1, #9*4] @ a[9] + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] + ldr r7, [r1, #7*4] @ a[7]*2 + umlal r11, r12, r8, r8 @ c' += a[3] * a[3] + mov r7, r7, asl #1 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] + umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] + umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] + umlal r9, r10, r8, r8 @ d' += a[8] * a[8] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I interleaved with J */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + ldr r2, [r1, #8*4] @ a[8] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] + ldr r14, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] + ldr r8, [r1, #5*4] @ a[5] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] + ldr r0, [r1, #3*4] @ a[3]*2 + mov r7, r7, asl #1 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] + mov r2, r2, asl #1 @ a[8]*2 + umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] + umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] + umlal r11, r12, r14, r14 @ c' += a[4] * a[4] + ldr r8, [r1, #9*4] @ a[9] + umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] + @ r8 will be used in J + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + umlal r5, r6, r8, r8 @ d += a[9] * a[9] + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h new file mode 100644 index 000000000000..fc588061ca40 --- /dev/null +++ b/src/secp256k1/src/basic-config.h @@ -0,0 +1,33 @@ +/********************************************************************** + * 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_ENDOMORPHISM +#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 + +#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 + +#endif /* USE_BASIC_CONFIG */ + +#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h new file mode 100644 index 000000000000..5b59783f68a9 --- /dev/null +++ b/src/secp256k1/src/bench.h @@ -0,0 +1,82 @@ +/********************************************************************** + * Copyright (c) 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_BENCH_H +#define SECP256K1_BENCH_H + +#include +#include +#include +#include "sys/time.h" + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +void print_number(double x) { + double y = x; + int c = 0; + if (y < 0.0) { + y = -y; + } + while (y > 0 && y < 100.0) { + y *= 10.0; + c++; + } + printf("%.*f", c, x); +} + +void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) { + int i; + double min = HUGE_VAL; + double sum = 0.0; + double max = 0.0; + for (i = 0; i < count; i++) { + double begin, total; + if (setup != NULL) { + setup(data); + } + begin = gettimedouble(); + benchmark(data); + total = gettimedouble() - begin; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } + sum += total; + } + printf("%s: min ", name); + print_number(min * 1000000.0 / iter); + printf("us / avg "); + print_number((sum / count) * 1000000.0 / iter); + printf("us / max "); + print_number(max * 1000000.0 / iter); + printf("us\n"); +} + +int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + if (argv == argm) { + return 1; + } + while (argv != NULL && argv != argm) { + if (strcmp(*argv, flag) == 0) { + return 1; + } + argv++; + } + return 0; +} + +#endif /* SECP256K1_BENCH_H */ diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c new file mode 100644 index 000000000000..c1dd5a6ac93c --- /dev/null +++ b/src/secp256k1/src/bench_ecdh.c @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point; + unsigned char scalar[32]; +} bench_ecdh_data; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh_data *data = (bench_ecdh_data*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + + /* create a context with no capabilities */ + data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + for (i = 0; i < 32; i++) { + data->scalar[i] = i + 1; + } + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ecdh(void* arg) { + int i; + unsigned char res[32]; + bench_ecdh_data *data = (bench_ecdh_data*)arg; + + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); + } +} + +int main(void) { + bench_ecdh_data data; + + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c new file mode 100644 index 000000000000..52d0476a30ff --- /dev/null +++ b/src/secp256k1/src/bench_ecmult.c @@ -0,0 +1,196 @@ +/********************************************************************** + * Copyright (c) 2017 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_impl.h" +#include "bench.h" +#include "secp256k1.c" + +#define POINTS 32768 +#define ITERS 10000 + +typedef struct { + /* Setup once in advance */ + secp256k1_context* ctx; + secp256k1_scratch_space* scratch; + secp256k1_scalar* scalars; + secp256k1_ge* pubkeys; + secp256k1_scalar* seckeys; + secp256k1_gej* expected_output; + secp256k1_ecmult_multi_func ecmult_multi; + + /* Changes per test */ + size_t count; + int includes_g; + + /* Changes per test iteration */ + size_t offset1; + size_t offset2; + + /* Test output. */ + secp256k1_gej* output; +} bench_data; + +static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) { + bench_data* data = (bench_data*)arg; + if (data->includes_g) ++idx; + if (idx == 0) { + *sc = data->scalars[data->offset1]; + *ge = secp256k1_ge_const_g; + } else { + *sc = data->scalars[(data->offset1 + idx) % POINTS]; + *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS]; + } + return 1; +} + +static void bench_ecmult(void* arg) { + bench_data* data = (bench_data*)arg; + + size_t count = data->count; + int includes_g = data->includes_g; + size_t iters = 1 + ITERS / count; + size_t iter; + + for (iter = 0; iter < iters; ++iter) { + data->ecmult_multi(&data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g); + data->offset1 = (data->offset1 + count) % POINTS; + data->offset2 = (data->offset2 + count - 1) % POINTS; + } +} + +static void bench_ecmult_setup(void* arg) { + bench_data* data = (bench_data*)arg; + data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS; + data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS; +} + +static void bench_ecmult_teardown(void* arg) { + bench_data* data = (bench_data*)arg; + size_t iters = 1 + ITERS / data->count; + size_t iter; + /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */ + for (iter = 0; iter < iters; ++iter) { + secp256k1_gej tmp; + secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); + CHECK(secp256k1_gej_is_infinity(&tmp)); + } +} + +static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { + secp256k1_sha256 sha256; + unsigned char c[11] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; + unsigned char buf[32]; + int overflow = 0; + c[6] = num; + c[7] = num >> 8; + c[8] = num >> 16; + c[9] = num >> 24; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, c, sizeof(c)); + secp256k1_sha256_finalize(&sha256, buf); + secp256k1_scalar_set_b32(scalar, buf, &overflow); + CHECK(!overflow); +} + +static void run_test(bench_data* data, size_t count, int includes_g) { + char str[32]; + static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + size_t iters = 1 + ITERS / count; + size_t iter; + + data->count = count; + data->includes_g = includes_g; + + /* Compute (the negation of) the expected results directly. */ + data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS; + data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS; + for (iter = 0; iter < iters; ++iter) { + secp256k1_scalar tmp; + secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS]; + size_t i = 0; + for (i = 0; i + 1 < count; ++i) { + secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); + secp256k1_scalar_add(&total, &total, &tmp); + } + secp256k1_scalar_negate(&total, &total); + secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->expected_output[iter], NULL, &zero, &total); + } + + /* Run the benchmark. */ + sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count); + run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * (1 + ITERS / count)); +} + +int main(int argc, char **argv) { + bench_data data; + int i, p; + secp256k1_gej* pubkeys_gej; + size_t scratch_size; + + if (argc > 1) { + if(have_flag(argc, argv, "pippenger_wnaf")) { + printf("Using pippenger_wnaf:\n"); + data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single; + } else if(have_flag(argc, argv, "strauss_wnaf")) { + printf("Using strauss_wnaf:\n"); + data.ecmult_multi = secp256k1_ecmult_strauss_batch_single; + } + } else { + data.ecmult_multi = secp256k1_ecmult_multi_var; + } + + /* Allocate stuff */ + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; + data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size); + data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS); + data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS); + data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS); + data.expected_output = malloc(sizeof(secp256k1_gej) * (ITERS + 1)); + data.output = malloc(sizeof(secp256k1_gej) * (ITERS + 1)); + + /* Generate a set of scalars, and private/public keypairs. */ + pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS); + secp256k1_gej_set_ge(&pubkeys_gej[0], &secp256k1_ge_const_g); + secp256k1_scalar_set_int(&data.seckeys[0], 1); + for (i = 0; i < POINTS; ++i) { + generate_scalar(i, &data.scalars[i]); + if (i) { + secp256k1_gej_double_var(&pubkeys_gej[i], &pubkeys_gej[i - 1], NULL); + secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); + } + } + secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS, &data.ctx->error_callback); + free(pubkeys_gej); + + for (i = 1; i <= 8; ++i) { + run_test(&data, i, 1); + } + + for (p = 0; p <= 11; ++p) { + for (i = 9; i <= 16; ++i) { + run_test(&data, i << p, 1); + } + } + secp256k1_context_destroy(data.ctx); + secp256k1_scratch_space_destroy(data.scratch); + free(data.scalars); + free(data.pubkeys); + free(data.seckeys); + free(data.output); + free(data.expected_output); + + return(0); +} diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c new file mode 100644 index 000000000000..9c0a07fbbdd0 --- /dev/null +++ b/src/secp256k1/src/bench_internal.c @@ -0,0 +1,367 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_impl.h" +#include "bench.h" +#include "secp256k1.c" + +typedef struct { + secp256k1_scalar scalar_x, scalar_y; + secp256k1_fe fe_x, fe_y; + secp256k1_ge ge_x, ge_y; + secp256k1_gej gej_x, gej_y; + unsigned char data[64]; + int wnaf[256]; +} bench_inv; + +void bench_setup(void* arg) { + bench_inv *data = (bench_inv*)arg; + + static const unsigned char init_x[32] = { + 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, + 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, + 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, + 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 + }; + + static const unsigned char init_y[32] = { + 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, + 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, + 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, + 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 + }; + + secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL); + secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL); + secp256k1_fe_set_b32(&data->fe_x, init_x); + secp256k1_fe_set_b32(&data->fe_y, init_y); + CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0)); + CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1)); + secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); + secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); + memcpy(data->data, init_x, 32); + memcpy(data->data + 32, init_y, 32); +} + +void bench_scalar_add(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_negate(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_sqr(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_mul(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +#ifdef USE_ENDOMORPHISM +void bench_scalar_split(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_scalar l, r; + secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} +#endif + +void bench_scalar_inverse(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_inverse_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_field_normalize(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize(&data->fe_x); + } +} + +void bench_field_normalize_weak(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize_weak(&data->fe_x); + } +} + +void bench_field_mul(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); + } +} + +void bench_field_sqr(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_fe_sqr(&data->fe_x, &data->fe_x); + } +} + +void bench_field_inverse(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_inv(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_inverse_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_sqrt(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_group_double_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); + } +} + +void bench_group_add_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); + } +} + +void bench_group_add_affine(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); + } +} + +void bench_group_add_affine_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); + } +} + +void bench_group_jacobi_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_gej_has_quad_y_var(&data->gej_x); + } +} + +void bench_ecmult_wnaf(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_wnaf_const(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + + +void bench_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_sha256 sha; + + for (i = 0; i < 20000; i++) { + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, data->data, 32); + secp256k1_sha256_finalize(&sha, data->data); + } +} + +void bench_hmac_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_hmac_sha256 hmac; + + for (i = 0; i < 20000; i++) { + secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); + secp256k1_hmac_sha256_write(&hmac, data->data, 32); + secp256k1_hmac_sha256_finalize(&hmac, data->data); + } +} + +void bench_rfc6979_hmac_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_rfc6979_hmac_sha256 rng; + + for (i = 0; i < 20000; i++) { + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); + secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + } +} + +void bench_context_verify(void* arg) { + int i; + (void)arg; + for (i = 0; i < 20; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); + } +} + +void bench_context_sign(void* arg) { + int i; + (void)arg; + for (i = 0; i < 200; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); + } +} + +#ifndef USE_NUM_NONE +void bench_num_jacobi(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_num nx, norder; + + secp256k1_scalar_get_num(&nx, &data->scalar_x); + secp256k1_scalar_order_get_num(&norder); + secp256k1_scalar_get_num(&norder, &data->scalar_y); + + for (i = 0; i < 200000; i++) { + secp256k1_num_jacobi(&nx, &norder); + } +} +#endif + +int main(int argc, char **argv) { + bench_inv data; + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000); +#ifdef USE_ENDOMORPHISM + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000); +#endif + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); + + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); + +#ifndef USE_NUM_NONE + if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); +#endif + return 0; +} diff --git a/src/secp256k1/src/bench_inv.c b/src/secp256k1/src/bench_inv.c deleted file mode 100644 index d6f664333fd9..000000000000 --- a/src/secp256k1/src/bench_inv.c +++ /dev/null @@ -1,41 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ -#include - -#include "include/secp256k1.h" - -#include "util.h" -#include "num_impl.h" -#include "field_impl.h" -#include "group_impl.h" -#include "scalar_impl.h" - -int main(void) { - static const unsigned char init[32] = { - 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, - 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, - 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, - 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 - }; - static const unsigned char fini[32] = { - 0xba, 0x28, 0x58, 0xd8, 0xaa, 0x11, 0xd6, 0xf2, - 0xfa, 0xce, 0x50, 0xb1, 0x67, 0x19, 0xb1, 0xa6, - 0xe0, 0xaa, 0x84, 0x53, 0xf6, 0x80, 0xfc, 0x23, - 0x88, 0x3c, 0xd6, 0x74, 0x9f, 0x27, 0x09, 0x03 - }; - secp256k1_ge_start(); - secp256k1_scalar_t base, x; - secp256k1_scalar_set_b32(&base, init, NULL); - secp256k1_scalar_set_b32(&x, init, NULL); - for (int i=0; i<1000000; i++) { - secp256k1_scalar_inverse(&x, &x); - secp256k1_scalar_add(&x, &x, &base); - } - unsigned char res[32]; - secp256k1_scalar_get_b32(res, &x); - CHECK(memcmp(res, fini, 32) == 0); - return 0; -} diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c new file mode 100644 index 000000000000..b806eed94e15 --- /dev/null +++ b/src/secp256k1/src/bench_recover.c @@ -0,0 +1,60 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "include/secp256k1_recovery.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char sig[64]; +} bench_recover_data; + +void bench_recover(void* arg) { + int i; + bench_recover_data *data = (bench_recover_data*)arg; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; + + for (i = 0; i < 20000; i++) { + int j; + size_t pubkeylen = 33; + secp256k1_ecdsa_recoverable_signature sig; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + for (j = 0; j < 32; j++) { + data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ + data->msg[j] = data->sig[j]; /* Move former R to message. */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + } + } +} + +void bench_recover_setup(void* arg) { + int i; + bench_recover_data *data = (bench_recover_data*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (i = 0; i < 64; i++) { + data->sig[i] = 65 + i; + } +} + +int main(void) { + bench_recover_data data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + + run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c index f01f11d689bb..544b43963c8d 100644 --- a/src/secp256k1/src/bench_sign.c +++ b/src/secp256k1/src/bench_sign.c @@ -3,47 +3,54 @@ * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#include -#include #include "include/secp256k1.h" #include "util.h" +#include "bench.h" -int main(void) { - secp256k1_start(SECP256K1_START_SIGN); - +typedef struct { + secp256k1_context* ctx; unsigned char msg[32]; - unsigned char nonce[32]; unsigned char key[32]; +} bench_sign; - for (int i = 0; i < 32; i++) msg[i] = i + 1; - for (int i = 0; i < 32; i++) nonce[i] = i + 33; - for (int i = 0; i < 32; i++) key[i] = i + 65; +static void bench_sign_setup(void* arg) { + int i; + bench_sign *data = (bench_sign*)arg; - unsigned char sig[64]; + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} - for (int i=0; i<1000000; i++) { - int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(msg, 32, sig, key, nonce, &recid)); - for (int j = 0; j < 32; j++) { - nonce[j] = key[j]; /* Move former key to nonce */ - msg[j] = sig[j]; /* Move former R to message. */ - key[j] = sig[j + 32]; /* Move former S to key. */ +static void bench_sign_run(void* arg) { + int i; + bench_sign *data = (bench_sign*)arg; + + unsigned char sig[74]; + for (i = 0; i < 20000; i++) { + size_t siglen = 74; + int j; + secp256k1_ecdsa_signature signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; } } +} + +int main(void) { + bench_sign data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000); - static const unsigned char fini[64] = { - 0x92, 0x03, 0xef, 0xf1, 0x58, 0x0b, 0x49, 0x8d, - 0x22, 0x3d, 0x49, 0x0e, 0xbf, 0x26, 0x50, 0x0e, - 0x2d, 0x62, 0x90, 0xd7, 0x82, 0xbd, 0x3d, 0x5c, - 0xa9, 0x10, 0xa5, 0x49, 0xb1, 0xd8, 0x8c, 0xc0, - 0x5b, 0x5e, 0x9e, 0x68, 0x51, 0x3d, 0xe8, 0xec, - 0x82, 0x30, 0x82, 0x88, 0x8c, 0xfd, 0xe7, 0x71, - 0x15, 0x92, 0xfc, 0x14, 0x59, 0x78, 0x31, 0xb3, - 0xf6, 0x07, 0x91, 0x18, 0x00, 0x8d, 0x4c, 0xb2 - }; - CHECK(memcmp(sig, fini, 64) == 0); - - secp256k1_stop(); + secp256k1_context_destroy(data.ctx); return 0; } diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c index 690595516d72..418defa0aa22 100644 --- a/src/secp256k1/src/bench_verify.c +++ b/src/secp256k1/src/bench_verify.c @@ -9,36 +9,104 @@ #include "include/secp256k1.h" #include "util.h" +#include "bench.h" -int main(void) { - secp256k1_start(SECP256K1_START_VERIFY); +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif +typedef struct { + secp256k1_context *ctx; unsigned char msg[32]; - unsigned char sig[64]; + unsigned char key[32]; + unsigned char sig[72]; + size_t siglen; + unsigned char pubkey[33]; + size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif +} benchmark_verify_t; - for (int i = 0; i < 32; i++) msg[i] = 1 + i; - for (int i = 0; i < 64; i++) sig[i] = 65 + i; +static void benchmark_verify(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; - unsigned char pubkey[33]; - for (int i=0; i<1000000; i++) { - int pubkeylen = 33; - CHECK(secp256k1_ecdsa_recover_compact(msg, 32, sig, pubkey, &pubkeylen, 1, i % 2)); - for (int j = 0; j < 32; j++) { - sig[j + 32] = msg[j]; /* Move former message to S. */ - msg[j] = sig[j]; /* Move former R to message. */ - sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + for (i = 0; i < 20000; i++) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} + +#ifdef ENABLE_OPENSSL_TESTS +static void benchmark_verify_openssl(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + { + EC_KEY *pkey = EC_KEY_new(); + const unsigned char *pubkey = &data->pubkey[0]; + int result; + + CHECK(pkey != NULL); + result = EC_KEY_set_group(pkey, data->ec_group); + CHECK(result); + result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; + CHECK(result); + result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); + CHECK(result); + EC_KEY_free(pkey); } + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + +int main(void) { + int i; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + benchmark_verify_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; } + data.siglen = 72; + CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); + data.pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - static const unsigned char fini[33] = { - 0x02, - 0x52, 0x63, 0xae, 0x9a, 0x9d, 0x47, 0x1f, 0x1a, - 0xb2, 0x36, 0x65, 0x89, 0x11, 0xe7, 0xcc, 0x86, - 0xa3, 0xab, 0x97, 0xb6, 0xf1, 0xaf, 0xfd, 0x8f, - 0x9b, 0x38, 0xb6, 0x18, 0x55, 0xe5, 0xc2, 0x43 - }; - CHECK(memcmp(fini, pubkey, 33) == 0); + run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); +#ifdef ENABLE_OPENSSL_TESTS + data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); + run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); + EC_GROUP_free(data.ec_group); +#endif - secp256k1_stop(); + secp256k1_context_destroy(data.ctx); return 0; } diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h index 5fc5230c36c0..80590c7cc862 100644 --- a/src/secp256k1/src/ecdsa.h +++ b/src/secp256k1/src/ecdsa.h @@ -4,24 +4,18 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECDSA_ -#define _SECP256K1_ECDSA_ +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H + +#include #include "scalar.h" #include "group.h" +#include "ecmult.h" -static void secp256k1_ecsda_start(void); -static void secp256k1_ecdsa_stop(void); - -typedef struct { - secp256k1_scalar_t r, s; -} secp256k1_ecdsa_sig_t; - -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); -static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); -static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s); +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); -#endif +#endif /* SECP256K1_ECDSA_H */ diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index a951d0b4adf0..c3400042d839 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -1,12 +1,12 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECDSA_IMPL_H_ -#define _SECP256K1_ECDSA_IMPL_H_ +#ifndef SECP256K1_ECDSA_IMPL_H +#define SECP256K1_ECDSA_IMPL_H #include "scalar.h" #include "field.h" @@ -15,88 +15,177 @@ #include "ecmult_gen.h" #include "ecdsa.h" -typedef struct { - secp256k1_fe_t order_as_fe; - secp256k1_fe_t p_minus_order; -} secp256k1_ecdsa_consts_t; +/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 + * sage: for t in xrange(1023, -1, -1): + * .. p = 2**256 - 2**32 - t + * .. if p.is_prime(): + * .. print '%x'%p + * .. break + * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) + * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + */ +static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL +); -static const secp256k1_ecdsa_consts_t *secp256k1_ecdsa_consts = NULL; +/** Difference between field and order, values 'p' and 'n' values defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) + * '14551231950b75fc4402da1722fc9baee' + */ +static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( + 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL +); -static void secp256k1_ecdsa_start(void) { - if (secp256k1_ecdsa_consts != NULL) - return; - - /* Allocate. */ - secp256k1_ecdsa_consts_t *ret = (secp256k1_ecdsa_consts_t*)malloc(sizeof(secp256k1_ecdsa_consts_t)); - - static const unsigned char order[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 - }; +static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { + int lenleft, b1; + size_t ret = 0; + if (*sigp >= sigend) { + return -1; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return -1; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; + if (lenleft > sigend - *sigp) { + return -1; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return -1; + } + if ((size_t)lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * certainly longer than the passed array size. + */ + return -1; + } + while (lenleft > 0) { + ret = (ret << 8) | **sigp; + if (ret + lenleft > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return -1; + } + (*sigp)++; + lenleft--; + } + if (ret < 128) { + /* Not the shortest possible length encoding. */ + return -1; + } + return ret; +} - secp256k1_fe_set_b32(&ret->order_as_fe, order); - secp256k1_fe_negate(&ret->p_minus_order, &ret->order_as_fe, 1); - secp256k1_fe_normalize(&ret->p_minus_order); +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + int rlen; - /* Set the global pointer. */ - secp256k1_ecdsa_consts = ret; + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ + return 0; + } + (*sig)++; + rlen = secp256k1_der_read_len(sig, sigend); + if (rlen <= 0 || (*sig) + rlen > sigend) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ + return 0; + } + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ + return 0; + } + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ + return 0; + } + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; + } + if (rlen > 32) { + overflow = 1; + } + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); + } + if (overflow) { + secp256k1_scalar_set_int(r, 0); + } + (*sig) += rlen; + return 1; } -static void secp256k1_ecdsa_stop(void) { - if (secp256k1_ecdsa_consts == NULL) - return; +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { + const unsigned char *sigend = sig + size; + int rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ + return 0; + } + rlen = secp256k1_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ + return 0; + } + if (sig + rlen != sigend) { + /* Garbage after tuple. */ + return 0; + } - secp256k1_ecdsa_consts_t *c = (secp256k1_ecdsa_consts_t*)secp256k1_ecdsa_consts; - secp256k1_ecdsa_consts = NULL; - free(c); -} + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { + return 0; + } + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { + return 0; + } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + return 0; + } -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { - if (sig[0] != 0x30) return 0; - int lenr = sig[3]; - if (5+lenr >= size) return 0; - int lens = sig[lenr+5]; - if (sig[1] != lenr+lens+4) return 0; - if (lenr+lens+6 > size) return 0; - if (sig[2] != 0x02) return 0; - if (lenr == 0) return 0; - if (sig[lenr+4] != 0x02) return 0; - if (lens == 0) return 0; - const unsigned char *sp = sig + 6 + lenr; - while (lens > 0 && sp[0] == 0) { - lens--; - sp++; - } - if (lens > 32) return 0; - const unsigned char *rp = sig + 4; - while (lenr > 0 && rp[0] == 0) { - lenr--; - rp++; - } - if (lenr > 32) return 0; - unsigned char ra[32] = {0}, sa[32] = {0}; - memcpy(ra + 32 - lenr, rp, lenr); - memcpy(sa + 32 - lens, sp, lens); - int overflow = 0; - secp256k1_scalar_set_b32(&r->r, ra, &overflow); - if (overflow) return 0; - secp256k1_scalar_set_b32(&r->s, sa, &overflow); - if (overflow) return 0; return 1; } -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { unsigned char r[33] = {0}, s[33] = {0}; - secp256k1_scalar_get_b32(&r[1], &a->r); - secp256k1_scalar_get_b32(&s[1], &a->s); unsigned char *rp = r, *sp = s; - int lenR = 33, lenS = 33; + size_t lenR = 33, lenS = 33; + secp256k1_scalar_get_b32(&r[1], ar); + secp256k1_scalar_get_b32(&s[1], as); while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } - if (*size < 6+lenS+lenR) + if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; return 0; + } *size = 6 + lenS + lenR; sig[0] = 0x30; sig[1] = 4 + lenS + lenR; @@ -109,97 +198,116 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_recompute(secp256k1_scalar_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { + unsigned char c[32]; + secp256k1_scalar sn, u1, u2; +#if !defined(EXHAUSTIVE_TEST_ORDER) + secp256k1_fe xr; +#endif + secp256k1_gej pubkeyj; + secp256k1_gej pr; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { return 0; + } - int ret = 0; - secp256k1_scalar_t sn, u1, u2; - secp256k1_scalar_inverse_var(&sn, &sig->s); + secp256k1_scalar_inverse_var(&sn, sigs); secp256k1_scalar_mul(&u1, &sn, message); - secp256k1_scalar_mul(&u2, &sn, &sig->r); - secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey); - secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); - if (!secp256k1_gej_is_infinity(&pr)) { - secp256k1_fe_t xr; secp256k1_gej_get_x_var(&xr, &pr); - secp256k1_fe_normalize(&xr); - unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr); - secp256k1_scalar_set_b32(r2, xrb, NULL); - ret = 1; + secp256k1_scalar_mul(&u2, &sn, sigr); + secp256k1_gej_set_ge(&pubkeyj, pubkey); + secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); + if (secp256k1_gej_is_infinity(&pr)) { + return 0; } - return ret; -} -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) - return 0; +#if defined(EXHAUSTIVE_TEST_ORDER) +{ + secp256k1_scalar computed_r; + secp256k1_ge pr_ge; + secp256k1_ge_set_gej(&pr_ge, &pr); + secp256k1_fe_normalize(&pr_ge.x); - unsigned char brx[32]; - secp256k1_scalar_get_b32(brx, &sig->r); - secp256k1_fe_t fx; - VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_consts->p_minus_order) >= 0) - return 0; - secp256k1_fe_add(&fx, &secp256k1_ecdsa_consts->order_as_fe); - } - secp256k1_ge_t x; - if (!secp256k1_ge_set_xo(&x, &fx, recid & 1)) - return 0; - secp256k1_gej_t xj; - secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_t rn, u1, u2; - secp256k1_scalar_inverse_var(&rn, &sig->r); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, &sig->s); - secp256k1_gej_t qj; - secp256k1_ecmult(&qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); + secp256k1_fe_get_b32(c, &pr_ge.x); + secp256k1_scalar_set_b32(&computed_r, c, NULL); + return secp256k1_scalar_eq(sigr, &computed_r); } +#else + secp256k1_scalar_get_b32(c, sigr); + secp256k1_fe_set_b32(&xr, c); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { - secp256k1_scalar_t r2; - int ret = 0; - ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_scalar_eq(&sig->r, &r2); - return ret; + /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) + * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), + * compute the remainder modulo n, and compare it to xr. However: + * + * xr == X(pr) mod n + * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) + * [Since 2 * n > p, h can only be 0 or 1] + * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) + * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] + * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) + * [Multiplying both sides of the equations by pr.z^2 mod p] + * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) + * + * Thus, we can avoid the inversion, but we have to check both cases separately. + * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + */ + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + /* xr + n >= p, so we can skip testing the second case. */ + return 0; + } + secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + return 0; +#endif } -static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { - secp256k1_gej_t rp; - secp256k1_ecmult_gen(&rp, nonce); - secp256k1_ge_t r; - secp256k1_ge_set_gej(&r, &rp); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { unsigned char b[32]; + secp256k1_gej rp; + secp256k1_ge r; + secp256k1_scalar n; + int overflow = 0; + + secp256k1_ecmult_gen(ctx, &rp, nonce); + secp256k1_ge_set_gej(&r, &rp); secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); - int overflow = 0; - secp256k1_scalar_set_b32(&sig->r, b, &overflow); - if (recid) + secp256k1_scalar_set_b32(sigr, b, &overflow); + /* These two conditions should be checked before calling */ + VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr)); + VERIFY_CHECK(overflow == 0); + + if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); - secp256k1_scalar_t n; - secp256k1_scalar_mul(&n, &sig->r, seckey); + } + secp256k1_scalar_mul(&n, sigr, seckey); secp256k1_scalar_add(&n, &n, message); - secp256k1_scalar_inverse(&sig->s, nonce); - secp256k1_scalar_mul(&sig->s, &sig->s, &n); + secp256k1_scalar_inverse(sigs, nonce); + secp256k1_scalar_mul(sigs, sigs, &n); secp256k1_scalar_clear(&n); secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(&sig->s)) + if (secp256k1_scalar_is_zero(sigs)) { return 0; - if (secp256k1_scalar_is_high(&sig->s)) { - secp256k1_scalar_negate(&sig->s, &sig->s); - if (recid) + } + if (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); + if (recid) { *recid ^= 1; + } } return 1; } -static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s) { - sig->r = *r; - sig->s = *s; -} - -#endif +#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h index 6de5dc0a590f..b621f1e6c39d 100644 --- a/src/secp256k1/src/eckey.h +++ b/src/secp256k1/src/eckey.h @@ -4,21 +4,22 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECKEY_ -#define _SECP256K1_ECKEY_ +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H + +#include #include "group.h" #include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" -static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); - -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen); -static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); -#endif +#endif /* SECP256K1_ECKEY_H */ diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h index 0f218ced9e81..1ab9a68ec048 100644 --- a/src/secp256k1/src/eckey_impl.h +++ b/src/secp256k1/src/eckey_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECKEY_IMPL_H_ -#define _SECP256K1_ECKEY_IMPL_H_ +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H #include "eckey.h" @@ -14,178 +14,87 @@ #include "group.h" #include "ecmult_gen.h" -static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) { - if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { - secp256k1_fe_t x; - return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03); +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { + secp256k1_fe x; + return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { - secp256k1_fe_t x, y; + secp256k1_fe x, y; if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { return 0; } secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { return 0; - return secp256k1_ge_is_valid(elem); + } + return secp256k1_ge_is_valid_var(elem); } else { return 0; } } -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) { +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { if (secp256k1_ge_is_infinity(elem)) { return 0; } - secp256k1_fe_normalize(&elem->x); - secp256k1_fe_normalize(&elem->y); + secp256k1_fe_normalize_var(&elem->x); + secp256k1_fe_normalize_var(&elem->y); secp256k1_fe_get_b32(&pub[1], &elem->x); if (compressed) { *size = 33; - pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); + pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; } else { *size = 65; - pub[0] = 0x04; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; secp256k1_fe_get_b32(&pub[33], &elem->y); } return 1; } -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) { - const unsigned char *end = privkey + privkeylen; - /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) - return 0; - privkey++; - /* sequence length constructor */ - int lenb = 0; - if (end < privkey+1 || !(*privkey & 0x80)) - return 0; - lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) - return 0; - if (end < privkey+lenb) - return 0; - /* sequence length */ - int len = 0; - len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); - privkey += lenb; - if (end < privkey+len) - return 0; - /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) - return 0; - privkey += 3; - /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) - return 0; - int overflow = 0; - unsigned char c[32] = {0}; - memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); - secp256k1_scalar_set_b32(key, c, &overflow); - memset(c, 0, 32); - return !overflow; -} - -static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { - secp256k1_gej_t rp; - secp256k1_ecmult_gen(&rp, key); - secp256k1_ge_t r; - secp256k1_ge_set_gej(&r, &rp); - if (compressed) { - static const unsigned char begin[] = { - 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - int pubkeylen = 0; - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } else { - static const unsigned char begin[] = { - 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, - 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, - 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - int pubkeylen = 0; - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } - return 1; -} - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { secp256k1_scalar_add(key, key, tweak); - if (secp256k1_scalar_is_zero(key)) + if (secp256k1_scalar_is_zero(key)) { return 0; + } return 1; } -static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_gej_t pt; +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_gej pt; + secp256k1_scalar one; secp256k1_gej_set_ge(&pt, key); - secp256k1_scalar_t one; secp256k1_scalar_set_int(&one, 1); - secp256k1_ecmult(&pt, &pt, &one, tweak); + secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); - if (secp256k1_gej_is_infinity(&pt)) + if (secp256k1_gej_is_infinity(&pt)) { return 0; + } secp256k1_ge_set_gej(key, &pt); return 1; } -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { - if (secp256k1_scalar_is_zero(tweak)) +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { + if (secp256k1_scalar_is_zero(tweak)) { return 0; + } secp256k1_scalar_mul(key, key, tweak); return 1; } -static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - if (secp256k1_scalar_is_zero(tweak)) +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_scalar zero; + secp256k1_gej pt; + if (secp256k1_scalar_is_zero(tweak)) { return 0; + } - secp256k1_scalar_t zero; secp256k1_scalar_set_int(&zero, 0); - secp256k1_gej_t pt; secp256k1_gej_set_ge(&pt, key); - secp256k1_ecmult(&pt, &pt, tweak, &zero); + secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); secp256k1_ge_set_gej(key, &pt); return 1; } -#endif +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index 15a7100a4a1f..ea1cd8a21f66 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -1,19 +1,47 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_ -#define _SECP256K1_ECMULT_ +#ifndef SECP256K1_ECMULT_H +#define SECP256K1_ECMULT_H #include "num.h" #include "group.h" +#include "scalar.h" +#include "scratch.h" -static void secp256k1_ecmult_start(void); -static void secp256k1_ecmult_stop(void); +typedef struct { + /* For accelerating the computation of a*P + b*G: */ + secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#endif +} secp256k1_ecmult_context; + +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); /** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); -#endif +typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data); + +/** + * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. + * Chooses the right algorithm for a given number of points and scratch space + * size. Resets and overwrites the given scratch space. If the points do not + * fit in the scratch space the algorithm is repeatedly run with batches of + * points. + * Returns: 1 on success (including when inp_g_sc is NULL and n is 0) + * 0 if there is not enough scratch space for a single point or + * callback returns 0 + */ +static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); + +#endif /* SECP256K1_ECMULT_H */ diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h new file mode 100644 index 000000000000..d4804b8b68fa --- /dev/null +++ b/src/secp256k1/src/ecmult_const.h @@ -0,0 +1,17 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H + +#include "scalar.h" +#include "group.h" + +/* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus + * one because we internally sometimes add 2 to the number during the WNAF conversion. */ +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits); + +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 000000000000..8411752eb069 --- /dev/null +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,257 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ + int m; \ + int abs_n = (n) * (((n) > 0) * 2 - 1); \ + int idx_n = abs_n / 2; \ + secp256k1_fe neg_y; \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ + for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + } \ + (r)->infinity = 0; \ + secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ +} while(0) + + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) + * - each wnaf[i] is nonzero + * - the number of words set is always WNAF_SIZE(w) + 1 + * + * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar + * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) + * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 + * + * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 + */ +static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) { + int global_sign; + int skew = 0; + int word = 0; + + /* 1 2 3 */ + int u_last; + int u; + + int flip; + int bit; + secp256k1_scalar neg_s; + int not_neg_one; + /* Note that we cannot handle even numbers by negating them to be odd, as is + * done in other implementations, since if our scalars were specified to have + * width < 256 for performance reasons, their negations would have width 256 + * and we'd lose any performance benefit. Instead, we use a technique from + * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) + * or 2 (for odd) to the number we are encoding, returning a skew value indicating + * this, and having the caller compensate after doing the multiplication. + * + * In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in + * particular, to ensure that the outputs from the endomorphism-split fit into + * 128 bits). If we negate, the parity of our number flips, inverting which of + * {1, 2} we want to add to the scalar when ensuring that it's odd. Further + * complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and + * we need to special-case it in this logic. */ + flip = secp256k1_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + bit = flip ^ !secp256k1_scalar_is_even(&s); + /* We check for negative one, since adding 2 to it will cause an overflow */ + secp256k1_scalar_negate(&neg_s, &s); + not_neg_one = !secp256k1_scalar_is_one(&neg_s); + secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); + /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects + * that we added two to it and flipped it. In fact for -1 these operations are + * identical. We only flipped, but since skewing is required (in the sense that + * the skew must be 1 or 2, never zero) and flipping is not, we need to change + * our flags to claim that we only skewed. */ + global_sign = secp256k1_scalar_cond_negate(&s, flip); + global_sign *= not_neg_one * 2 - 1; + skew = 1 << bit; + + /* 4 */ + u_last = secp256k1_scalar_shr_int(&s, w); + while (word * w < size) { + int sign; + int even; + + /* 4.1 4.4 */ + u = secp256k1_scalar_shr_int(&s, w); + /* 4.2 */ + even = ((u & 1) == 0); + sign = 2 * (u_last > 0) - 1; + u += sign * even; + u_last -= sign * even * (1 << w); + + /* 4.3, adapted for global sign change */ + wnaf[word++] = u_last * global_sign; + + u_last = u; + } + wnaf[word] = u * global_sign; + + VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); + VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w)); + return skew; +} + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; + + int skew_1; +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_lam; + secp256k1_scalar q_1, q_lam; +#endif + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; + + int i; + secp256k1_scalar sc = *scalar; + + /* build wnaf representation for q. */ + int rsize = size; +#ifdef USE_ENDOMORPHISM + if (size > 128) { + rsize = 128; + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); + skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128); + skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128); + } else +#endif + { + skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size); +#ifdef USE_ENDOMORPHISM + skew_lam = 0; +#endif + } + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_gej_set_ge(r, a); + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_normalize_weak(&pre_a[i].y); + } +#ifdef USE_ENDOMORPHISM + if (size > 128) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } + } +#endif + + /* first loop iteration (separated out so we can directly set r, rather + * than having it start at infinity, get doubled several times, then have + * its new value added to it) */ + i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); + } +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) { + int n; + int j; + for (j = 0; j < WINDOW_A - 1; ++j) { + secp256k1_gej_double_nonzero(r, r, NULL); + } + + n = wnaf_1[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); + } +#endif + } + + secp256k1_fe_mul(&r->z, &r->z, &Z); + + { + /* Correct for wNAF skew */ + secp256k1_ge correction = *a; + secp256k1_ge_storage correction_1_stor; +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage correction_lam_stor; +#endif + secp256k1_ge_storage a2_stor; + secp256k1_gej tmpj; + secp256k1_gej_set_ge(&tmpj, &correction); + secp256k1_gej_double_var(&tmpj, &tmpj, NULL); + secp256k1_ge_set_gej(&correction, &tmpj); + secp256k1_ge_to_storage(&correction_1_stor, a); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + secp256k1_ge_to_storage(&correction_lam_stor, a); + } +#endif + secp256k1_ge_to_storage(&a2_stor, &correction); + + /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ + secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); + } +#endif + + /* Apply the correction */ + secp256k1_ge_from_storage(&correction, &correction_1_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + +#ifdef USE_ENDOMORPHISM + if (size > 128) { + secp256k1_ge_from_storage(&correction, &correction_lam_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_ge_mul_lambda(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + } +#endif + } +} + +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index 42f822f9cef2..7564b7015f0b 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -4,16 +4,40 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_ -#define _SECP256K1_ECMULT_GEN_ +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H #include "scalar.h" #include "group.h" -static void secp256k1_ecmult_gen_start(void); -static void secp256k1_ecmult_gen_stop(void); +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). + * 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_scalar blind; + secp256k1_gej initial; +} secp256k1_ecmult_gen_context; + +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); +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(secp256k1_gej_t *r, const secp256k1_scalar_t *a); +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 +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index af0ead522d4a..714f02e94c98 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -1,121 +1,210 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * 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_ +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_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 +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { + ctx->prec = NULL; +} -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). - * None of the resulting prec group elements have a known scalar, and neither do any of - * the intermediate sums while computing a*G. - */ - secp256k1_fe_t prec[64][16][2]; /* prec[j][i] = (16^j * i * G + U_i).{x,y} */ -} secp256k1_ecmult_gen_consts_t; - -static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL; +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + secp256k1_ge prec[1024]; + secp256k1_gej gj; + secp256k1_gej nums_gej; + int i, j; +#endif -static void secp256k1_ecmult_gen_start(void) { - if (secp256k1_ecmult_gen_consts != NULL) + if (ctx->prec != NULL) { return; - - /* Allocate the precomputation table. */ - secp256k1_ecmult_gen_consts_t *ret = (secp256k1_ecmult_gen_consts_t*)malloc(sizeof(secp256k1_ecmult_gen_consts_t)); + } +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); /* get the generator */ - const secp256k1_ge_t *g = &secp256k1_ge_consts->g; - secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g); + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ - secp256k1_gej_t nums_gej; { - static const unsigned char nums_b32[32] = "The scalar for this x is unknown"; - secp256k1_fe_t nums_x; - VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); - secp256k1_ge_t nums_ge; - VERIFY_CHECK(secp256k1_ge_set_xo(&nums_ge, &nums_x, 0)); + 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, g); + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); } /* compute prec. */ - secp256k1_ge_t prec[1024]; { - secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */ - secp256k1_gej_t gbase; gbase = gj; /* 16^j * G */ - secp256k1_gej_t numsbase; numsbase = nums_gej; /* 2^j * nums. */ - for (int j=0; j<64; j++) { + secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ + secp256k1_gej gbase; + secp256k1_gej numsbase; + gbase = gj; /* 16^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 (int i=1; i<16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase); + for (i = 1; i < 16; i++) { + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); } /* Multiply gbase by 16. */ - for (int i=0; i<4; i++) { - secp256k1_gej_double_var(&gbase, &gbase); + for (i = 0; i < 4; i++) { + secp256k1_gej_double_var(&gbase, &gbase, NULL); } /* Multiply numbase by 2. */ - secp256k1_gej_double_var(&numsbase, &numsbase); + secp256k1_gej_double_var(&numsbase, &numsbase, NULL); if (j == 62) { /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ secp256k1_gej_neg(&numsbase, &numsbase); - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej); + secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(1024, prec, precj); + secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); } - for (int j=0; j<64; j++) { - for (int i=0; i<16; i++) { - VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[j*16 + i])); - ret->prec[j][i][0] = prec[j*16 + i].x; - ret->prec[j][i][1] = prec[j*16 + i].y; + for (j = 0; j < 64; j++) { + for (i = 0; i < 16; i++) { + secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); } } +#else + (void)cb; + ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; +#endif + secp256k1_ecmult_gen_blind(ctx, NULL); +} - /* Set the global pointer to the precomputation table. */ - secp256k1_ecmult_gen_consts = ret; +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { + return ctx->prec != NULL; } -static void secp256k1_ecmult_gen_stop(void) { - if (secp256k1_ecmult_gen_consts == NULL) - return; +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { + if (src->prec == NULL) { + dst->prec = NULL; + } else { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); + memcpy(dst->prec, src->prec, sizeof(*dst->prec)); +#else + (void)cb; + dst->prec = src->prec; +#endif + dst->initial = src->initial; + dst->blind = src->blind; + } +} - secp256k1_ecmult_gen_consts_t *c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts; - secp256k1_ecmult_gen_consts = NULL; - free(c); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + free(ctx->prec); +#endif + secp256k1_scalar_clear(&ctx->blind); + secp256k1_gej_clear(&ctx->initial); + ctx->prec = NULL; } -static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { - const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts; - secp256k1_gej_set_infinity(r); - secp256k1_ge_t add; - add.infinity = 0; +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; - for (int j=0; j<64; j++) { - bits = secp256k1_scalar_get_bits(gn, j * 4, 4); - for (int i=0; i<16; i++) { - secp256k1_fe_cmov(&add.x, &c->prec[j][i][0], i == bits); - secp256k1_fe_cmov(&add.y, &c->prec[j][i][1], i == 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++) { + /** 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); } -#endif +/* 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 |= 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 |= 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/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index 445b81593f89..d5fb6c5b61dd 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -1,120 +1,256 @@ -/********************************************************************** - * 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.* - **********************************************************************/ +/***************************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************/ -#ifndef _SECP256K1_ECMULT_IMPL_H_ -#define _SECP256K1_ECMULT_IMPL_H_ +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H + +#include +#include #include "group.h" #include "scalar.h" #include "ecmult.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# define WINDOW_G 8 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# define WINDOW_G 4 +# else +# define WINDOW_A 2 +# define WINDOW_G 2 +# endif +#else /* optimal for 128-bit and 256-bit exponents. */ #define WINDOW_A 5 - /** larger numbers may result in slightly better performance, at the cost of - exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB. */ + exponentially larger precomputed tables. */ #ifdef USE_ENDOMORPHISM -#define WINDOW_G 14 -#else +/** Two tables for window size 15: 1.375 MiB. */ #define WINDOW_G 15 +#else +/** One table for window size 16: 1.375 MiB. */ +#define WINDOW_G 16 #endif +#endif + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w)) +#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) + +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) + +/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ +#define PIPPENGER_SCRATCH_OBJECTS 6 +#define STRAUSS_SCRATCH_OBJECTS 6 + +#define PIPPENGER_MAX_BUCKET_WINDOW 12 + +/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ +#ifdef USE_ENDOMORPHISM + #define ECMULT_PIPPENGER_THRESHOLD 88 +#else + #define ECMULT_PIPPENGER_THRESHOLD 160 +#endif + +#ifdef USE_ENDOMORPHISM + #define ECMULT_MAX_POINTS_PER_BATCH 5000000 +#else + #define ECMULT_MAX_POINTS_PER_BATCH 10000000 +#endif + +/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain + * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will + * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. + * Prej's Z values are undefined, except for the last value. + */ +static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) { + secp256k1_gej d; + secp256k1_ge a_ge, d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_gej_double_var(&d, a, NULL); + + /* + * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate + * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. + */ + d_ge.x = d.x; + d_ge.y = d.y; + d_ge.infinity = 0; + + secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z); + prej[0].x = a_ge.x; + prej[0].y = a_ge.y; + prej[0].z = a->z; + prej[0].infinity = 0; + + zr[0] = d.z; + for (i = 1; i < n; i++) { + secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); + } + + /* + * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only + * the final point's z coordinate is actually used though, so just update that. + */ + secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); +} -/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table. - * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for - * 2^(w-2) entries. +/** Fill a table 'pre' with precomputed odd multiples of a. * * There are two versions of this function: - * - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation, - * fast to precompute, but slower to use in later additions. - * - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations, - * (much) slower to precompute, but a bit faster to use in later additions. - * To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as - * G is constant, so it only needs to be done once in advance. + * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its + * resulting point set to a single constant Z denominator, stores the X and Y + * coordinates as ge_storage points in pre, and stores the global Z in rz. + * It only operates on tables sized for WINDOW_A wnaf multiples. + * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its + * resulting point set to actually affine points, and stores those in pre. + * It operates on tables of any size, but uses heap-allocated temporaries. + * + * To compute a*P + b*G, we compute a table for P using the first function, + * and for G using the second (which requires an inverse, but it only needs to + * happen once). */ -static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) { - pre[0] = *a; - secp256k1_gej_t d; secp256k1_gej_double_var(&d, &pre[0]); - for (int i=1; i<(1 << (w-2)); i++) - secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]); +static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); + /* Bring them to the same Z denominator. */ + secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); } -static void secp256k1_ecmult_table_precomp_ge_var(secp256k1_ge_t *pre, const secp256k1_gej_t *a, int w) { - const int table_size = 1 << (w-2); - secp256k1_gej_t prej[table_size]; - prej[0] = *a; - secp256k1_gej_t d; secp256k1_gej_double_var(&d, a); - for (int i=1; i= -((1 << ((w)-1)) - 1)); \ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) \ + if ((n) > 0) { \ *(r) = (pre)[((n)-1)/2]; \ - else \ - (neg)((r), &(pre)[(-(n)-1)/2]); \ + } else { \ + secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ + } \ } while(0) -#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg) -#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg) +#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \ + } else { \ + secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_ge_neg((r), (r)); \ + } \ +} while(0) -typedef struct { - /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */ +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { + ctx->pre_g = NULL; #ifdef USE_ENDOMORPHISM - secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */ + ctx->pre_g_128 = NULL; #endif -} secp256k1_ecmult_consts_t; +} -static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL; +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { + secp256k1_gej gj; -static void secp256k1_ecmult_start(void) { - if (secp256k1_ecmult_consts != NULL) + if (ctx->pre_g != NULL) { return; - - /* Allocate the precomputation table. */ - secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)malloc(sizeof(secp256k1_ecmult_consts_t)); + } /* get the generator */ - const secp256k1_ge_t *g = &secp256k1_ge_consts->g; - secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g); + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); -#ifdef USE_ENDOMORPHISM - /* calculate 2^128*generator */ - secp256k1_gej_t g_128j = gj; - for (int i=0; i<128; i++) - secp256k1_gej_double_var(&g_128j, &g_128j); -#endif + ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* precompute the tables with odd multiples */ - secp256k1_ecmult_table_precomp_ge_var(ret->pre_g, &gj, WINDOW_G); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); + #ifdef USE_ENDOMORPHISM - secp256k1_ecmult_table_precomp_ge_var(ret->pre_g_128, &g_128j, WINDOW_G); + { + secp256k1_gej g_128j; + int i; + + ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + + /* calculate 2^128*generator */ + g_128j = gj; + for (i = 0; i < 128; i++) { + secp256k1_gej_double_var(&g_128j, &g_128j, NULL); + } + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); + } #endif +} - /* Set the global pointer to the precomputation table. */ - secp256k1_ecmult_consts = ret; +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { + if (src->pre_g == NULL) { + dst->pre_g = NULL; + } else { + size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); + memcpy(dst->pre_g, src->pre_g, size); + } +#ifdef USE_ENDOMORPHISM + if (src->pre_g_128 == NULL) { + dst->pre_g_128 = NULL; + } else { + size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); + memcpy(dst->pre_g_128, src->pre_g_128, size); + } +#endif } -static void secp256k1_ecmult_stop(void) { - if (secp256k1_ecmult_consts == NULL) - return; +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { + return ctx->pre_g != NULL; +} - secp256k1_ecmult_consts_t *c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts; - secp256k1_ecmult_consts = NULL; - free(c); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { + free(ctx->pre_g); +#ifdef USE_ENDOMORPHISM + free(ctx->pre_g_128); +#endif + secp256k1_ecmult_context_init(ctx); } /** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), @@ -122,124 +258,770 @@ static void secp256k1_ecmult_stop(void) { * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) * - two non-zero entries in wnaf are separated by at least w-1 zeroes. * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * - than the number of bits in the (absolute value) of the input. + * than the number of bits in the (absolute value) of the input. */ -static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) { - secp256k1_scalar_t s = *a; - +static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { + secp256k1_scalar s = *a; + int last_set_bit = -1; + int bit = 0; int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + memset(wnaf, 0, len * sizeof(wnaf[0])); + if (secp256k1_scalar_get_bits(&s, 255, 1)) { secp256k1_scalar_negate(&s, &s); sign = -1; } - int set_bits = 0; - int bit = 0; - while (bit < 256) { - if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) { + while (bit < len) { + int now; + int word; + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { bit++; continue; } - while (set_bits < bit) { - wnaf[set_bits++] = 0; - } - int now = w; - if (bit + now > 256) { - now = 256 - bit; - } - int word = secp256k1_scalar_get_bits_var(&s, bit, now); - if (word & (1 << (w-1))) { - secp256k1_scalar_add_bit(&s, bit + w); - wnaf[set_bits++] = sign * (word - (1 << w)); - } else { - wnaf[set_bits++] = sign * word; + + now = w; + if (now > len - bit) { + now = len - bit; } + + word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + bit += now; } - return set_bits; +#ifdef VERIFY + CHECK(carry == 0); + while (bit < 256) { + CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); + } +#endif + return last_set_bit + 1; } -static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { - const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts; +struct secp256k1_strauss_point_state { +#ifdef USE_ENDOMORPHISM + secp256k1_scalar na_1, na_lam; + int wnaf_na_1[130]; + int wnaf_na_lam[130]; + int bits_na_1; + int bits_na_lam; +#else + int wnaf_na[256]; + int bits_na; +#endif + size_t input_pos; +}; +struct secp256k1_strauss_state { + secp256k1_gej* prej; + secp256k1_fe* zr; + secp256k1_ge* pre_a; #ifdef USE_ENDOMORPHISM - secp256k1_scalar_t na_1, na_lam; - /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na); + secp256k1_ge* pre_a_lam; +#endif + struct secp256k1_strauss_point_state* ps; +}; - /* build wnaf representation for na_1 and na_lam. */ - int wnaf_na_1[130]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); - int wnaf_na_lam[130]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); - VERIFY_CHECK(bits_na_1 <= 130); - VERIFY_CHECK(bits_na_lam <= 130); - int bits = bits_na_1; - if (bits_na_lam > bits) bits = bits_na_lam; +static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, const struct secp256k1_strauss_state *state, secp256k1_gej *r, int num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_ge tmpa; + secp256k1_fe Z; +#ifdef USE_ENDOMORPHISM + /* Splitted G factors. */ + secp256k1_scalar ng_1, ng_128; + int wnaf_ng_1[129]; + int bits_ng_1 = 0; + int wnaf_ng_128[129]; + int bits_ng_128 = 0; #else - /* build wnaf representation for na. */ - int wnaf_na[256]; int bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); - int bits = bits_na; + int wnaf_ng[256]; + int bits_ng = 0; #endif + int i; + int bits = 0; + int np; + int no = 0; - /* calculate odd multiples of a */ - secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A); - + for (np = 0; np < num; ++np) { + if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) { + continue; + } + state->ps[no].input_pos = np; #ifdef USE_ENDOMORPHISM - secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - for (int i=0; ips[no].na_1, &state->ps[no].na_lam, &na[np]); - /* Splitted G factors. */ - secp256k1_scalar_t ng_1, ng_128; + /* build wnaf representation for na_1 and na_lam. */ + state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 130, &state->ps[no].na_1, WINDOW_A); + state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 130, &state->ps[no].na_lam, WINDOW_A); + VERIFY_CHECK(state->ps[no].bits_na_1 <= 130); + VERIFY_CHECK(state->ps[no].bits_na_lam <= 130); + if (state->ps[no].bits_na_1 > bits) { + bits = state->ps[no].bits_na_1; + } + if (state->ps[no].bits_na_lam > bits) { + bits = state->ps[no].bits_na_lam; + } +#else + /* build wnaf representation for na. */ + state->ps[no].bits_na = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na, 256, &na[np], WINDOW_A); + if (state->ps[no].bits_na > bits) { + bits = state->ps[no].bits_na; + } +#endif + ++no; + } - /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ - secp256k1_scalar_split_128(&ng_1, &ng_128, ng); + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + if (no > 0) { + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]); + for (np = 1; np < no; ++np) { + secp256k1_gej tmp = a[state->ps[np].input_pos]; +#ifdef VERIFY + secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z)); +#endif + secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z)); + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp); + secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z)); + } + /* Bring them to the same Z denominator. */ + secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr); + } else { + secp256k1_fe_set_int(&Z, 1); + } - /* Build wnaf representation for ng_1 and ng_128 */ - int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); - int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) bits = bits_ng_1; - if (bits_ng_128 > bits) bits = bits_ng_128; +#ifdef USE_ENDOMORPHISM + for (np = 0; np < no; ++np) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]); + } + } + + if (ng) { + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + secp256k1_scalar_split_128(&ng_1, &ng_128, ng); + + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } + } #else - int wnaf_ng[257]; int bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); - if (bits_ng > bits) bits = bits_ng; + if (ng) { + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); + if (bits_ng > bits) { + bits = bits_ng; + } + } #endif secp256k1_gej_set_infinity(r); - secp256k1_gej_t tmpj; - secp256k1_ge_t tmpa; - for (int i=bits-1; i>=0; i--) { - secp256k1_gej_double_var(r, r); + for (i = bits - 1; i >= 0; i--) { int n; + secp256k1_gej_double_var(r, r, NULL); #ifdef USE_ENDOMORPHISM - if (i < bits_na_1 && (n = wnaf_na_1[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); - } - if (i < bits_na_lam && (n = wnaf_na_lam[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { + ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { + ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } } if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } #else - if (i < bits_na && (n = wnaf_na[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na && (n = state->ps[np].wnaf_na[i])) { + ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } } if (i < bits_ng && (n = wnaf_ng[i])) { - ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); + } +#endif + } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } +} + +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + struct secp256k1_strauss_point_state ps[1]; +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; +#endif + struct secp256k1_strauss_state state; + + state.prej = prej; + state.zr = zr; + state.pre_a = pre_a; +#ifdef USE_ENDOMORPHISM + state.pre_a_lam = pre_a_lam; +#endif + state.ps = ps; + secp256k1_ecmult_strauss_wnaf(ctx, &state, r, 1, a, na, ng); +} + +static size_t secp256k1_strauss_scratch_size(size_t n_points) { +#ifdef USE_ENDOMORPHISM + static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); +#else + static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); +#endif + return n_points*point_size; +} + +static int secp256k1_ecmult_strauss_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + secp256k1_gej* points; + secp256k1_scalar* scalars; + struct secp256k1_strauss_state state; + size_t i; + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + + if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) { + return 0; + } + points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_gej)); + scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_scalar)); + state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej)); + state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); +#ifdef USE_ENDOMORPHISM + state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); + state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A); +#else + state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); +#endif + state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); + + for (i = 0; i < n_points; i++) { + secp256k1_ge point; + if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { + secp256k1_scratch_deallocate_frame(scratch); + return 0; + } + secp256k1_gej_set_ge(&points[i], &point); + } + secp256k1_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc); + secp256k1_scratch_deallocate_frame(scratch); + return 1; +} + +/* Wrapper for secp256k1_ecmult_multi_func interface */ +static int secp256k1_ecmult_strauss_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_ecmult_strauss_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +static size_t secp256k1_strauss_max_points(secp256k1_scratch *scratch) { + return secp256k1_scratch_max_allocation(scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); +} + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) + * - the number of words set is always WNAF_SIZE(w) + * - the returned skew is 0 or 1 + */ +static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) { + int skew = 0; + int pos; + int max_pos; + int last_w; + const secp256k1_scalar *work = s; + + if (secp256k1_scalar_is_zero(s)) { + for (pos = 0; pos < WNAF_SIZE(w); pos++) { + wnaf[pos] = 0; + } + return 0; + } + + if (secp256k1_scalar_is_even(s)) { + skew = 1; + } + + wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew; + /* Compute last window size. Relevant when window size doesn't divide the + * number of bits in the scalar */ + last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; + + /* Store the position of the first nonzero word in max_pos to allow + * skipping leading zeros when calculating the wnaf. */ + for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { + int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if(val != 0) { + break; + } + wnaf[pos] = 0; + } + max_pos = pos; + pos = 1; + + while (pos <= max_pos) { + int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if ((val & 1) == 0) { + wnaf[pos - 1] -= (1 << w); + wnaf[pos] = (val + 1); + } else { + wnaf[pos] = val; + } + /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit + * is strictly negative or strictly positive respectively. Only change + * coefficients at previous positions because above code assumes that + * wnaf[pos - 1] is odd. + */ + if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { + if (wnaf[pos - 1] == 1) { + wnaf[pos - 2] += 1 << w; + } else { + wnaf[pos - 2] -= 1 << w; + } + wnaf[pos - 1] = 0; + } + ++pos; + } + + return skew; +} + +struct secp256k1_pippenger_point_state { + int skew_na; + size_t input_pos; +}; + +struct secp256k1_pippenger_state { + int *wnaf_na; + struct secp256k1_pippenger_point_state* ps; +}; + +/* + * pippenger_wnaf computes the result of a multi-point multiplication as + * follows: The scalars are brought into wnaf with n_wnaf elements each. Then + * for every i < n_wnaf, first each point is added to a "bucket" corresponding + * to the point's wnaf[i]. Second, the buckets are added together such that + * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... + */ +static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_window, struct secp256k1_pippenger_state *state, secp256k1_gej *r, const secp256k1_scalar *sc, const secp256k1_ge *pt, size_t num) { + size_t n_wnaf = WNAF_SIZE(bucket_window+1); + size_t np; + size_t no = 0; + int i; + int j; + + for (np = 0; np < num; ++np) { + if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) { + continue; + } + state->ps[no].input_pos = np; + state->ps[no].skew_na = secp256k1_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); + no++; + } + secp256k1_gej_set_infinity(r); + + if (no == 0) { + return 1; + } + + for (i = n_wnaf - 1; i >= 0; i--) { + secp256k1_gej running_sum; + + for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { + secp256k1_gej_set_infinity(&buckets[j]); + } + + for (np = 0; np < no; ++np) { + int n = state->wnaf_na[np*n_wnaf + i]; + struct secp256k1_pippenger_point_state point_state = state->ps[np]; + secp256k1_ge tmp; + int idx; + + if (i == 0) { + /* correct for wnaf skew */ + int skew = point_state.skew_na; + if (skew) { + secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); + } + } + if (n > 0) { + idx = (n - 1)/2; + secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); + } else if (n < 0) { + idx = -(n + 1)/2; + secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); + } + } + + for(j = 0; j < bucket_window; j++) { + secp256k1_gej_double_var(r, r, NULL); } + + secp256k1_gej_set_infinity(&running_sum); + /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... + * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... + * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) + * using an intermediate running sum: + * running_sum = bucket[0] + bucket[1] + bucket[2] + ... + * + * The doubling is done implicitly by deferring the final window doubling (of 'r'). + */ + for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); + secp256k1_gej_add_var(r, r, &running_sum, NULL); + } + + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); + secp256k1_gej_double_var(r, r, NULL); + secp256k1_gej_add_var(r, r, &running_sum, NULL); + } + return 1; +} + +/** + * Returns optimal bucket_window (number of bits of a scalar represented by a + * set of buckets) for a given number of points. + */ +static int secp256k1_pippenger_bucket_window(size_t n) { +#ifdef USE_ENDOMORPHISM + if (n <= 1) { + return 1; + } else if (n <= 4) { + return 2; + } else if (n <= 20) { + return 3; + } else if (n <= 57) { + return 4; + } else if (n <= 136) { + return 5; + } else if (n <= 235) { + return 6; + } else if (n <= 1260) { + return 7; + } else if (n <= 4420) { + return 9; + } else if (n <= 7880) { + return 10; + } else if (n <= 16050) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +#else + if (n <= 1) { + return 1; + } else if (n <= 11) { + return 2; + } else if (n <= 45) { + return 3; + } else if (n <= 100) { + return 4; + } else if (n <= 275) { + return 5; + } else if (n <= 625) { + return 6; + } else if (n <= 1850) { + return 7; + } else if (n <= 3400) { + return 8; + } else if (n <= 9630) { + return 9; + } else if (n <= 17900) { + return 10; + } else if (n <= 32800) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +#endif +} + +/** + * Returns the maximum optimal number of points for a bucket_window. + */ +static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) { + switch(bucket_window) { +#ifdef USE_ENDOMORPHISM + case 1: return 1; + case 2: return 4; + case 3: return 20; + case 4: return 57; + case 5: return 136; + case 6: return 235; + case 7: return 1260; + case 8: return 1260; + case 9: return 4420; + case 10: return 7880; + case 11: return 16050; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; +#else + case 1: return 1; + case 2: return 11; + case 3: return 45; + case 4: return 100; + case 5: return 275; + case 6: return 625; + case 7: return 1850; + case 8: return 3400; + case 9: return 9630; + case 10: return 17900; + case 11: return 32800; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; #endif } + return 0; } + +#ifdef USE_ENDOMORPHISM +SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) { + secp256k1_scalar tmp = *s1; + secp256k1_scalar_split_lambda(s1, s2, &tmp); + secp256k1_ge_mul_lambda(p2, p1); + + if (secp256k1_scalar_is_high(s1)) { + secp256k1_scalar_negate(s1, s1); + secp256k1_ge_neg(p1, p1); + } + if (secp256k1_scalar_is_high(s2)) { + secp256k1_scalar_negate(s2, s2); + secp256k1_ge_neg(p2, p2); + } +} +#endif + +/** + * Returns the scratch size required for a given number of points (excluding + * base point G) without considering alignment. + */ +static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) { +#ifdef USE_ENDOMORPHISM + size_t entries = 2*n_points + 2; +#else + size_t entries = n_points + 1; +#endif + size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + return ((1<ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(scratch, entries * sizeof(*state_space->ps)); + state_space->wnaf_na = (int *) secp256k1_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); + buckets = (secp256k1_gej *) secp256k1_scratch_alloc(scratch, (1<ps[i].skew_na = 0; + for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) { + state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0; + } + } + for(i = 0; i < 1< max_alloc) { + break; + } + space_for_points = max_alloc - space_overhead; + + n_points = space_for_points/entry_size; + n_points = n_points > max_points ? max_points : n_points; + if (n_points > res) { + res = n_points; + } + if (n_points < max_points) { + /* A larger bucket_window may support even more points. But if we + * would choose that then the caller couldn't safely use any number + * smaller than what this function returns */ + break; + } + } + return res; +} + +typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t); +static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + size_t i; + + int (*f)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t); + size_t max_points; + size_t n_batches; + size_t n_batch_points; + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n == 0) { + return 1; + } else if (n == 0) { + secp256k1_scalar szero; + secp256k1_scalar_set_int(&szero, 0); + secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc); + return 1; + } + + max_points = secp256k1_pippenger_max_points(scratch); + if (max_points == 0) { + return 0; + } else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) { + max_points = ECMULT_MAX_POINTS_PER_BATCH; + } + n_batches = (n+max_points-1)/max_points; + n_batch_points = (n+n_batches-1)/n_batches; + + if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { + f = secp256k1_ecmult_pippenger_batch; + } else { + max_points = secp256k1_strauss_max_points(scratch); + if (max_points == 0) { + return 0; + } + n_batches = (n+max_points-1)/max_points; + n_batch_points = (n+n_batches-1)/n_batches; + f = secp256k1_ecmult_strauss_batch; + } + for(i = 0; i < n_batches; i++) { + size_t nbp = n < n_batch_points ? n : n_batch_points; + size_t offset = n_batch_points*i; + secp256k1_gej tmp; + if (!f(ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { + return 0; + } + secp256k1_gej_add_var(r, r, &tmp, NULL); + n -= nbp; + } + return 1; +} + +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h index 0cdf0fb47924..bb6692ad5783 100644 --- a/src/secp256k1/src/field.h +++ b/src/secp256k1/src/field.h @@ -4,13 +4,13 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_ -#define _SECP256K1_FIELD_ +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H /** Field element module. * * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properaties into account: + * it (and implementations) need to take certain properties into account: * - Each field element can be normalized or not. * - Each field element has a magnitude, which represents how far away * its representation is away from normalization. Normalized elements @@ -22,9 +22,7 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_FIELD_GMP) -#include "field_gmp.h" -#elif defined(USE_FIELD_10X26) +#if defined(USE_FIELD_10X26) #include "field_10x26.h" #elif defined(USE_FIELD_5X52) #include "field_5x52.h" @@ -32,91 +30,103 @@ #error "Please select field implementation" #endif -typedef struct { -#ifndef USE_NUM_NONE - secp256k1_num_t p; -#endif - secp256k1_fe_t order; -} secp256k1_fe_consts_t; +#include "util.h" -static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL; +/** Normalize a field element. */ +static void secp256k1_fe_normalize(secp256k1_fe *r); -/** Initialize field element precomputation data. */ -static void secp256k1_fe_start(void); +/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ +static void secp256k1_fe_normalize_weak(secp256k1_fe *r); -/** Unload field element precomputation data. */ -static void secp256k1_fe_stop(void); +/** Normalize a field element, without constant-time guarantee. */ +static void secp256k1_fe_normalize_var(secp256k1_fe *r); -/** Normalize a field element. */ -static void secp256k1_fe_normalize(secp256k1_fe_t *r); +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); /** Set a field element equal to a small integer. Resulting field element is normalized. */ -static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a); +static void secp256k1_fe_set_int(secp256k1_fe *r, int a); + +/** Sets a field element equal to zero, initializing all fields. */ +static void secp256k1_fe_clear(secp256k1_fe *a); /** Verify whether a field element is zero. Requires the input to be normalized. */ -static int secp256k1_fe_is_zero(const secp256k1_fe_t *a); +static int secp256k1_fe_is_zero(const secp256k1_fe *a); /** Check the "oddness" of a field element. Requires the input to be normalized. */ -static int secp256k1_fe_is_odd(const secp256k1_fe_t *a); +static int secp256k1_fe_is_odd(const secp256k1_fe *a); -/** Compare two field elements. Requires both inputs to be normalized */ -static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +/** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Same as secp256k1_fe_equal, but may be variable time. */ +static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */ -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); +/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a); +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); /** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input * as an argument. The magnitude of the output is one higher. */ -static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m); +static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that * small integer. */ -static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a); +static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); /** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ -static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); /** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b); +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); /** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); + +/** If a has a square root, it is computed in r and 1 is returned. If a does not + * have a square root, the root of its negation is computed and 0 is returned. + * The input's magnitude can be at most 8. The output magnitude is 1 (but not + * guaranteed to be normalized). The result in r will always be a square + * itself. */ +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the - * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be - * normalized). Return value indicates whether a square root was found. */ -static int secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a); +/** Checks whether a field element is a quadratic residue. */ +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); /** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ -static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]); +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len); -/** Potentially faster version of secp256k1_fe_inv_all, without constant-time guarantee. */ -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]); +/** Convert a field element to the storage type. */ +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); -/** Convert a field element to a hexadecimal string. */ -static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a); +/** Convert a field element back from the storage type. */ +static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); -/** Convert a hexadecimal string to a field element. */ -static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen); +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag); +static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -#endif +#endif /* SECP256K1_FIELD_H */ diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h index 66fb3f2563a6..727c5267fbb5 100644 --- a/src/secp256k1/src/field_10x26.h +++ b/src/secp256k1/src/field_10x26.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include @@ -16,6 +16,33 @@ typedef struct { int magnitude; int normalized; #endif -} secp256k1_fe_t; +} secp256k1_fe; +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) & 0x3FFFFFFUL, \ + (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ + (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ + (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ + (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ + (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ + (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ + (((uint32_t)d7) >> 10) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} #endif + +typedef struct { + uint32_t n[8]; +} secp256k1_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} +#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h index c4403fba22de..94f8132fc8e6 100644 --- a/src/secp256k1/src/field_10x26_impl.h +++ b/src/secp256k1/src/field_10x26_impl.h @@ -4,20 +4,15 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H -#include -#include #include "util.h" #include "num.h" #include "field.h" -static void secp256k1_fe_inner_start(void) {} -static void secp256k1_fe_inner_stop(void) {} - #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; r &= (d[0] <= 0x3FFFFFFUL * m); @@ -31,6 +26,7 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { r &= (d[8] <= 0x3FFFFFFUL * m); r &= (d[9] <= 0x03FFFFFUL * m); r &= (a->magnitude >= 0); + r &= (a->magnitude <= 32); if (a->normalized) { r &= (a->magnitude <= 1); if (r && (d[9] == 0x03FFFFFUL)) { @@ -42,19 +38,15 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { } VERIFY_CHECK(r == 1); } -#else -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { - (void)a; -} #endif -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; /* The first pass ensures the magnitude is 1, ... */ t0 += x * 0x3D1UL; t1 += (x << 6); @@ -103,7 +95,175 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + if (x) { + t0 += 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0, z1; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t z0, z1; + uint32_t x; + + t0 = r->n[0]; + t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + x = t9 >> 22; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0x3FFFFFFUL; + z1 = z0 ^ 0x3D0UL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + t4 = r->n[4]; + t5 = r->n[5]; + t6 = r->n[6]; + t7 = r->n[7]; + t8 = r->n[8]; + + t9 &= 0x03FFFFFUL; + t1 += (x << 6); + + t1 += (t0 >> 26); + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; #ifdef VERIFY @@ -113,16 +273,16 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + const uint32_t *t = a->n; #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); #endif - const uint32_t *t = a->n; return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); @@ -130,52 +290,48 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + int i; #ifdef VERIFY a->magnitude = 0; a->normalized = 1; #endif - for (int i=0; i<10; i++) { + for (i=0; i<10; i++) { a->n[i] = 0; } } -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif - const uint32_t *t = a->n, *u = b->n; - return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4]) - | (t[5]^u[5]) | (t[6]^u[6]) | (t[7]^u[7]) | (t[8]^u[8]) | (t[9]^u[9])) == 0; -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); VERIFY_CHECK(b->normalized); secp256k1_fe_verify(a); secp256k1_fe_verify(b); #endif - for (int i = 9; i >= 0; i--) { - if (a->n[i] > b->n[i]) return 1; - if (a->n[i] < b->n[i]) return -1; + for (i = 9; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } } return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; - for (int i=0; i<32; i++) { - for (int j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; - } - } +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); + r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); + r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); + r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); + r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); + r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); + r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); + r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); + r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); + r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); + if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { return 0; } @@ -188,23 +344,46 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); #endif - for (int i=0; i<32; i++) { - int c = 0; - for (int j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - c |= ((a->n[limb] >> shift) & 0x3) << (2 * j); - } - r[31-i] = c; - } + r[0] = (a->n[9] >> 14) & 0xff; + r[1] = (a->n[9] >> 6) & 0xff; + r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); + r[3] = (a->n[8] >> 16) & 0xff; + r[4] = (a->n[8] >> 8) & 0xff; + r[5] = a->n[8] & 0xff; + r[6] = (a->n[7] >> 18) & 0xff; + r[7] = (a->n[7] >> 10) & 0xff; + r[8] = (a->n[7] >> 2) & 0xff; + r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); + r[10] = (a->n[6] >> 12) & 0xff; + r[11] = (a->n[6] >> 4) & 0xff; + r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); + r[13] = (a->n[5] >> 14) & 0xff; + r[14] = (a->n[5] >> 6) & 0xff; + r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); + r[16] = (a->n[4] >> 16) & 0xff; + r[17] = (a->n[4] >> 8) & 0xff; + r[18] = a->n[4] & 0xff; + r[19] = (a->n[3] >> 18) & 0xff; + r[20] = (a->n[3] >> 10) & 0xff; + r[21] = (a->n[3] >> 2) & 0xff; + r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); + r[23] = (a->n[2] >> 12) & 0xff; + r[24] = (a->n[2] >> 4) & 0xff; + r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); + r[26] = (a->n[1] >> 14) & 0xff; + r[27] = (a->n[1] >> 6) & 0xff; + r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); + r[29] = (a->n[0] >> 16) & 0xff; + r[30] = (a->n[0] >> 8) & 0xff; + r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= m); secp256k1_fe_verify(a); @@ -226,7 +405,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25 #endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -244,7 +423,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); #endif @@ -265,13 +444,26 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1 #endif } +#if defined(USE_EXTERNAL_ASM) + +/* External assembler implementation */ +void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); + +#else + #ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #else #define VERIFY_BITS(x, n) do { } while(0) #endif -SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b, uint32_t *r) { +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + VERIFY_BITS(a[0], 30); VERIFY_BITS(a[1], 30); VERIFY_BITS(a[2], 30); @@ -293,14 +485,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin VERIFY_BITS(b[8], 30); VERIFY_BITS(b[9], 26); - const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. * px is a shorthand for sum(a[i]*b[x-i], i=0..x). * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. */ - uint64_t c, d; - d = (uint64_t)a[0] * b[9] + (uint64_t)a[1] * b[8] + (uint64_t)a[2] * b[7] @@ -313,7 +502,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[0]; /* VERIFY_BITS(d, 64); */ /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - uint32_t t9 = d & M; d >>= 26; + t9 = d & M; d >>= 26; VERIFY_BITS(t9, 26); VERIFY_BITS(d, 38); /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ @@ -332,12 +521,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[1]; VERIFY_BITS(d, 63); /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - uint64_t u0 = d & M; d >>= 26; c += u0 * R0; + u0 = d & M; d >>= 26; c += u0 * R0; VERIFY_BITS(u0, 26); VERIFY_BITS(d, 37); VERIFY_BITS(c, 61); /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - uint32_t t0 = c & M; c >>= 26; c += u0 * R1; + t0 = c & M; c >>= 26; c += u0 * R1; VERIFY_BITS(t0, 26); VERIFY_BITS(c, 37); /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ @@ -357,12 +546,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[2]; VERIFY_BITS(d, 63); /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - uint64_t u1 = d & M; d >>= 26; c += u1 * R0; + u1 = d & M; d >>= 26; c += u1 * R0; VERIFY_BITS(u1, 26); VERIFY_BITS(d, 37); VERIFY_BITS(c, 63); /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - uint32_t t1 = c & M; c >>= 26; c += u1 * R1; + t1 = c & M; c >>= 26; c += u1 * R1; VERIFY_BITS(t1, 26); VERIFY_BITS(c, 38); /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ @@ -382,12 +571,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[3]; VERIFY_BITS(d, 63); /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - uint64_t u2 = d & M; d >>= 26; c += u2 * R0; + u2 = d & M; d >>= 26; c += u2 * R0; VERIFY_BITS(u2, 26); VERIFY_BITS(d, 37); VERIFY_BITS(c, 63); /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - uint32_t t2 = c & M; c >>= 26; c += u2 * R1; + t2 = c & M; c >>= 26; c += u2 * R1; VERIFY_BITS(t2, 26); VERIFY_BITS(c, 38); /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ @@ -407,12 +596,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[4]; VERIFY_BITS(d, 63); /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - uint64_t u3 = d & M; d >>= 26; c += u3 * R0; + u3 = d & M; d >>= 26; c += u3 * R0; VERIFY_BITS(u3, 26); VERIFY_BITS(d, 37); /* VERIFY_BITS(c, 64); */ /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - uint32_t t3 = c & M; c >>= 26; c += u3 * R1; + t3 = c & M; c >>= 26; c += u3 * R1; VERIFY_BITS(t3, 26); VERIFY_BITS(c, 39); /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ @@ -432,12 +621,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[5]; VERIFY_BITS(d, 62); /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - uint64_t u4 = d & M; d >>= 26; c += u4 * R0; + u4 = d & M; d >>= 26; c += u4 * R0; VERIFY_BITS(u4, 26); VERIFY_BITS(d, 36); /* VERIFY_BITS(c, 64); */ /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - uint32_t t4 = c & M; c >>= 26; c += u4 * R1; + t4 = c & M; c >>= 26; c += u4 * R1; VERIFY_BITS(t4, 26); VERIFY_BITS(c, 39); /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ @@ -457,12 +646,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[6]; VERIFY_BITS(d, 62); /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - uint64_t u5 = d & M; d >>= 26; c += u5 * R0; + u5 = d & M; d >>= 26; c += u5 * R0; VERIFY_BITS(u5, 26); VERIFY_BITS(d, 36); /* VERIFY_BITS(c, 64); */ /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - uint32_t t5 = c & M; c >>= 26; c += u5 * R1; + t5 = c & M; c >>= 26; c += u5 * R1; VERIFY_BITS(t5, 26); VERIFY_BITS(c, 39); /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ @@ -482,12 +671,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[7]; VERIFY_BITS(d, 61); /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - uint64_t u6 = d & M; d >>= 26; c += u6 * R0; + u6 = d & M; d >>= 26; c += u6 * R0; VERIFY_BITS(u6, 26); VERIFY_BITS(d, 35); /* VERIFY_BITS(c, 64); */ /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - uint32_t t6 = c & M; c >>= 26; c += u6 * R1; + t6 = c & M; c >>= 26; c += u6 * R1; VERIFY_BITS(t6, 26); VERIFY_BITS(c, 39); /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ @@ -508,13 +697,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin + (uint64_t)a[9] * b[8]; VERIFY_BITS(d, 58); /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - uint64_t u7 = d & M; d >>= 26; c += u7 * R0; + u7 = d & M; d >>= 26; c += u7 * R0; VERIFY_BITS(u7, 26); VERIFY_BITS(d, 32); /* VERIFY_BITS(c, 64); */ VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - uint32_t t7 = c & M; c >>= 26; c += u7 * R1; + t7 = c & M; c >>= 26; c += u7 * R1; VERIFY_BITS(t7, 26); VERIFY_BITS(c, 38); /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ @@ -535,7 +724,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin d += (uint64_t)a[9] * b[9]; VERIFY_BITS(d, 57); /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - uint64_t u8 = d & M; d >>= 26; c += u8 * R0; + u8 = d & M; d >>= 26; c += u8 * R0; VERIFY_BITS(u8, 26); VERIFY_BITS(d, 31); /* VERIFY_BITS(c, 64); */ @@ -598,7 +787,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uin /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t *r) { +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + VERIFY_BITS(a[0], 30); VERIFY_BITS(a[1], 30); VERIFY_BITS(a[2], 30); @@ -610,14 +804,11 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t VERIFY_BITS(a[8], 30); VERIFY_BITS(a[9], 26); - const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. * px is a shorthand for sum(a[i]*a[x-i], i=0..x). * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. */ - uint64_t c, d; - d = (uint64_t)(a[0]*2) * a[9] + (uint64_t)(a[1]*2) * a[8] + (uint64_t)(a[2]*2) * a[7] @@ -625,7 +816,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)(a[4]*2) * a[5]; /* VERIFY_BITS(d, 64); */ /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - uint32_t t9 = d & M; d >>= 26; + t9 = d & M; d >>= 26; VERIFY_BITS(t9, 26); VERIFY_BITS(d, 38); /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ @@ -640,12 +831,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)a[5] * a[5]; VERIFY_BITS(d, 63); /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - uint64_t u0 = d & M; d >>= 26; c += u0 * R0; + u0 = d & M; d >>= 26; c += u0 * R0; VERIFY_BITS(u0, 26); VERIFY_BITS(d, 37); VERIFY_BITS(c, 61); /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - uint32_t t0 = c & M; c >>= 26; c += u0 * R1; + t0 = c & M; c >>= 26; c += u0 * R1; VERIFY_BITS(t0, 26); VERIFY_BITS(c, 37); /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ @@ -660,12 +851,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)(a[5]*2) * a[6]; VERIFY_BITS(d, 63); /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - uint64_t u1 = d & M; d >>= 26; c += u1 * R0; + u1 = d & M; d >>= 26; c += u1 * R0; VERIFY_BITS(u1, 26); VERIFY_BITS(d, 37); VERIFY_BITS(c, 63); /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - uint32_t t1 = c & M; c >>= 26; c += u1 * R1; + t1 = c & M; c >>= 26; c += u1 * R1; VERIFY_BITS(t1, 26); VERIFY_BITS(c, 38); /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ @@ -681,12 +872,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)a[6] * a[6]; VERIFY_BITS(d, 63); /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - uint64_t u2 = d & M; d >>= 26; c += u2 * R0; + u2 = d & M; d >>= 26; c += u2 * R0; VERIFY_BITS(u2, 26); VERIFY_BITS(d, 37); VERIFY_BITS(c, 63); /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - uint32_t t2 = c & M; c >>= 26; c += u2 * R1; + t2 = c & M; c >>= 26; c += u2 * R1; VERIFY_BITS(t2, 26); VERIFY_BITS(c, 38); /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ @@ -701,12 +892,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)(a[6]*2) * a[7]; VERIFY_BITS(d, 63); /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - uint64_t u3 = d & M; d >>= 26; c += u3 * R0; + u3 = d & M; d >>= 26; c += u3 * R0; VERIFY_BITS(u3, 26); VERIFY_BITS(d, 37); /* VERIFY_BITS(c, 64); */ /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - uint32_t t3 = c & M; c >>= 26; c += u3 * R1; + t3 = c & M; c >>= 26; c += u3 * R1; VERIFY_BITS(t3, 26); VERIFY_BITS(c, 39); /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ @@ -722,12 +913,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)a[7] * a[7]; VERIFY_BITS(d, 62); /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - uint64_t u4 = d & M; d >>= 26; c += u4 * R0; + u4 = d & M; d >>= 26; c += u4 * R0; VERIFY_BITS(u4, 26); VERIFY_BITS(d, 36); /* VERIFY_BITS(c, 64); */ /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - uint32_t t4 = c & M; c >>= 26; c += u4 * R1; + t4 = c & M; c >>= 26; c += u4 * R1; VERIFY_BITS(t4, 26); VERIFY_BITS(c, 39); /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ @@ -742,12 +933,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)(a[7]*2) * a[8]; VERIFY_BITS(d, 62); /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - uint64_t u5 = d & M; d >>= 26; c += u5 * R0; + u5 = d & M; d >>= 26; c += u5 * R0; VERIFY_BITS(u5, 26); VERIFY_BITS(d, 36); /* VERIFY_BITS(c, 64); */ /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - uint32_t t5 = c & M; c >>= 26; c += u5 * R1; + t5 = c & M; c >>= 26; c += u5 * R1; VERIFY_BITS(t5, 26); VERIFY_BITS(c, 39); /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ @@ -763,12 +954,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t + (uint64_t)a[8] * a[8]; VERIFY_BITS(d, 61); /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - uint64_t u6 = d & M; d >>= 26; c += u6 * R0; + u6 = d & M; d >>= 26; c += u6 * R0; VERIFY_BITS(u6, 26); VERIFY_BITS(d, 35); /* VERIFY_BITS(c, 64); */ /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - uint32_t t6 = c & M; c >>= 26; c += u6 * R1; + t6 = c & M; c >>= 26; c += u6 * R1; VERIFY_BITS(t6, 26); VERIFY_BITS(c, 39); /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ @@ -784,13 +975,13 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t d += (uint64_t)(a[8]*2) * a[9]; VERIFY_BITS(d, 58); /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - uint64_t u7 = d & M; d >>= 26; c += u7 * R0; + u7 = d & M; d >>= 26; c += u7 * R0; VERIFY_BITS(u7, 26); VERIFY_BITS(d, 32); /* VERIFY_BITS(c, 64); */ VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - uint32_t t7 = c & M; c >>= 26; c += u7 * R1; + t7 = c & M; c >>= 26; c += u7 * R1; VERIFY_BITS(t7, 26); VERIFY_BITS(c, 38); /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ @@ -807,7 +998,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t d += (uint64_t)a[9] * a[9]; VERIFY_BITS(d, 57); /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - uint64_t u8 = d & M; d >>= 26; c += u8 * R0; + u8 = d & M; d >>= 26; c += u8 * R0; VERIFY_BITS(u8, 26); VERIFY_BITS(d, 31); /* VERIFY_BITS(c, 64); */ @@ -869,9 +1060,9 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t VERIFY_BITS(r[2], 27); /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } +#endif - -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8); @@ -879,7 +1070,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s secp256k1_fe_verify(b); VERIFY_CHECK(r != b); #endif - secp256k1_fe_mul_inner(a->n, b->n, r->n); + secp256k1_fe_mul_inner(r->n, a->n, b->n); #ifdef VERIFY r->magnitude = 1; r->normalized = 0; @@ -887,12 +1078,12 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s #endif } -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); secp256k1_fe_verify(a); #endif - secp256k1_fe_sqr_inner(a->n, r->n); + secp256k1_fe_sqr_inner(r->n, a->n); #ifdef VERIFY r->magnitude = 1; r->normalized = 0; @@ -900,8 +1091,10 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { - uint32_t mask0 = flag + ~((uint32_t)0), mask1 = ~mask0; +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); @@ -913,11 +1106,56 @@ static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int fl r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); #ifdef VERIFY - if (flag) { + if (a->magnitude > r->magnitude) { r->magnitude = a->magnitude; - r->normalized = a->normalized; } + r->normalized &= a->normalized; #endif } +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); +} + +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 26; + r->n[1] = a->n[1] >> 6 | a->n[2] << 20; + r->n[2] = a->n[2] >> 12 | a->n[3] << 14; + r->n[3] = a->n[3] >> 18 | a->n[4] << 8; + r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28; + r->n[5] = a->n[6] >> 4 | a->n[7] << 22; + r->n[6] = a->n[7] >> 10 | a->n[8] << 16; + r->n[7] = a->n[8] >> 16 | a->n[9] << 10; +} + +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + r->n[0] = a->n[0] & 0x3FFFFFFUL; + r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); + r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); + r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL); + r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL); + r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL; + r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL); + r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); + r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); + r->n[9] = a->n[7] >> 10; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; #endif +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h index aeb0a6a1e861..bccd8feb4dde 100644 --- a/src/secp256k1/src/field_5x52.h +++ b/src/secp256k1/src/field_5x52.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include @@ -16,6 +16,32 @@ typedef struct { int magnitude; int normalized; #endif -} secp256k1_fe_t; +} secp256k1_fe; +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ + ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ + ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ + ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ + ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} #endif + +typedef struct { + uint64_t n[4]; +} secp256k1_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ +}} + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/secp256k1/src/field_5x52_asm.asm b/src/secp256k1/src/field_5x52_asm.asm deleted file mode 100644 index 5e785f763055..000000000000 --- a/src/secp256k1/src/field_5x52_asm.asm +++ /dev/null @@ -1,469 +0,0 @@ - ;; Added by Diederik Huys, March 2013 - ;; - ;; Provided public procedures: - ;; secp256k1_fe_mul_inner - ;; secp256k1_fe_sqr_inner - ;; - ;; Needed tools: YASM (http://yasm.tortall.net) - ;; - ;; - - BITS 64 - -%ifidn __OUTPUT_FORMAT__,macho64 -%define SYM(x) _ %+ x -%else -%define SYM(x) x -%endif - - ;; Procedure ExSetMult - ;; Register Layout: - ;; INPUT: rdi = a->n - ;; rsi = b->n - ;; rdx = r->a - ;; - ;; INTERNAL: rdx:rax = multiplication accumulator - ;; r9:r8 = c - ;; r10-r13 = t0-t3 - ;; r14 = b.n[0] / t4 - ;; r15 = b.n[1] / t5 - ;; rbx = b.n[2] / t6 - ;; rcx = b.n[3] / t7 - ;; rbp = Constant 0FFFFFFFFFFFFFh / t8 - ;; rsi = b.n / b.n[4] / t9 - - GLOBAL SYM(secp256k1_fe_mul_inner) - ALIGN 32 -SYM(secp256k1_fe_mul_inner): - push rbp - push rbx - push r12 - push r13 - push r14 - push r15 - push rdx - mov r14,[rsi+8*0] ; preload b.n[0]. This will be the case until - ; b.n[0] is no longer needed, then we reassign - ; r14 to t4 - ;; c=a.n[0] * b.n[0] - mov rax,[rdi+0*8] ; load a.n[0] - mov rbp,0FFFFFFFFFFFFFh - mul r14 ; rdx:rax=a.n[0]*b.n[0] - mov r15,[rsi+1*8] - mov r10,rbp ; load modulus into target register for t0 - mov r8,rax - and r10,rax ; only need lower qword of c - shrd r8,rdx,52 - xor r9,r9 ; c < 2^64, so we ditch the HO part - - ;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0] - mov rax,[rdi+0*8] - mul r15 - add r8,rax - adc r9,rdx - - mov rax,[rdi+1*8] - mul r14 - mov r11,rbp - mov rbx,[rsi+2*8] - add r8,rax - adc r9,rdx - and r11,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[0 1 2] * b.n[2 1 0] - mov rax,[rdi+0*8] - mul rbx - add r8,rax - adc r9,rdx - - mov rax,[rdi+1*8] - mul r15 - add r8,rax - adc r9,rdx - - mov rax,[rdi+2*8] - mul r14 - mov r12,rbp - mov rcx,[rsi+3*8] - add r8,rax - adc r9,rdx - and r12,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[0 1 2 3] * b.n[3 2 1 0] - mov rax,[rdi+0*8] - mul rcx - add r8,rax - adc r9,rdx - - mov rax,[rdi+1*8] - mul rbx - add r8,rax - adc r9,rdx - - mov rax,[rdi+2*8] - mul r15 - add r8,rax - adc r9,rdx - - mov rax,[rdi+3*8] - mul r14 - mov r13,rbp - mov rsi,[rsi+4*8] ; load b.n[4] and destroy pointer - add r8,rax - adc r9,rdx - and r13,r8 - - shrd r8,r9,52 - xor r9,r9 - - - ;; c+=a.n[0 1 2 3 4] * b.n[4 3 2 1 0] - mov rax,[rdi+0*8] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,[rdi+1*8] - mul rcx - add r8,rax - adc r9,rdx - - mov rax,[rdi+2*8] - mul rbx - add r8,rax - adc r9,rdx - - mov rax,[rdi+3*8] - mul r15 - add r8,rax - adc r9,rdx - - mov rax,[rdi+4*8] - mul r14 - mov r14,rbp ; load modulus into t4 and destroy a.n[0] - add r8,rax - adc r9,rdx - and r14,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[1 2 3 4] * b.n[4 3 2 1] - mov rax,[rdi+1*8] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,[rdi+2*8] - mul rcx - add r8,rax - adc r9,rdx - - mov rax,[rdi+3*8] - mul rbx - add r8,rax - adc r9,rdx - - mov rax,[rdi+4*8] - mul r15 - mov r15,rbp - add r8,rax - adc r9,rdx - - and r15,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[2 3 4] * b.n[4 3 2] - mov rax,[rdi+2*8] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,[rdi+3*8] - mul rcx - add r8,rax - adc r9,rdx - - mov rax,[rdi+4*8] - mul rbx - mov rbx,rbp - add r8,rax - adc r9,rdx - - and rbx,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[3 4] * b.n[4 3] - mov rax,[rdi+3*8] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,[rdi+4*8] - mul rcx - mov rcx,rbp - add r8,rax - adc r9,rdx - and rcx,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[4] * b.n[4] - mov rax,[rdi+4*8] - mul rsi - ;; mov rbp,rbp ; modulus already there! - add r8,rax - adc r9,rdx - and rbp,r8 - shrd r8,r9,52 - xor r9,r9 - - mov rsi,r8 ; load c into t9 and destroy b.n[4] - - ;; ******************************************************* -common_exit_norm: - mov rdi,01000003D10h ; load constant - - mov rax,r15 ; get t5 - mul rdi - add rax,r10 ; +t0 - adc rdx,0 - mov r10,0FFFFFFFFFFFFFh ; modulus. Sadly, we ran out of registers! - mov r8,rax ; +c - and r10,rax - shrd r8,rdx,52 - xor r9,r9 - - mov rax,rbx ; get t6 - mul rdi - add rax,r11 ; +t1 - adc rdx,0 - mov r11,0FFFFFFFFFFFFFh ; modulus - add r8,rax ; +c - adc r9,rdx - and r11,r8 - shrd r8,r9,52 - xor r9,r9 - - mov rax,rcx ; get t7 - mul rdi - add rax,r12 ; +t2 - adc rdx,0 - pop rbx ; retrieve pointer to this.n - mov r12,0FFFFFFFFFFFFFh ; modulus - add r8,rax ; +c - adc r9,rdx - and r12,r8 - mov [rbx+2*8],r12 ; mov into this.n[2] - shrd r8,r9,52 - xor r9,r9 - - mov rax,rbp ; get t8 - mul rdi - add rax,r13 ; +t3 - adc rdx,0 - mov r13,0FFFFFFFFFFFFFh ; modulus - add r8,rax ; +c - adc r9,rdx - and r13,r8 - mov [rbx+3*8],r13 ; -> this.n[3] - shrd r8,r9,52 - xor r9,r9 - - mov rax,rsi ; get t9 - mul rdi - add rax,r14 ; +t4 - adc rdx,0 - mov r14,0FFFFFFFFFFFFh ; !!! - add r8,rax ; +c - adc r9,rdx - and r14,r8 - mov [rbx+4*8],r14 ; -> this.n[4] - shrd r8,r9,48 ; !!! - xor r9,r9 - - mov rax,01000003D1h - mul r8 - add rax,r10 - adc rdx,0 - mov r10,0FFFFFFFFFFFFFh ; modulus - mov r8,rax - and rax,r10 - shrd r8,rdx,52 - mov [rbx+0*8],rax ; -> this.n[0] - add r8,r11 - mov [rbx+1*8],r8 ; -> this.n[1] - - pop r15 - pop r14 - pop r13 - pop r12 - pop rbx - pop rbp - ret - - - ;; PROC ExSetSquare - ;; Register Layout: - ;; INPUT: rdi = a.n - ;; rsi = this.a - ;; INTERNAL: rdx:rax = multiplication accumulator - ;; r9:r8 = c - ;; r10-r13 = t0-t3 - ;; r14 = a.n[0] / t4 - ;; r15 = a.n[1] / t5 - ;; rbx = a.n[2] / t6 - ;; rcx = a.n[3] / t7 - ;; rbp = 0FFFFFFFFFFFFFh / t8 - ;; rsi = a.n[4] / t9 - GLOBAL SYM(secp256k1_fe_sqr_inner) - ALIGN 32 -SYM(secp256k1_fe_sqr_inner): - push rbp - push rbx - push r12 - push r13 - push r14 - push r15 - push rsi - mov rbp,0FFFFFFFFFFFFFh - - ;; c=a.n[0] * a.n[0] - mov r14,[rdi+0*8] ; r14=a.n[0] - mov r10,rbp ; modulus - mov rax,r14 - mul rax - mov r15,[rdi+1*8] ; a.n[1] - add r14,r14 ; r14=2*a.n[0] - mov r8,rax - and r10,rax ; only need lower qword - shrd r8,rdx,52 - xor r9,r9 - - ;; c+=2*a.n[0] * a.n[1] - mov rax,r14 ; r14=2*a.n[0] - mul r15 - mov rbx,[rdi+2*8] ; rbx=a.n[2] - mov r11,rbp ; modulus - add r8,rax - adc r9,rdx - and r11,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1] - mov rax,r14 - mul rbx - add r8,rax - adc r9,rdx - - mov rax,r15 - mov r12,rbp ; modulus - mul rax - mov rcx,[rdi+3*8] ; rcx=a.n[3] - add r15,r15 ; r15=a.n[1]*2 - add r8,rax - adc r9,rdx - and r12,r8 ; only need lower dword - shrd r8,r9,52 - xor r9,r9 - - ;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2] - mov rax,r14 - mul rcx - add r8,rax - adc r9,rdx - - mov rax,r15 ; rax=2*a.n[1] - mov r13,rbp ; modulus - mul rbx - mov rsi,[rdi+4*8] ; rsi=a.n[4] - add r8,rax - adc r9,rdx - and r13,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=2*a.n[0]*a.n[4]+2*a.n[1]*a.n[3]+a.n[2]*a.n[2] - mov rax,r14 ; last time we need 2*a.n[0] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,r15 - mul rcx - mov r14,rbp ; modulus - add r8,rax - adc r9,rdx - - mov rax,rbx - mul rax - add rbx,rbx ; rcx=2*a.n[2] - add r8,rax - adc r9,rdx - and r14,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=2*a.n[1]*a.n[4]+2*a.n[2]*a.n[3] - mov rax,r15 ; last time we need 2*a.n[1] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,rbx - mul rcx - mov r15,rbp ; modulus - add r8,rax - adc r9,rdx - and r15,r8 - shrd r8,r9,52 - xor r9,r9 - - ;; c+=2*a.n[2]*a.n[4]+a.n[3]*a.n[3] - mov rax,rbx ; last time we need 2*a.n[2] - mul rsi - add r8,rax - adc r9,rdx - - mov rax,rcx ; a.n[3] - mul rax - mov rbx,rbp ; modulus - add r8,rax - adc r9,rdx - and rbx,r8 ; only need lower dword - lea rax,[2*rcx] - shrd r8,r9,52 - xor r9,r9 - - ;; c+=2*a.n[3]*a.n[4] - mul rsi - mov rcx,rbp ; modulus - add r8,rax - adc r9,rdx - and rcx,r8 ; only need lower dword - shrd r8,r9,52 - xor r9,r9 - - ;; c+=a.n[4]*a.n[4] - mov rax,rsi - mul rax - ;; mov rbp,rbp ; modulus is already there! - add r8,rax - adc r9,rdx - and rbp,r8 - shrd r8,r9,52 - xor r9,r9 - - mov rsi,r8 - - ;; ******************************************************* - jmp common_exit_norm - end - - diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h index f29605b11b98..1fc3171f6b0e 100644 --- a/src/secp256k1/src/field_5x52_asm_impl.h +++ b/src/secp256k1/src/field_5x52_asm_impl.h @@ -1,13 +1,502 @@ /********************************************************************** - * Copyright (c) 2013 Pieter Wuille * + * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +/** + * Changelog: + * - March 2013, Diederik Huys: original version + * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm + * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly + */ -void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r); -void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r); +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H -#endif +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * r15:rcx = d + * r10-r14 = a0-a4 + * rbx = b + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + + /* d += a3 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rcx\n" + "movq %%rdx,%%r15\n" + /* d += a2 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d = a0 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c = a4 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* d += a4 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a0 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* t4 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a4 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* u0 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a1 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a4 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a2 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a1 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b2 (last use of %%r10 = a0) */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* d += a4 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rcx only) */ + "shrdq $52,%%r15,%%rcx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rcx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "b"(b), "D"(r) +: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * rcx:rbx = d + * r10-r14 = a0-a4 + * r15 = M (0xfffffffffffff) + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + "movq $0xfffffffffffff,%%r15\n" + + /* d = (a0*2) * a3 */ + "leaq (%%r10,%%r10,1),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rbx\n" + "movq %%rdx,%%rcx\n" + /* d += (a1*2) * a2 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c = a4 * a4 */ + "movq %%r14,%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* a4 *= 2 */ + "addq %%r14,%%r14\n" + /* d += a0 * a4 */ + "movq %%r10,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d+= (a1*2) * a3 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a2 * a2 */ + "movq %%r12,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* t4 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * a0 */ + "movq %%r10,%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a1 * a4 */ + "movq %%r11,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += (a2*2) * a3 */ + "leaq (%%r12,%%r12,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* u0 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* a0 *= 2 */ + "addq %%r10,%%r10\n" + /* c += a0 * a1 */ + "movq %%r10,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a2 * a4 */ + "movq %%r12,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a3 * a3 */ + "movq %%r13,%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a0 * a2 (last use of %%r10) */ + "movq %%r10,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* c += a1 * a1 */ + "movq %%r11,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a3 * a4 */ + "movq %%r13,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rbx only) */ + "shrdq $52,%%rcx,%%rbx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rbx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "D"(r) +: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h index 75b210eaf688..957c61b01451 100644 --- a/src/secp256k1/src/field_5x52_impl.h +++ b/src/secp256k1/src/field_5x52_impl.h @@ -4,24 +4,21 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" #endif -#include #include "util.h" #include "num.h" #include "field.h" -#if defined(USE_FIELD_5X52_ASM) +#if defined(USE_ASM_X86_64) #include "field_5x52_asm_impl.h" -#elif defined(USE_FIELD_5X52_INT128) -#include "field_5x52_int128_impl.h" #else -#error "Please select field_5x52 implementation" +#include "field_5x52_int128_impl.h" #endif /** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, @@ -32,19 +29,18 @@ * output. */ -static void secp256k1_fe_inner_start(void) {} -static void secp256k1_fe_inner_stop(void) {} - #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); r &= (a->magnitude >= 0); + r &= (a->magnitude <= 2048); if (a->normalized) { r &= (a->magnitude <= 1); if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { @@ -53,18 +49,14 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { } VERIFY_CHECK(r == 1); } -#else -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { - (void)a; -} #endif -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; /* The first pass ensures the magnitude is 1, ... */ t0 += x * 0x1000003D1ULL; @@ -102,7 +94,139 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + if (x) { + t0 += 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { + uint64_t t0, t1, t2, t3, t4; + uint64_t z0, z1; + uint64_t x; + + t0 = r->n[0]; + t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + x = t4 >> 48; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0xFFFFFFFFFFFFFULL; + z1 = z0 ^ 0x1000003D0ULL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + + t4 &= 0x0FFFFFFFFFFFFULL; + + t1 += (t0 >> 52); + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; #ifdef VERIFY @@ -112,16 +236,16 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + const uint64_t *t = a->n; #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); #endif - const uint64_t *t = a->n; return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); @@ -129,50 +253,71 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + int i; #ifdef VERIFY a->magnitude = 0; a->normalized = 1; #endif - for (int i=0; i<5; i++) { + for (i=0; i<5; i++) { a->n[i] = 0; } } -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif - const uint64_t *t = a->n, *u = b->n; - return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4])) == 0; -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); VERIFY_CHECK(b->normalized); secp256k1_fe_verify(a); secp256k1_fe_verify(b); #endif - for (int i = 4; i >= 0; i--) { - if (a->n[i] > b->n[i]) return 1; - if (a->n[i] < b->n[i]) return -1; + for (i = 4; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } } return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - for (int i=0; i<32; i++) { - for (int j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; - } - } +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint64_t)a[31] + | ((uint64_t)a[30] << 8) + | ((uint64_t)a[29] << 16) + | ((uint64_t)a[28] << 24) + | ((uint64_t)a[27] << 32) + | ((uint64_t)a[26] << 40) + | ((uint64_t)(a[25] & 0xF) << 48); + r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) + | ((uint64_t)a[24] << 4) + | ((uint64_t)a[23] << 12) + | ((uint64_t)a[22] << 20) + | ((uint64_t)a[21] << 28) + | ((uint64_t)a[20] << 36) + | ((uint64_t)a[19] << 44); + r->n[2] = (uint64_t)a[18] + | ((uint64_t)a[17] << 8) + | ((uint64_t)a[16] << 16) + | ((uint64_t)a[15] << 24) + | ((uint64_t)a[14] << 32) + | ((uint64_t)a[13] << 40) + | ((uint64_t)(a[12] & 0xF) << 48); + r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) + | ((uint64_t)a[11] << 4) + | ((uint64_t)a[10] << 12) + | ((uint64_t)a[9] << 20) + | ((uint64_t)a[8] << 28) + | ((uint64_t)a[7] << 36) + | ((uint64_t)a[6] << 44); + r->n[4] = (uint64_t)a[5] + | ((uint64_t)a[4] << 8) + | ((uint64_t)a[3] << 16) + | ((uint64_t)a[2] << 24) + | ((uint64_t)a[1] << 32) + | ((uint64_t)a[0] << 40); if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { return 0; } @@ -185,23 +330,46 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); #endif - for (int i=0; i<32; i++) { - int c = 0; - for (int j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - c |= ((a->n[limb] >> shift) & 0xF) << (4 * j); - } - r[31-i] = c; - } + r[0] = (a->n[4] >> 40) & 0xFF; + r[1] = (a->n[4] >> 32) & 0xFF; + r[2] = (a->n[4] >> 24) & 0xFF; + r[3] = (a->n[4] >> 16) & 0xFF; + r[4] = (a->n[4] >> 8) & 0xFF; + r[5] = a->n[4] & 0xFF; + r[6] = (a->n[3] >> 44) & 0xFF; + r[7] = (a->n[3] >> 36) & 0xFF; + r[8] = (a->n[3] >> 28) & 0xFF; + r[9] = (a->n[3] >> 20) & 0xFF; + r[10] = (a->n[3] >> 12) & 0xFF; + r[11] = (a->n[3] >> 4) & 0xFF; + r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); + r[13] = (a->n[2] >> 40) & 0xFF; + r[14] = (a->n[2] >> 32) & 0xFF; + r[15] = (a->n[2] >> 24) & 0xFF; + r[16] = (a->n[2] >> 16) & 0xFF; + r[17] = (a->n[2] >> 8) & 0xFF; + r[18] = a->n[2] & 0xFF; + r[19] = (a->n[1] >> 44) & 0xFF; + r[20] = (a->n[1] >> 36) & 0xFF; + r[21] = (a->n[1] >> 28) & 0xFF; + r[22] = (a->n[1] >> 20) & 0xFF; + r[23] = (a->n[1] >> 12) & 0xFF; + r[24] = (a->n[1] >> 4) & 0xFF; + r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); + r[26] = (a->n[0] >> 40) & 0xFF; + r[27] = (a->n[0] >> 32) & 0xFF; + r[28] = (a->n[0] >> 24) & 0xFF; + r[29] = (a->n[0] >> 16) & 0xFF; + r[30] = (a->n[0] >> 8) & 0xFF; + r[31] = a->n[0] & 0xFF; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= m); secp256k1_fe_verify(a); @@ -218,7 +386,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25 #endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -231,7 +399,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); #endif @@ -247,7 +415,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1 #endif } -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8); @@ -255,7 +423,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s secp256k1_fe_verify(b); VERIFY_CHECK(r != b); #endif - secp256k1_fe_mul_inner(a->n, b->n, r->n); + secp256k1_fe_mul_inner(r->n, a->n, b->n); #ifdef VERIFY r->magnitude = 1; r->normalized = 0; @@ -263,12 +431,12 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s #endif } -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); secp256k1_fe_verify(a); #endif - secp256k1_fe_sqr_inner(a->n, r->n); + secp256k1_fe_sqr_inner(r->n, a->n); #ifdef VERIFY r->magnitude = 1; r->normalized = 0; @@ -276,19 +444,53 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { - uint64_t mask0 = flag + ~((uint64_t)0), mask1 = ~mask0; +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); #ifdef VERIFY - if (flag) { + if (a->magnitude > r->magnitude) { r->magnitude = a->magnitude; - r->normalized = a->normalized; } + r->normalized &= a->normalized; #endif } +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); +} + +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); #endif + r->n[0] = a->n[0] | a->n[1] << 52; + r->n[1] = a->n[1] >> 12 | a->n[2] << 40; + r->n[2] = a->n[2] >> 24 | a->n[3] << 28; + r->n[3] = a->n[3] >> 36 | a->n[4] << 16; +} + +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; + r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); + r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); + r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); + r->n[4] = a->n[3] >> 16; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h index e552fb4319ef..95a0d1791c05 100644 --- a/src/secp256k1/src/field_5x52_int128_impl.h +++ b/src/secp256k1/src/field_5x52_int128_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H #include @@ -15,7 +15,12 @@ #define VERIFY_BITS(x, n) do { } while(0) #endif -SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b, uint64_t *r) { +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { + uint128_t c, d; + uint64_t t3, t4, tx, u0; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + VERIFY_BITS(a[0], 56); VERIFY_BITS(a[1], 56); VERIFY_BITS(a[2], 56); @@ -28,63 +33,58 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin VERIFY_BITS(b[4], 52); VERIFY_CHECK(r != b); - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. * px is a shorthand for sum(a[i]*b[x-i], i=0..x). * Note that [x 0 0 0 0 0] = [x*R]. */ - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - - __int128 c, d; - - d = (__int128)a0 * b[3] - + (__int128)a1 * b[2] - + (__int128)a2 * b[1] - + (__int128)a3 * b[0]; + d = (uint128_t)a0 * b[3] + + (uint128_t)a1 * b[2] + + (uint128_t)a2 * b[1] + + (uint128_t)a3 * b[0]; VERIFY_BITS(d, 114); /* [d 0 0 0] = [p3 0 0 0] */ - c = (__int128)a4 * b[4]; + c = (uint128_t)a4 * b[4]; VERIFY_BITS(c, 112); /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ d += (c & M) * R; c >>= 52; VERIFY_BITS(d, 115); VERIFY_BITS(c, 60); /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - uint64_t t3 = d & M; d >>= 52; + t3 = d & M; d >>= 52; VERIFY_BITS(t3, 52); VERIFY_BITS(d, 63); /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (__int128)a0 * b[4] - + (__int128)a1 * b[3] - + (__int128)a2 * b[2] - + (__int128)a3 * b[1] - + (__int128)a4 * b[0]; + d += (uint128_t)a0 * b[4] + + (uint128_t)a1 * b[3] + + (uint128_t)a2 * b[2] + + (uint128_t)a3 * b[1] + + (uint128_t)a4 * b[0]; VERIFY_BITS(d, 115); /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ d += c * R; VERIFY_BITS(d, 116); /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - uint64_t t4 = d & M; d >>= 52; + t4 = d & M; d >>= 52; VERIFY_BITS(t4, 52); VERIFY_BITS(d, 64); /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - uint64_t tx = (t4 >> 48); t4 &= (M >> 4); + tx = (t4 >> 48); t4 &= (M >> 4); VERIFY_BITS(tx, 4); VERIFY_BITS(t4, 48); /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - c = (__int128)a0 * b[0]; + c = (uint128_t)a0 * b[0]; VERIFY_BITS(c, 112); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (__int128)a1 * b[4] - + (__int128)a2 * b[3] - + (__int128)a3 * b[2] - + (__int128)a4 * b[1]; + d += (uint128_t)a1 * b[4] + + (uint128_t)a2 * b[3] + + (uint128_t)a3 * b[2] + + (uint128_t)a4 * b[1]; VERIFY_BITS(d, 115); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - uint64_t u0 = d & M; d >>= 52; + u0 = d & M; d >>= 52; VERIFY_BITS(u0, 52); VERIFY_BITS(d, 63); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ @@ -92,7 +92,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (__int128)u0 * (R >> 4); + c += (uint128_t)u0 * (R >> 4); VERIFY_BITS(c, 115); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ r[0] = c & M; c >>= 52; @@ -100,13 +100,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin VERIFY_BITS(c, 61); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (__int128)a0 * b[1] - + (__int128)a1 * b[0]; + c += (uint128_t)a0 * b[1] + + (uint128_t)a1 * b[0]; VERIFY_BITS(c, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (__int128)a2 * b[4] - + (__int128)a3 * b[3] - + (__int128)a4 * b[2]; + d += (uint128_t)a2 * b[4] + + (uint128_t)a3 * b[3] + + (uint128_t)a4 * b[2]; VERIFY_BITS(d, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ c += (d & M) * R; d >>= 52; @@ -118,13 +118,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin VERIFY_BITS(c, 63); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (__int128)a0 * b[2] - + (__int128)a1 * b[1] - + (__int128)a2 * b[0]; + c += (uint128_t)a0 * b[2] + + (uint128_t)a1 * b[1] + + (uint128_t)a2 * b[0]; VERIFY_BITS(c, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (__int128)a3 * b[4] - + (__int128)a4 * b[3]; + d += (uint128_t)a3 * b[4] + + (uint128_t)a4 * b[3]; VERIFY_BITS(d, 114); /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ c += (d & M) * R; d >>= 52; @@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin VERIFY_BITS(r[2], 52); VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; @@ -152,65 +152,65 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r) { +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { + uint128_t c, d; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + int64_t t3, t4, tx, u0; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + VERIFY_BITS(a[0], 56); VERIFY_BITS(a[1], 56); VERIFY_BITS(a[2], 56); VERIFY_BITS(a[3], 56); VERIFY_BITS(a[4], 52); - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. * px is a shorthand for sum(a[i]*a[x-i], i=0..x). * Note that [x 0 0 0 0 0] = [x*R]. */ - __int128 c, d; - - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - - d = (__int128)(a0*2) * a3 - + (__int128)(a1*2) * a2; + d = (uint128_t)(a0*2) * a3 + + (uint128_t)(a1*2) * a2; VERIFY_BITS(d, 114); /* [d 0 0 0] = [p3 0 0 0] */ - c = (__int128)a4 * a4; + c = (uint128_t)a4 * a4; VERIFY_BITS(c, 112); /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ d += (c & M) * R; c >>= 52; VERIFY_BITS(d, 115); VERIFY_BITS(c, 60); /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - uint64_t t3 = d & M; d >>= 52; + t3 = d & M; d >>= 52; VERIFY_BITS(t3, 52); VERIFY_BITS(d, 63); /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ a4 *= 2; - d += (__int128)a0 * a4 - + (__int128)(a1*2) * a3 - + (__int128)a2 * a2; + d += (uint128_t)a0 * a4 + + (uint128_t)(a1*2) * a3 + + (uint128_t)a2 * a2; VERIFY_BITS(d, 115); /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ d += c * R; VERIFY_BITS(d, 116); /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - uint64_t t4 = d & M; d >>= 52; + t4 = d & M; d >>= 52; VERIFY_BITS(t4, 52); VERIFY_BITS(d, 64); /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - uint64_t tx = (t4 >> 48); t4 &= (M >> 4); + tx = (t4 >> 48); t4 &= (M >> 4); VERIFY_BITS(tx, 4); VERIFY_BITS(t4, 48); /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - c = (__int128)a0 * a0; + c = (uint128_t)a0 * a0; VERIFY_BITS(c, 112); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (__int128)a1 * a4 - + (__int128)(a2*2) * a3; + d += (uint128_t)a1 * a4 + + (uint128_t)(a2*2) * a3; VERIFY_BITS(d, 114); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - uint64_t u0 = d & M; d >>= 52; + u0 = d & M; d >>= 52; VERIFY_BITS(u0, 52); VERIFY_BITS(d, 62); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ @@ -218,7 +218,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (__int128)u0 * (R >> 4); + c += (uint128_t)u0 * (R >> 4); VERIFY_BITS(c, 113); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ r[0] = c & M; c >>= 52; @@ -227,11 +227,11 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ a0 *= 2; - c += (__int128)a0 * a1; + c += (uint128_t)a0 * a1; VERIFY_BITS(c, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (__int128)a2 * a4 - + (__int128)a3 * a3; + d += (uint128_t)a2 * a4 + + (uint128_t)a3 * a3; VERIFY_BITS(d, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ c += (d & M) * R; d >>= 52; @@ -243,11 +243,11 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t VERIFY_BITS(c, 63); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (__int128)a0 * a2 - + (__int128)a1 * a1; + c += (uint128_t)a0 * a2 + + (uint128_t)a1 * a1; VERIFY_BITS(c, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (__int128)a3 * a4; + d += (uint128_t)a3 * a4; VERIFY_BITS(d, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ c += (d & M) * R; d >>= 52; @@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; @@ -274,4 +274,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -#endif +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/secp256k1/src/field_gmp_impl.h b/src/secp256k1/src/field_gmp_impl.h deleted file mode 100644 index 8af7dd68f8e8..000000000000 --- a/src/secp256k1/src/field_gmp_impl.h +++ /dev/null @@ -1,180 +0,0 @@ -/********************************************************************** - * 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_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ - -#include -#include -#include "num.h" -#include "field.h" - -static mp_limb_t secp256k1_field_p[FIELD_LIMBS]; -static mp_limb_t secp256k1_field_pc[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS]; - -static void secp256k1_fe_inner_start(void) { - for (int i=0; i<(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; i++) - secp256k1_field_pc[i] = 0; - secp256k1_field_pc[0] += 0x3D1UL; - secp256k1_field_pc[32/GMP_NUMB_BITS] += (((mp_limb_t)1) << (32 % GMP_NUMB_BITS)); - for (int i=0; in[FIELD_LIMBS] != 0) { -#if (GMP_NUMB_BITS >= 40) - mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * r->n[FIELD_LIMBS]); - mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * carry); -#else - mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * r->n[FIELD_LIMBS]) + - mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), r->n[FIELD_LIMBS] << (32 % GMP_NUMB_BITS)); - mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * carry); - mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), carry << (32%GMP_NUMB_BITS)); -#endif - r->n[FIELD_LIMBS] = 0; - } - if (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) >= 0) - mpn_sub(r->n, r->n, FIELD_LIMBS, secp256k1_field_p, FIELD_LIMBS); -} - -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { - r->n[0] = a; - for (int i=1; in[i] = 0; -} - -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *r) { - for (int i=0; in[i] = 0; -} - -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { - int ret = 1; - for (int i=0; in[i] == 0); - return ret; -} - -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { - return a->n[0] & 1; -} - -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - int ret = 1; - for (int i=0; in[i] == b->n[i]); - return ret; -} - -SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - for (int i=FIELD_LIMBS; i>=0; i--) { - if (a->n[i] > b->n[i]) return 1; - if (a->n[i] < b->n[i]) return -1; - } - return 0; -} - -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { - for (int i=0; in[i] = 0; - for (int i=0; i<256; i++) { - int limb = i/GMP_NUMB_BITS; - int shift = i%GMP_NUMB_BITS; - r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift; - } - return (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) < 0); -} - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { - for (int i=0; i<32; i++) { - int c = 0; - for (int j=0; j<8; j++) { - int limb = (8*i+j)/GMP_NUMB_BITS; - int shift = (8*i+j)%GMP_NUMB_BITS; - c |= ((a->n[limb] >> shift) & 0x1) << j; - } - r[31-i] = c; - } -} - -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { - (void)m; - *r = *a; - secp256k1_fe_normalize(r); - for (int i=0; in[i] = ~(r->n[i]); -#if (GMP_NUMB_BITS >= 33) - mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x1000003D0ULL); -#else - mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x3D0UL); - mpn_sub_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS)); -#endif -} - -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { - mpn_mul_1(r->n, r->n, FIELD_LIMBS+1, a); -} - -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - mpn_add(r->n, r->n, FIELD_LIMBS+1, a->n, FIELD_LIMBS+1); -} - -static void secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) { - /** - * B1 B2 B3 B4 - * + C * A1 A2 A3 A4 - * + A1 A2 A3 A4 - */ - -#if (GMP_NUMB_BITS >= 33) - mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x1000003D1ULL); -#else - mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x3D1UL) + - mpn_addmul_1(tmp+(32/GMP_NUMB_BITS), tmp+FIELD_LIMBS, FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS)); -#endif - mp_limb_t q[1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS]; - q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] = mpn_mul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o); -#if (GMP_NUMB_BITS <= 32) - mp_limb_t o2 = tmp[2*FIELD_LIMBS-(32/GMP_NUMB_BITS)] << (32%GMP_NUMB_BITS); - q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] += mpn_addmul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o2); -#endif - r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS); -} - -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { - VERIFY_CHECK(r != b); - secp256k1_fe_t ac = *a; - secp256k1_fe_t bc = *b; - secp256k1_fe_normalize(&ac); - secp256k1_fe_normalize(&bc); - mp_limb_t tmp[2*FIELD_LIMBS]; - mpn_mul_n(tmp, ac.n, bc.n, FIELD_LIMBS); - secp256k1_fe_reduce(r, tmp); -} - -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t ac = *a; - secp256k1_fe_normalize(&ac); - mp_limb_t tmp[2*FIELD_LIMBS]; - mpn_sqr(tmp, ac.n, FIELD_LIMBS); - secp256k1_fe_reduce(r, tmp); -} - -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { - mp_limb_t mask0 = flag + ~((mp_limb_t)0), mask1 = ~mask0; - for (int i = 0; i <= FIELD_LIMBS; i++) { - r->n[i] = (r->n[i] & mask0) | (a->n[i] & mask1); - } -} - -#endif diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index 4d25e5371526..20428648af31 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/src/field_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_IMPL_H_ -#define _SECP256K1_FIELD_IMPL_H_ +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -13,9 +13,7 @@ #include "util.h" -#if defined(USE_FIELD_GMP) -#include "field_gmp_impl.h" -#elif defined(USE_FIELD_10X26) +#if defined(USE_FIELD_10X26) #include "field_10x26_impl.h" #elif defined(USE_FIELD_5X52) #include "field_5x52_impl.h" @@ -23,106 +21,108 @@ #error "Please select field implementation" #endif -static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) { - if (*rlen < 65) { - *rlen = 65; - return; - } - *rlen = 65; - unsigned char tmp[32]; - secp256k1_fe_t b = *a; - secp256k1_fe_normalize(&b); - secp256k1_fe_get_b32(tmp, &b); - for (int i=0; i<32; i++) { - static const char *c = "0123456789ABCDEF"; - r[2*i] = c[(tmp[i] >> 4) & 0xF]; - r[2*i+1] = c[(tmp[i]) & 0xF]; - } - r[64] = 0x00; +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero(&na); } -static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) { - unsigned char tmp[32] = {}; - static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0, - 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}; - for (int i=0; i<32; i++) { - if (alen > i*2) - tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]]; - } - return secp256k1_fe_set_b32(r, tmp); +SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero_var(&na); } -static int secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] */ - secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, a); secp256k1_fe_mul(&x2, &x2, a); - secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &x2); secp256k1_fe_mul(&x3, &x3, a); - secp256k1_fe_t x6 = x3; - for (int j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6); + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } secp256k1_fe_mul(&x6, &x6, &x3); - secp256k1_fe_t x9 = x6; - for (int j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9); + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } secp256k1_fe_mul(&x9, &x9, &x3); - secp256k1_fe_t x11 = x9; - for (int j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11); + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } secp256k1_fe_mul(&x11, &x11, &x2); - secp256k1_fe_t x22 = x11; - for (int j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22); + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } secp256k1_fe_mul(&x22, &x22, &x11); - secp256k1_fe_t x44 = x22; - for (int j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44); + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } secp256k1_fe_mul(&x44, &x44, &x22); - secp256k1_fe_t x88 = x44; - for (int j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88); + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } secp256k1_fe_mul(&x88, &x88, &x44); - secp256k1_fe_t x176 = x88; - for (int j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176); + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } secp256k1_fe_mul(&x176, &x176, &x88); - secp256k1_fe_t x220 = x176; - for (int j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220); + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } secp256k1_fe_mul(&x220, &x220, &x44); - secp256k1_fe_t x223 = x220; - for (int j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223); + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } secp256k1_fe_mul(&x223, &x223, &x3); /* The final result is then assembled using a sliding window over the blocks. */ - secp256k1_fe_t t1 = x223; - for (int j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1); + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x22); - for (int j=0; j<6; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<6; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x2); secp256k1_fe_sqr(&t1, &t1); secp256k1_fe_sqr(r, &t1); @@ -130,135 +130,156 @@ static int secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - secp256k1_fe_negate(&t1, &t1, 1); - secp256k1_fe_add(&t1, a); - secp256k1_fe_normalize(&t1); - return secp256k1_fe_is_zero(&t1); + return secp256k1_fe_equal(&t1, a); } -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] */ - secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, a); secp256k1_fe_mul(&x2, &x2, a); - secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &x2); secp256k1_fe_mul(&x3, &x3, a); - secp256k1_fe_t x6 = x3; - for (int j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6); + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } secp256k1_fe_mul(&x6, &x6, &x3); - secp256k1_fe_t x9 = x6; - for (int j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9); + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } secp256k1_fe_mul(&x9, &x9, &x3); - secp256k1_fe_t x11 = x9; - for (int j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11); + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } secp256k1_fe_mul(&x11, &x11, &x2); - secp256k1_fe_t x22 = x11; - for (int j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22); + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } secp256k1_fe_mul(&x22, &x22, &x11); - secp256k1_fe_t x44 = x22; - for (int j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44); + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } secp256k1_fe_mul(&x44, &x44, &x22); - secp256k1_fe_t x88 = x44; - for (int j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88); + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } secp256k1_fe_mul(&x88, &x88, &x44); - secp256k1_fe_t x176 = x88; - for (int j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176); + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } secp256k1_fe_mul(&x176, &x176, &x88); - secp256k1_fe_t x220 = x176; - for (int j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220); + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } secp256k1_fe_mul(&x220, &x220, &x44); - secp256k1_fe_t x223 = x220; - for (int j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223); + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } secp256k1_fe_mul(&x223, &x223, &x3); /* The final result is then assembled using a sliding window over the blocks. */ - secp256k1_fe_t t1 = x223; - for (int j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1); + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x22); - for (int j=0; j<5; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<5; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, a); - for (int j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x2); - for (int j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(r, a, &t1); } -static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { #if defined(USE_FIELD_INV_BUILTIN) secp256k1_fe_inv(r, a); #elif defined(USE_FIELD_INV_NUM) + secp256k1_num n, m; + static const secp256k1_fe negone = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL + ); + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; unsigned char b[32]; - secp256k1_fe_t c = *a; - secp256k1_fe_normalize(&c); + int res; + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); secp256k1_fe_get_b32(b, &c); - secp256k1_num_t n; secp256k1_num_set_bin(&n, b, 32); - secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p); + secp256k1_num_set_bin(&m, prime, 32); + secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); - VERIFY_CHECK(secp256k1_fe_set_b32(r, b)); + res = secp256k1_fe_set_b32(r, b); + (void)res; + VERIFY_CHECK(res); + /* Verify the result is the (unique) valid inverse using non-GMP code. */ + secp256k1_fe_mul(&c, &c, r); + secp256k1_fe_add(&c, &negone); + CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); #else #error "Please select field inverse implementation" #endif } -static void secp256k1_fe_inv_all(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]) { - if (len < 1) +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { + secp256k1_fe u; + size_t i; + if (len < 1) { return; - - VERIFY_CHECK((r + len <= a) || (a + len <= r)); - - r[0] = a[0]; - - size_t i = 0; - while (++i < len) { - secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]); - } - - secp256k1_fe_t u; secp256k1_fe_inv(&u, &r[--i]); - - while (i > 0) { - int j = i--; - secp256k1_fe_mul(&r[j], &r[i], &u); - secp256k1_fe_mul(&u, &u, &a[j]); } - r[0] = u; -} - -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]) { - if (len < 1) - return; - VERIFY_CHECK((r + len <= a) || (a + len <= r)); r[0] = a[0]; - size_t i = 0; + i = 0; while (++i < len) { secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]); } - secp256k1_fe_t u; secp256k1_fe_inv_var(&u, &r[--i]); + secp256k1_fe_inv_var(&u, &r[--i]); while (i > 0) { - int j = i--; + size_t j = i--; secp256k1_fe_mul(&r[j], &r[i], &u); secp256k1_fe_mul(&u, &u, &a[j]); } @@ -266,32 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const se r[0] = u; } -static void secp256k1_fe_start(void) { +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { #ifndef USE_NUM_NONE - static const unsigned char secp256k1_fe_consts_p[] = { + unsigned char b[32]; + secp256k1_num n; + secp256k1_num m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F }; -#endif - if (secp256k1_fe_consts == NULL) { - secp256k1_fe_inner_start(); - secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t)); -#ifndef USE_NUM_NONE - secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p)); -#endif - secp256k1_fe_consts = ret; - } -} -static void secp256k1_fe_stop(void) { - if (secp256k1_fe_consts != NULL) { - secp256k1_fe_consts_t *c = (secp256k1_fe_consts_t*)secp256k1_fe_consts; - free((void*)c); - secp256k1_fe_consts = NULL; - secp256k1_fe_inner_stop(); - } + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + return secp256k1_num_jacobi(&n, &m) >= 0; +#else + secp256k1_fe r; + return secp256k1_fe_sqrt(&r, a); +#endif } -#endif +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c new file mode 100644 index 000000000000..87d296ebf0e2 --- /dev/null +++ b/src/secp256k1/src/gen_context.c @@ -0,0 +1,74 @@ +/********************************************************************** + * 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.* + **********************************************************************/ + +#define USE_BASIC_CONFIG 1 + +#include "basic-config.h" +#include "include/secp256k1.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; + 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"); + + secp256k1_ecmult_gen_context_init(&ctx); + secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); + for(outer = 0; outer != 64; outer++) { + fprintf(fp,"{\n"); + for(inner = 0; inner != 16; 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) { + fprintf(fp,",\n"); + } else { + fprintf(fp,"\n"); + } + } + if (outer != 63) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + fprintf(fp,"};\n"); + secp256k1_ecmult_gen_context_clear(&ctx); + + fprintf(fp, "#undef SC\n"); + fprintf(fp, "#endif\n"); + fclose(fp); + + return 0; +} diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h index 0f14bd25f309..3947ea2ddafa 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -4,117 +4,144 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_GROUP_ -#define _SECP256K1_GROUP_ +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H #include "num.h" #include "field.h" /** A group element of the secp256k1 curve, in affine coordinates. */ typedef struct { - secp256k1_fe_t x; - secp256k1_fe_t y; + secp256k1_fe x; + secp256k1_fe y; int infinity; /* whether this represents the point at infinity */ -} secp256k1_ge_t; +} secp256k1_ge; + +#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} +#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} /** A group element of the secp256k1 curve, in jacobian coordinates. */ typedef struct { - secp256k1_fe_t x; /* actual X: x/z^2 */ - secp256k1_fe_t y; /* actual Y: y/z^3 */ - secp256k1_fe_t z; + secp256k1_fe x; /* actual X: x/z^2 */ + secp256k1_fe y; /* actual Y: y/z^3 */ + secp256k1_fe z; int infinity; /* whether this represents the point at infinity */ -} secp256k1_gej_t; - -/** Global constants related to the group */ -typedef struct { - secp256k1_ge_t g; /* the generator point */ - -#ifdef USE_ENDOMORPHISM - /* constants related to secp256k1's efficiently computable endomorphism */ - secp256k1_fe_t beta; -#endif -} secp256k1_ge_consts_t; +} secp256k1_gej; -static const secp256k1_ge_consts_t *secp256k1_ge_consts = NULL; +#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} +#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} -/** Initialize the group module. */ -static void secp256k1_ge_start(void); +typedef struct { + secp256k1_fe_storage x; + secp256k1_fe_storage y; +} secp256k1_ge_storage; -/** De-initialize the group module. */ -static void secp256k1_ge_stop(void); +#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} -/** Set a group element equal to the point at infinity */ -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r); +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) /** Set a group element equal to the point with given X and Y coordinates */ -static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate + * and a Y coordinate that is a quadratic residue modulo p. The return value + * is true iff a coordinate with the given X coordinate exists. + */ +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x); /** Set a group element (affine) equal to the point with the given X coordinate, and given oddness * for Y. Return value indicates whether the result is valid. */ -static int secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd); +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); /** Check whether a group element is the point at infinity. */ -static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a); +static int secp256k1_ge_is_infinity(const secp256k1_ge *a); /** Check whether a group element is valid (i.e., on the curve). */ -static int secp256k1_ge_is_valid(const secp256k1_ge_t *a); +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); -static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a); - -/** Get a hex representation of a point. *rlen will be overwritten with the real length. */ -static void secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a); +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); /** Set a group element equal to another which is given in jacobian coordinates */ -static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a); +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t r[len], const secp256k1_gej_t a[len]); +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb); +/** Set a batch of group elements equal to the inputs given in jacobian + * coordinates (with known z-ratios). zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len); -/** Set a group element (jacobian) equal to the point at infinity. */ -static void secp256k1_gej_set_infinity(secp256k1_gej_t *r); +/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to + * the same global z "denominator". zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y + * coordinates of the result are stored in r, the common z coordinate is + * stored in globalz. */ +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr); -/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */ -static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); +/** Set a group element (affine) equal to the point at infinity. */ +static void secp256k1_ge_set_infinity(secp256k1_ge *r); + +/** Set a group element (jacobian) equal to the point at infinity. */ +static void secp256k1_gej_set_infinity(secp256k1_gej *r); /** Set a group element (jacobian) equal to another which is given in affine coordinates. */ -static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a); +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); -/** Get the X coordinate of a group element (jacobian). */ -static void secp256k1_gej_get_x_var(secp256k1_fe_t *r, const secp256k1_gej_t *a); +/** Compare the X coordinate of a group element (jacobian). */ +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); /** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); /** Check whether a group element is the point at infinity. */ -static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a); +static int secp256k1_gej_is_infinity(const secp256k1_gej *a); + +/** Check whether a group element's y coordinate is a quadratic residue. */ +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a); -/** Set r equal to the double of a. */ -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a); +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). + * a may not be zero. Constant time. */ +static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); -/** Set r equal to the sum of a and b. */ -static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b); +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */ +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); /** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ -static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); /** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. */ -static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); + guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); -/** Get a hex representation of a point. *rlen will be overwritten with the real length. */ -static void secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a); +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); #ifdef USE_ENDOMORPHISM /** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ -static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); #endif -/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */ -static void secp256k1_gej_clear(secp256k1_gej_t *r); +/** Clear a secp256k1_gej to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej *r); -/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */ -static void secp256k1_ge_clear(secp256k1_ge_t *r); +/** Clear a secp256k1_ge to prevent leaking sensitive information. */ +static void secp256k1_ge_clear(secp256k1_ge *r); -#endif +/** Convert a group element to the storage type. */ +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); + +/** Convert a group element back from the storage type. */ +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); + +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); + +#endif /* SECP256K1_GROUP_H */ diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index cbd0d8c4fc61..b1ace87b6ffd 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -4,63 +4,105 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_GROUP_IMPL_H_ -#define _SECP256K1_GROUP_IMPL_H_ - -#include +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H #include "num.h" #include "field.h" #include "group.h" -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) { - r->infinity = 1; +/* These points can be generated in sage as follows: + * + * 0. Setup a worksheet with the following parameters. + * b = 4 # whatever CURVE_B will be set to + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (b)]) + * + * 1. Determine all the small orders available to you. (If there are + * no satisfactory ones, go back and change b.) + * print C.order().factor(limit=1000) + * + * 2. Choose an order as one of the prime factors listed in the above step. + * (You can also multiply some to get a composite order, though the + * tests will crash trying to invert scalars during signing.) We take a + * random point and scale it to drop its order to the desired value. + * There is some probability this won't work; just try again. + * order = 199 + * P = C.random_point() + * P = (int(P.order()) / int(order)) * P + * assert(P.order() == order) + * + * 3. Print the values. You'll need to use a vim macro or something to + * split the hex output into 4-byte chunks. + * print "%x %x" % P.xy() + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 199 +const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, + 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, + 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, + 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED +); + +const int CURVE_B = 4; +# elif EXHAUSTIVE_TEST_ORDER == 13 +const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, + 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, + 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, + 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac +); +const int CURVE_B = 2; +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, + 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, + 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, + 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL +); + +const int CURVE_B = 7; +#endif + +static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; } -static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { r->infinity = 0; r->x = *x; r->y = *y; } -static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a) { +static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { return a->infinity; } -static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) { - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - secp256k1_fe_normalize(&r->y); +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { + *r = *a; + secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); } -static void secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a) { - char cx[65]; int lx=65; - char cy[65]; int ly=65; - secp256k1_fe_get_hex(cx, &lx, &a->x); - secp256k1_fe_get_hex(cy, &ly, &a->y); - lx = strlen(cx); - ly = strlen(cy); - int len = lx + ly + 3 + 1; - if (*rlen < len) { - *rlen = len; - return; - } - *rlen = len; - r[0] = '('; - memcpy(r+1, cx, lx); - r[1+lx] = ','; - memcpy(r+2+lx, cy, ly); - r[2+lx+ly] = ')'; - r[3+lx+ly] = 0; -} - -static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); - secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); secp256k1_fe_mul(&a->x, &a->x, &z2); secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_set_int(&a->z, 1); @@ -68,14 +110,15 @@ static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; r->infinity = a->infinity; if (a->infinity) { return; } secp256k1_fe_inv_var(&a->z, &a->z); - secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); secp256k1_fe_mul(&a->x, &a->x, &z2); secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_set_int(&a->z, 1); @@ -83,140 +126,217 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t r[len], const secp256k1_gej_t a[len]) { +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) { + secp256k1_fe *az; + secp256k1_fe *azi; + size_t i; size_t count = 0; - secp256k1_fe_t az[len]; - for (size_t i=0; i 0) { + /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */ + secp256k1_fe_inv(&zi, &a[i].z); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + + /* Work out way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + secp256k1_fe_mul(&zi, &zi, &zr[i]); + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + } + } +} + +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zs; + + if (len > 0) { + /* The z of the final point gives us the "global Z" for the table. */ + r[i].x = a[i].x; + r[i].y = a[i].y; + *globalz = a[i].z; + r[i].infinity = 0; + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + secp256k1_fe_mul(&zs, &zs, &zr[i]); + } + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs); + } + } +} + +static void secp256k1_gej_set_infinity(secp256k1_gej *r) { r->infinity = 1; - secp256k1_fe_set_int(&r->x, 0); - secp256k1_fe_set_int(&r->y, 0); - secp256k1_fe_set_int(&r->z, 0); + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); } -static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { - r->infinity = 0; - r->x = *x; - r->y = *y; - secp256k1_fe_set_int(&r->z, 1); +static void secp256k1_ge_set_infinity(secp256k1_ge *r) { + r->infinity = 1; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); } -static void secp256k1_gej_clear(secp256k1_gej_t *r) { +static void secp256k1_gej_clear(secp256k1_gej *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); } -static void secp256k1_ge_clear(secp256k1_ge_t *r) { +static void secp256k1_ge_clear(secp256k1_ge *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); } -static int secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) { +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { + secp256k1_fe x2, x3, c; r->x = *x; - secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, x); - secp256k1_fe_t x3; secp256k1_fe_mul(&x3, x, &x2); + secp256k1_fe_sqr(&x2, x); + secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&c, &x3); - if (!secp256k1_fe_sqrt(&r->y, &c)) + return secp256k1_fe_sqrt(&r->y, &c); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + if (!secp256k1_ge_set_xquad(r, x)) { return 0; - secp256k1_fe_normalize(&r->y); - if (secp256k1_fe_is_odd(&r->y) != odd) + } + secp256k1_fe_normalize_var(&r->y); + if (secp256k1_fe_is_odd(&r->y) != odd) { secp256k1_fe_negate(&r->y, &r->y, 1); + } return 1; + } -static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) { +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); } -static void secp256k1_gej_get_x_var(secp256k1_fe_t *r, const secp256k1_gej_t *a) { - secp256k1_fe_t zi2; secp256k1_fe_inv_var(&zi2, &a->z); secp256k1_fe_sqr(&zi2, &zi2); - secp256k1_fe_mul(r, &a->x, &zi2); +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { + secp256k1_fe r, r2; + VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); + r2 = a->x; secp256k1_fe_normalize_weak(&r2); + return secp256k1_fe_equal_var(&r, &r2); } -static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; r->z = a->z; - secp256k1_fe_normalize(&r->y); + secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); } -static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) { +static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { return a->infinity; } -static int secp256k1_gej_is_valid(const secp256k1_gej_t *a) { - if (a->infinity) +static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { + secp256k1_fe y2, x3, z2, z6; + if (a->infinity) { return 0; + } /** y^2 = x^3 + 7 * (Y/Z^3)^2 = (X/Z^2)^3 + 7 * Y^2 / Z^6 = X^3 / Z^6 + 7 * Y^2 = X^3 + 7*Z^6 */ - secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); - secp256k1_fe_mul_int(&z6, 7); + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); + secp256k1_fe_mul_int(&z6, CURVE_B); secp256k1_fe_add(&x3, &z6); - secp256k1_fe_normalize(&y2); - secp256k1_fe_normalize(&x3); - return secp256k1_fe_equal(&y2, &x3); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); } -static int secp256k1_ge_is_valid(const secp256k1_ge_t *a) { - if (a->infinity) +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { + secp256k1_fe y2, x3, c; + if (a->infinity) { return 0; + } /* y^2 = x^3 + 7 */ - secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7); + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&x3, &c); - secp256k1_fe_normalize(&y2); - secp256k1_fe_normalize(&x3); - return secp256k1_fe_equal(&y2, &x3); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); } -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { - // For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, - // Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have - // y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. + * + * Note that there is an implementation described at + * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + * which trades a multiply for a square, but in practice this is actually slower, + * mainly because it requires more normalizations. + */ + secp256k1_fe t1,t2,t3,t4; + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, + * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have + * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). + */ r->infinity = a->infinity; if (r->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } return; } - secp256k1_fe_t t1,t2,t3,t4; + if (rzr != NULL) { + *rzr = a->y; + secp256k1_fe_normalize_weak(rzr); + secp256k1_fe_mul_int(rzr, 2); + } + secp256k1_fe_mul(&r->z, &a->z, &a->y); secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ secp256k1_fe_sqr(&t1, &a->x); @@ -239,91 +359,176 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ } -static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) { +static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); + secp256k1_gej_double_var(r, a, rzr); +} + +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { + /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ + secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); *r = *b; return; } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } *r = *a; return; } + r->infinity = 0; - secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &b->z); - secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z); - secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &a->x, &z22); - secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12); - secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); - secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_normalize(&u1); - secp256k1_fe_normalize(&u2); - if (secp256k1_fe_equal(&u1, &u2)) { - secp256k1_fe_normalize(&s1); - secp256k1_fe_normalize(&s2); - if (secp256k1_fe_equal(&s1, &s2)) { - secp256k1_gej_double_var(r, a); + secp256k1_fe_sqr(&z22, &b->z); + secp256k1_fe_sqr(&z12, &a->z); + secp256k1_fe_mul(&u1, &a->x, &z22); + secp256k1_fe_mul(&u2, &b->x, &z12); + secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, rzr); } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } r->infinity = 1; } return; } - secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); - secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); - secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h); - secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2); + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + secp256k1_fe_mul(&h, &h, &b->z); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); secp256k1_fe_add(&r->y, &h3); } -static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { + /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; if (a->infinity) { - r->infinity = b->infinity; - r->x = b->x; - r->y = b->y; - secp256k1_fe_set_int(&r->z, 1); + VERIFY_CHECK(rzr == NULL); + secp256k1_gej_set_ge(r, b); return; } if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } *r = *a; return; } r->infinity = 0; - secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z); - secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1); - secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12); - secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1); - secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_normalize(&u1); - secp256k1_fe_normalize(&u2); - if (secp256k1_fe_equal(&u1, &u2)) { - secp256k1_fe_normalize(&s1); - secp256k1_fe_normalize(&s2); - if (secp256k1_fe_equal(&s1, &s2)) { - secp256k1_gej_double_var(r, a); + + secp256k1_fe_sqr(&z12, &a->z); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, rzr); } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } r->infinity = 1; } return; } - secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); - secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { + /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (b->infinity) { + *r = *a; + return; + } + if (a->infinity) { + secp256k1_fe bzinv2, bzinv3; + r->infinity = b->infinity; + secp256k1_fe_sqr(&bzinv2, bzinv); + secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); + secp256k1_fe_mul(&r->x, &b->x, &bzinv2); + secp256k1_fe_mul(&r->y, &b->y, &bzinv3); + secp256k1_fe_set_int(&r->z, 1); + return; + } + r->infinity = 0; + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + secp256k1_fe_mul(&az, &a->z, bzinv); + + secp256k1_fe_sqr(&z12, &az); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, NULL); + } else { + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h); - secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2); + secp256k1_fe_mul(&t, &u1, &h2); r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); secp256k1_fe_add(&r->y, &h3); } -static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { + +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { + /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ + static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_fe m_alt, rr_alt; + int infinity, degenerate; VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); @@ -347,111 +552,155 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c * Y3 = 4*(R*(3*Q-2*R^2)-M^4) * Z3 = 2*M*Z * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. */ - secp256k1_fe_t zz; secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1); /* u1 = U1 = X1*Z2^2 (1) */ - secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ - secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */ - secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - secp256k1_fe_t z = a->z; /* z = Z = Z1*Z2 (8) */ - secp256k1_fe_t t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ - secp256k1_fe_t m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ - secp256k1_fe_t n; secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */ - secp256k1_fe_t q; secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */ - secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */ - secp256k1_fe_t rr; secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */ - secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */ - secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */ - secp256k1_fe_normalize(&r->z); - int infinity = secp256k1_fe_is_zero(&r->z) * (1 - a->infinity); - secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */ - r->x = t; /* r->x = R^2 (1) */ + secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ + u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ + s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ + secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ + m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ + secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m) & + secp256k1_fe_normalizes_to_zero(&rr); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ + + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); + secp256k1_fe_cmov(&m_alt, &m, !degenerate); + /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_fe_sqr(&n, &n); + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ + infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ - secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */ - secp256k1_fe_normalize(&r->x); - secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */ - secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */ - secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */ - secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */ - secp256k1_fe_normalize(&r->y); - secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */ - secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */ - - /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0. - * Add b->x to x, b->y to y, and 1 to z in that case. - */ - t = b->x; secp256k1_fe_mul_int(&t, a->infinity); - secp256k1_fe_add(&r->x, &t); - t = b->y; secp256k1_fe_mul_int(&t, a->infinity); - secp256k1_fe_add(&r->y, &t); - secp256k1_fe_set_int(&t, a->infinity); - secp256k1_fe_add(&r->z, &t); + secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ + secp256k1_fe_normalize_weak(&t); + r->x = t; /* r->x = Ralt^2-Q (1) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ + secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ + secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ + secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ + + /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + secp256k1_fe_cmov(&r->x, &b->x, a->infinity); + secp256k1_fe_cmov(&r->y, &b->y, a->infinity); + secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); r->infinity = infinity; } +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { + /* Operations: 4 mul, 1 sqr */ + secp256k1_fe zz; + VERIFY_CHECK(!secp256k1_fe_is_zero(s)); + secp256k1_fe_sqr(&zz, s); + secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + secp256k1_fe_mul(&r->y, &r->y, &zz); + secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ +} + +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { + secp256k1_fe x, y; + VERIFY_CHECK(!a->infinity); + x = a->x; + secp256k1_fe_normalize(&x); + y = a->y; + secp256k1_fe_normalize(&y); + secp256k1_fe_to_storage(&r->x, &x); + secp256k1_fe_to_storage(&r->y, &y); +} +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { + secp256k1_fe_from_storage(&r->x, &a->x); + secp256k1_fe_from_storage(&r->y, &a->y); + r->infinity = 0; +} -static void secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a) { - secp256k1_gej_t c = *a; - secp256k1_ge_t t; secp256k1_ge_set_gej(&t, &c); - secp256k1_ge_get_hex(r, rlen, &t); +static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { + secp256k1_fe_storage_cmov(&r->x, &a->x, flag); + secp256k1_fe_storage_cmov(&r->y, &a->y, flag); } #ifdef USE_ENDOMORPHISM -static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) { - const secp256k1_fe_t *beta = &secp256k1_ge_consts->beta; +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { + static const secp256k1_fe beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul + ); *r = *a; - secp256k1_fe_mul(&r->x, &r->x, beta); + secp256k1_fe_mul(&r->x, &r->x, &beta); } #endif -static void secp256k1_ge_start(void) { - static const unsigned char secp256k1_ge_consts_g_x[] = { - 0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC, - 0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07, - 0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9, - 0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98 - }; - static const unsigned char secp256k1_ge_consts_g_y[] = { - 0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65, - 0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8, - 0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19, - 0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8 - }; -#ifdef USE_ENDOMORPHISM - /* properties of secp256k1's efficiently computable endomorphism */ - static const unsigned char secp256k1_ge_consts_beta[] = { - 0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10, - 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9, - 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95, - 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee - }; -#endif - if (secp256k1_ge_consts == NULL) { - secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t)); -#ifdef USE_ENDOMORPHISM - VERIFY_CHECK(secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta)); -#endif - secp256k1_fe_t g_x, g_y; - VERIFY_CHECK(secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x)); - VERIFY_CHECK(secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y)); - secp256k1_ge_set_xy(&ret->g, &g_x, &g_y); - secp256k1_ge_consts = ret; - } -} +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { + secp256k1_fe yz; -static void secp256k1_ge_stop(void) { - if (secp256k1_ge_consts != NULL) { - secp256k1_ge_consts_t *c = (secp256k1_ge_consts_t*)secp256k1_ge_consts; - free((void*)c); - secp256k1_ge_consts = NULL; + if (a->infinity) { + return 0; } + + /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as + * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z + is */ + secp256k1_fe_mul(&yz, &a->y, &a->z); + return secp256k1_fe_is_quad_var(&yz); } -#endif +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h new file mode 100644 index 000000000000..de26e4b89f8c --- /dev/null +++ b/src/secp256k1/src/hash.h @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (c) 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_HASH_H +#define SECP256K1_HASH_H + +#include +#include + +typedef struct { + uint32_t s[8]; + uint32_t buf[16]; /* In big endian */ + size_t bytes; +} secp256k1_sha256; + +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); + +typedef struct { + secp256k1_sha256 inner, outer; +} secp256k1_hmac_sha256; + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + int retry; +} secp256k1_rfc6979_hmac_sha256; + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); + +#endif /* SECP256K1_HASH_H */ diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h new file mode 100644 index 000000000000..009f26beba93 --- /dev/null +++ b/src/secp256k1/src/hash_impl.h @@ -0,0 +1,282 @@ +/********************************************************************** + * Copyright (c) 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_HASH_IMPL_H +#define SECP256K1_HASH_IMPL_H + +#include "hash.h" + +#include +#include +#include + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +#ifdef WORDS_BIGENDIAN +#define BE32(x) (x) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#endif + +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { + hash->s[0] = 0x6a09e667ul; + hash->s[1] = 0xbb67ae85ul; + hash->s[2] = 0x3c6ef372ul; + hash->s[3] = 0xa54ff53aul; + hash->s[4] = 0x510e527ful; + hash->s[5] = 0x9b05688cul; + hash->s[6] = 0x1f83d9abul; + hash->s[7] = 0x5be0cd19ul; + hash->bytes = 0; +} + +/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ +static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15])); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { + size_t bufsize = hash->bytes & 0x3F; + hash->bytes += len; + while (bufsize + len >= 64) { + /* Fill the buffer, and process it. */ + size_t chunk_len = 64 - bufsize; + memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len); + data += chunk_len; + len -= chunk_len; + secp256k1_sha256_transform(hash->s, hash->buf); + bufsize = 0; + } + if (len) { + /* Fill the buffer with what remains. */ + memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + } +} + +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { + static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t sizedesc[2]; + uint32_t out[8]; + int i = 0; + sizedesc[0] = BE32(hash->bytes >> 29); + sizedesc[1] = BE32(hash->bytes << 3); + secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8); + for (i = 0; i < 8; i++) { + out[i] = BE32(hash->s[i]); + hash->s[i] = 0; + } + memcpy(out32, (const unsigned char*)out, 32); +} + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { + size_t n; + unsigned char rkey[64]; + if (keylen <= sizeof(rkey)) { + memcpy(rkey, key, keylen); + memset(rkey + keylen, 0, sizeof(rkey) - keylen); + } else { + secp256k1_sha256 sha256; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, key, keylen); + secp256k1_sha256_finalize(&sha256, rkey); + memset(rkey + 32, 0, 32); + } + + secp256k1_sha256_initialize(&hash->outer); + for (n = 0; n < sizeof(rkey); n++) { + rkey[n] ^= 0x5c; + } + secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey)); + + secp256k1_sha256_initialize(&hash->inner); + for (n = 0; n < sizeof(rkey); n++) { + rkey[n] ^= 0x5c ^ 0x36; + } + secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey)); + memset(rkey, 0, sizeof(rkey)); +} + +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(&hash->inner, data, size); +} + +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { + unsigned char temp[32]; + secp256k1_sha256_finalize(&hash->inner, temp); + secp256k1_sha256_write(&hash->outer, temp, 32); + memset(temp, 0, 32); + secp256k1_sha256_finalize(&hash->outer, out32); +} + + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + secp256k1_hmac_sha256 hmac; + static const unsigned char zero[1] = {0x00}; + static const unsigned char one[1] = {0x01}; + + memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ + memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ + + /* RFC6979 3.2.d. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + + /* RFC6979 3.2.f. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, one, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + rng->retry = 0; +} + +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + secp256k1_hmac_sha256 hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + } + + while (outlen > 0) { + secp256k1_hmac_sha256 hmac; + int now = outlen; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + if (now > 32) { + now = 32; + } + memcpy(out, rng->v, now); + out += now; + outlen -= now; + } + + rng->retry = 1; +} + +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) { + memset(rng->k, 0, 32); + memset(rng->v, 0, 32); + rng->retry = 0; +} + +#undef BE32 +#undef Round +#undef sigma1 +#undef sigma0 +#undef Sigma1 +#undef Sigma0 +#undef Maj +#undef Ch + +#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java index 90a498eaa2c4..1c67802fba82 100644 --- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -1,60 +1,446 @@ +/* + * Copyright 2013 Google Inc. + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.bitcoin; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.math.BigInteger; import com.google.common.base.Preconditions; - +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import static org.bitcoin.NativeSecp256k1Util.*; /** - * This class holds native methods to handle ECDSA verification. - * You can find an example library that can be used for this at - * https://github.com/sipa/secp256k1 + *

    This class holds native methods to handle ECDSA verification.

    + * + *

    You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

    + * + *

    To build secp256k1 for use with bitcoinj, run + * `./configure --enable-jni --enable-experimental --enable-module-ecdh` + * and `make` then copy `.libs/libsecp256k1.so` to your system library path + * or point the JVM to the folder containing it with -Djava.library.path + *

    */ public class NativeSecp256k1 { - public static final boolean enabled; - static { - boolean isEnabled = true; - try { - System.loadLibrary("javasecp256k1"); - } catch (UnsatisfiedLinkError e) { - isEnabled = false; - } - enabled = isEnabled; - } - + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); /** * Verifies the given secp256k1 signature in native code. * Calling when enabled == false is undefined (probably library not loaded) - * + * * @param data The data which was signed, must be exactly 32 bytes * @param signature The signature * @param pub The public key which did the signing */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); byteBuff.order(ByteOrder.nativeOrder()); nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); byteBuff.put(data); - byteBuff.putInt(signature.length); - byteBuff.putInt(pub.length); byteBuff.put(signature); byteBuff.put(pub); - return secp256k1_ecdsa_verify(byteBuff) == 1; + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } + } + + /** + * libsecp256k1 Create an ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature + */ + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 32) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(sigArr.length, sigLen, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + /** + * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid + * + * @param seckey ECDSA Secret key, 32 bytes + */ + public static boolean secKeyVerify(byte[] seckey) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + r.lock(); + try { + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } + } + + + /** + * libsecp256k1 Compute Pubkey - computes public key from secret key + * + * @param seckey ECDSA Secret key, 32 bytes + * + * Return values + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + //TODO add a 'compressed' arg + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + return retVal == 0 ? new byte[0]: pubArr; + } + + /** + * libsecp256k1 Cleanup - This destroys the secp256k1 context object + * This should be called at the end of the program for proper cleanup of the context. + */ + public static synchronized void cleanup() { + w.lock(); + try { + secp256k1_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } + } + + public static long cloneContext() { + r.lock(); + try { + return secp256k1_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } + } + + /** + * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; } /** - * @param byteBuff signature format is byte[32] data, - * native-endian int signatureLength, native-endian int pubkeyLength, - * byte[signatureLength] signature, byte[pubkeyLength] pub - * @returns 1 for valid signature, anything else for invalid + * libsecp256k1 create ECDH secret - constant time ECDH calculation + * + * @param seckey byte array of secret key used in exponentiaion + * @param pubkey byte array of public key used in exponentiaion */ - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); + public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { + byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.put(pubkey); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] resArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(resArr.length, 32, "Got bad result length."); + assertEquals(retVal, 1, "Failed return value check."); + + return resArr; + } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed 32-byte random seed + */ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seed.length) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + w.lock(); + try { + return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } + } + + private static native long secp256k1_ctx_clone(long context); + + private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); + + private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); + + private static native void secp256k1_destroy_context(long context); + + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); + + private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); + + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); + } diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 000000000000..d766a1029ce3 --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,226 @@ +package org.bitcoin; + +import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import java.math.BigInteger; +import javax.xml.bind.DatatypeConverter; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + * This class holds test cases defined for testing this library. + */ +public class NativeSecp256k1Test { + + //TODO improve comments/add more tests + /** + * This tests verify() for a valid signature + */ + public static void testVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + assertEquals( result, true , "testVerifyPos"); + } + + /** + * This tests verify() for a non-valid signature + */ + public static void testVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } + + /** + * This tests secret key verify() for a valid secretkey + */ + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + /** + * This tests secret key verify() for an invalid secretkey + */ + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyNeg"); + } + + /** + * This tests public key create() for a valid secretkey + */ + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); + } + + /** + * This tests public key create() for a invalid secretkey + */ + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); + } + + /** + * This tests sign() for a valid secretkey + */ + public static void testSignPos() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); + } + + /** + * This tests sign() for a invalid secretkey + */ + public static void testSignNeg() throws AssertFailException{ + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "" , "testSignNeg"); + } + + /** + * This tests private key tweak-add + */ + public static void testPrivKeyTweakAdd_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); + } + + /** + * This tests private key tweak-mul + */ + public static void testPrivKeyTweakMul_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); + } + + /** + * This tests private key tweak-add uncompressed + */ + public static void testPrivKeyTweakAdd_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); + } + + /** + * This tests private key tweak-mul uncompressed + */ + public static void testPrivKeyTweakMul_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); + } + + /** + * This tests seed randomization + */ + public static void testRandomize() throws AssertFailException { + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + boolean result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "testRandomize"); + } + + public static void testCreateECDHSecret() throws AssertFailException{ + + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); + String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); + } + + public static void main(String[] args) throws AssertFailException{ + + + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); + + assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + testPubKeyCreatePos(); + testPubKeyCreateNeg(); + + //Test sign() success/fail + testSignPos(); + testSignNeg(); + + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); + + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); + + //Test privKeyTweakAdd() 3 + testPrivKeyTweakAdd_2(); + + //Test privKeyTweakMul() 4 + testPrivKeyTweakMul_2(); + + //Test randomize() + testRandomize(); + + //Test ECDH + testCreateECDHSecret(); + + NativeSecp256k1.cleanup(); + + System.out.println(" All tests passed." ); + + } +} diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 000000000000..04732ba04436 --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +public class NativeSecp256k1Util{ + + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + + public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ + if( !val.equals(val2) ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); + } + } +} diff --git a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 000000000000..216c986a8b56 --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +/** + * This class holds the context reference used in native methods + * to handle ECDSA operations. + */ +public class Secp256k1Context { + private static final boolean enabled; //true if the library is loaded + private static final long context; //ref to pointer to context obj + + static { //static initializer + boolean isEnabled = true; + long contextRef = -1; + try { + System.loadLibrary("secp256k1"); + contextRef = secp256k1_init_context(); + } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); + isEnabled = false; + } + enabled = isEnabled; + context = contextRef; + } + + public static boolean isEnabled() { + return enabled; + } + + public static long getContext() { + if(!enabled) return -1; //sanity check + return context; + } + + private static native long secp256k1_init_context(); +} diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c index bb4cd707280a..b50970b4f24c 100644 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,23 +1,379 @@ +#include +#include +#include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); + + (void)classObject;(void)env; + + return ctx_clone_l; + +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int sigLen = *((int*)(data + 32)); - int pubLen = *((int*)(data + 32 + 4)); + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_context_randomize(ctx, seed); - return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); } -static void __javasecp256k1_attach(void) __attribute__((constructor)); -static void __javasecp256k1_detach(void) __attribute__((destructor)); +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + secp256k1_context_destroy(ctx); -static void __javasecp256k1_attach(void) { - secp256k1_start(SECP256K1_START_VERIFY); + (void)classObject;(void)env; } -static void __javasecp256k1_detach(void) { - secp256k1_stop(); +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; + + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); + + if( ret ) { + ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); + } + } + + (void)classObject; + + return ret; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; + + secp256k1_ecdsa_signature sig[72]; + + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL); + + unsigned char outputSer[72]; + size_t outputLen = 72; + + if( ret ) { + int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_ec_seckey_verify(ctx, secKey); +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + secp256k1_pubkey pubkey; + + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); + + unsigned char outputSer[65]; + size_t outputLen = 65; + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; + +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; +/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if( ret ) { + ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if ( ret ) { + ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) +{ + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; + + return 0; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* pubdata = (const unsigned char*) (secdata + 32); + + jobjectArray retArray; + jbyteArray outArray, intsByteArray; + unsigned char intsarray[1]; + secp256k1_pubkey pubkey; + unsigned char nonce_res[32]; + size_t outputLen = 32; + + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if (ret) { + ret = secp256k1_ecdh( + ctx, + nonce_res, + &pubkey, + secdata, + NULL, + NULL + ); + } + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + outArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); + (*env)->SetObjectArrayElement(env, retArray, 0, outArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; } diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h index d7fb004fa841..fe613c9e9e77 100644 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -1,5 +1,6 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include +#include "include/secp256k1.h" /* Header for class org_bitcoin_NativeSecp256k1 */ #ifndef _Included_org_bitcoin_NativeSecp256k1 @@ -7,13 +8,110 @@ #ifdef __cplusplus extern "C" { #endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ctx_clone + * Signature: (J)J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_destroy_context + * Signature: (J)V + */ +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv *, jclass, jlong); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Signature: (Ljava/nio/ByteBuffer;JII)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv *, jclass, jobject, jlong, jint, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdh + * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject); +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); + #ifdef __cplusplus } diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 000000000000..a52939e7e7da --- /dev/null +++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,15 @@ +#include +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (uintptr_t)ctx; +} + diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 000000000000..0d2bc84b7f3f --- /dev/null +++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_Secp256k1Context */ + +#ifndef _Included_org_bitcoin_Secp256k1Context +#define _Included_org_bitcoin_Secp256k1Context +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_Secp256k1Context + * Method: secp256k1_init_context + * Signature: ()J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include new file mode 100644 index 000000000000..e3088b469790 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ecdh +bench_ecdh_SOURCES = src/bench_ecdh.c +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 000000000000..44cb68e75025 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,67 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H + +#include "include/secp256k1_ecdh.h" +#include "ecmult_const_impl.h" + +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + unsigned char version = (y[31] & 0x01) | 0x02; + secp256k1_sha256 sha; + (void)data; + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &version, 1); + secp256k1_sha256_write(&sha, x, 32); + secp256k1_sha256_finalize(&sha, output); + + return 1; +} + +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow = 0; + secp256k1_gej res; + secp256k1_ge pt; + secp256k1_scalar s; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + if (hashfp == NULL) { + hashfp = secp256k1_ecdh_hash_function_default; + } + + secp256k1_pubkey_load(ctx, &pt, point); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + unsigned char x[32]; + unsigned char y[32]; + + secp256k1_ecmult_const(&res, &pt, &s, 256); + secp256k1_ge_set_gej(&pt, &res); + + /* Compute a hash of the point */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + secp256k1_fe_get_b32(y, &pt.y); + + ret = hashfp(output, x, y, data); + } + + secp256k1_scalar_clear(&s); + return ret; +} + +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 000000000000..fe26e8fb6957 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,132 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H + +int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)output; + (void)x; + (void)y; + (void)data; + return 0; +} + +int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)data; + /* Save x and y as uncompressed public key */ + output[0] = 0x04; + memcpy(output + 1, x, 32); + memcpy(output + 33, y, 32); + return 1; +} + +void test_ecdh_api(void) { + /* Setup context that just counts errors */ + secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_pubkey point; + unsigned char res[32]; + unsigned char s_one[32] = { 0 }; + int32_t ecount = 0; + s_one[31] = 1; + + secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); + + /* Check all NULLs are detected */ + CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); + CHECK(ecount == 3); + + /* Cleanup */ + secp256k1_context_destroy(tctx); +} + +void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 100; ++i) { + secp256k1_sha256 sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[65]; + unsigned char output_ser[32]; + unsigned char point_ser[65]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_scalar s; + + random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + + /* compute using ECDH function with custom hash function */ + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + /* compare */ + CHECK(memcmp(output_ecdh, point_ser, 65) == 0); + + /* compute using ECDH function with default hash function */ + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(memcmp(output_ecdh, output_ser, 32) == 0); + } +} + +void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_scalar rand; + secp256k1_pubkey point; + + /* Create random point */ + random_scalar_order(&rand); + secp256k1_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1); + + /* Hash function failure results in ecdh failure */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); +} + +void run_ecdh_tests(void) { + test_ecdh_api(); + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include new file mode 100644 index 000000000000..bf23c26e71c5 --- /dev/null +++ b/src/secp256k1/src/modules/recovery/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_recovery.h +noinst_HEADERS += src/modules/recovery/main_impl.h +noinst_HEADERS += src/modules/recovery/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_recover +bench_recover_SOURCES = src/bench_recover.c +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h new file mode 100755 index 000000000000..2f6691c5a130 --- /dev/null +++ b/src/secp256k1/src/modules/recovery/main_impl.h @@ -0,0 +1,193 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H + +#include "include/secp256k1_recovery.h" + +static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { + secp256k1_scalar r, s; + int recid; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { + unsigned char brx[32]; + secp256k1_fe fx; + secp256k1_ge x; + secp256k1_gej xj; + secp256k1_scalar rn, u1, u2; + secp256k1_gej qj; + int r; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, sigr); + r = secp256k1_fe_set_b32(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, sigr); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, sigs); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + +int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; + int recid; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; + unsigned int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { + break; + } + } + count++; + } + memset(nonce32, 0, 32); + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ + secp256k1_scalar_set_b32(&m, msg32, NULL); + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h new file mode 100644 index 000000000000..5c9bbe86101c --- /dev/null +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,393 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H + +static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + + /* On the first run, return 0 to force a second run */ + if (counter == 0) { + memset(nonce32, 0, 32); + return 1; + } + /* On the second run, return an overflow to force a third run */ + if (counter == 1) { + memset(nonce32, 0xff, 32); + return 1; + } + /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ + memset(nonce32, 1, 32); + return secp256k1_rand_bits(1); +} + +void test_ecdsa_recovery_api(void) { + /* Setup contexts that just count errors */ + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + secp256k1_ecdsa_signature normal_sig; + secp256k1_ecdsa_recoverable_signature recsig; + unsigned char privkey[32] = { 1 }; + unsigned char message[32] = { 2 }; + int32_t ecount = 0; + int recid = 0; + unsigned char sig[74]; + unsigned char zero_privkey[32] = { 0 }; + unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Check bad contexts and NULLs for signing */ + ecount = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ + secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); + CHECK(ecount == 5); + /* These will all fail, but not in ARG_CHECK way */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); + /* This one will succeed. */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 5); + + /* Check signing with a goofy nonce function */ + + /* Check bad contexts and NULLs for recovery */ + ecount = 0; + CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); + CHECK(ecount == 5); + + /* Check NULLs for conversion */ + CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); + + /* Check NULLs for de/serialization */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); + CHECK(ecount == 7); + /* overflow in signature will fail but not affect ecount */ + memcpy(sig, over_privkey, 32); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); + CHECK(ecount == 7); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + +void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(memcmp(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 0. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + secp256k1_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + secp256k1_pubkey pubkeyb; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + int recid; + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + secp256k1_pubkey pubkey2b; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + secp256k1_pubkey pubkeyc; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + } +} + +void run_recovery_tests(void) { + int i; + for (i = 0; i < count; i++) { + test_ecdsa_recovery_api(); + } + for (i = 0; i < 64*count; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h index 339b6bb6ec2c..49f2dd791d56 100644 --- a/src/secp256k1/src/num.h +++ b/src/secp256k1/src/num.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_ -#define _SECP256K1_NUM_ +#ifndef SECP256K1_NUM_H +#define SECP256K1_NUM_H #ifndef USE_NUM_NONE @@ -20,49 +20,55 @@ #endif /** Copy a number. */ -static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a); +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a); /** Convert a number's absolute value to a binary big-endian string. * There must be enough place. */ -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a); +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a); /** Set a number to the value of a binary big-endian string. */ -static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen); +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen); /** Compute a modular inverse. The input must be less than the modulus. */ -static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m); +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); + +/** Compute the jacobi symbol (a|b). b must be positive and odd. */ +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b); /** Compare the absolute value of two numbers. */ -static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b); +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); /** Test whether two number are equal (including sign). */ -static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b); +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); /** Add two (signed) numbers. */ -static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Subtract two (signed) numbers. */ -static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Multiply two (signed) numbers. */ -static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, even if r was negative. */ -static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m); +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); /** Right-shift the passed number by bits bits. */ -static void secp256k1_num_shift(secp256k1_num_t *r, int bits); +static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ -static int secp256k1_num_is_zero(const secp256k1_num_t *a); +static int secp256k1_num_is_zero(const secp256k1_num *a); + +/** Check whether a number is one. */ +static int secp256k1_num_is_one(const secp256k1_num *a); /** Check whether a number is strictly negative. */ -static int secp256k1_num_is_neg(const secp256k1_num_t *a); +static int secp256k1_num_is_neg(const secp256k1_num *a); /** Change a number's sign. */ -static void secp256k1_num_negate(secp256k1_num_t *r); +static void secp256k1_num_negate(secp256k1_num *r); #endif -#endif +#endif /* SECP256K1_NUM_H */ diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h index baa1f2bf2e4d..3619844bd512 100644 --- a/src/secp256k1/src/num_gmp.h +++ b/src/secp256k1/src/num_gmp.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_REPR_ -#define _SECP256K1_NUM_REPR_ +#ifndef SECP256K1_NUM_REPR_H +#define SECP256K1_NUM_REPR_H #include @@ -15,6 +15,6 @@ typedef struct { mp_limb_t data[2*NUM_LIMBS]; int neg; int limbs; -} secp256k1_num_t; +} secp256k1_num; -#endif +#endif /* SECP256K1_NUM_REPR_H */ diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h index 19d474e59fff..0ae2a8ba0ecb 100644 --- a/src/secp256k1/src/num_gmp_impl.h +++ b/src/secp256k1/src/num_gmp_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_REPR_IMPL_H_ -#define _SECP256K1_NUM_REPR_IMPL_H_ +#ifndef SECP256K1_NUM_REPR_IMPL_H +#define SECP256K1_NUM_REPR_IMPL_H #include #include @@ -15,24 +15,24 @@ #include "num.h" #ifdef VERIFY -static void secp256k1_num_sanity(const secp256k1_num_t *a) { +static void secp256k1_num_sanity(const secp256k1_num *a) { VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); } #else #define secp256k1_num_sanity(a) do { } while(0) #endif -static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) { *r = *a; } -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) { unsigned char tmp[65]; int len = 0; + int shift = 0; if (a->limbs>1 || a->data[0] != 0) { len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs); } - int shift = 0; while (shift < len && tmp[shift] == 0) shift++; VERIFY_CHECK(len-shift <= (int)rlen); memset(r, 0, rlen - len + shift); @@ -42,10 +42,11 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) { +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) { + int len; VERIFY_CHECK(alen > 0); VERIFY_CHECK(alen <= 64); - int len = mpn_set_str(r->data, a, alen, 256); + len = mpn_set_str(r->data, a, alen, 256); if (len == 0) { r->data[0] = 0; len = 1; @@ -53,10 +54,12 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un VERIFY_CHECK(len <= NUM_LIMBS*2); r->limbs = len; r->neg = 0; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } -static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); r->limbs = a->limbs; if (c != 0) { @@ -65,14 +68,17 @@ static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, } } -static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + (void)c; VERIFY_CHECK(c == 0); r->limbs = a->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } -static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) { secp256k1_num_sanity(r); secp256k1_num_sanity(m); @@ -81,7 +87,9 @@ static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); memset(t, 0, sizeof(t)); r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { @@ -90,7 +98,13 @@ static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { } } -static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) { +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) { + int i; + mp_limb_t g[NUM_LIMBS+1]; + mp_limb_t u[NUM_LIMBS+1]; + mp_limb_t v[NUM_LIMBS+1]; + mp_size_t sn; + mp_size_t gn; secp256k1_num_sanity(a); secp256k1_num_sanity(m); @@ -106,22 +120,22 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t */ VERIFY_CHECK(m->limbs <= NUM_LIMBS); VERIFY_CHECK(m->data[m->limbs-1] != 0); - mp_limb_t g[NUM_LIMBS+1]; - mp_limb_t u[NUM_LIMBS+1]; - mp_limb_t v[NUM_LIMBS+1]; - for (int i=0; i < m->limbs; i++) { + for (i = 0; i < m->limbs; i++) { u[i] = (i < a->limbs) ? a->data[i] : 0; v[i] = m->data[i]; } - mp_size_t sn = NUM_LIMBS+1; - mp_size_t gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + sn = NUM_LIMBS+1; + gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + (void)gn; VERIFY_CHECK(gn == 1); VERIFY_CHECK(g[0] == 1); r->neg = a->neg ^ m->neg; if (sn < 0) { mpn_sub(r->data, m->data, m->limbs, r->data, -sn); r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } else { r->limbs = sn; } @@ -130,28 +144,64 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t memset(v, 0, sizeof(v)); } -static int secp256k1_num_is_zero(const secp256k1_num_t *a) { +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) { + int ret; + mpz_t ga, gb; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); + + mpz_inits(ga, gb, NULL); + + mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); + mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); + if (a->neg) { + mpz_neg(ga, ga); + } + + ret = mpz_jacobi(ga, gb); + + mpz_clears(ga, gb, NULL); + + return ret; +} + +static int secp256k1_num_is_one(const secp256k1_num *a) { + return (a->limbs == 1 && a->data[0] == 1); +} + +static int secp256k1_num_is_zero(const secp256k1_num *a) { return (a->limbs == 1 && a->data[0] == 0); } -static int secp256k1_num_is_neg(const secp256k1_num_t *a) { +static int secp256k1_num_is_neg(const secp256k1_num *a) { return (a->limbs > 1 || a->data[0] != 0) && a->neg; } -static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { - if (a->limbs > b->limbs) return 1; - if (a->limbs < b->limbs) return -1; +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { + if (a->limbs > b->limbs) { + return 1; + } + if (a->limbs < b->limbs) { + return -1; + } return mpn_cmp(a->data, b->data, a->limbs); } -static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) { - if (a->limbs > b->limbs) return 0; - if (a->limbs < b->limbs) return 0; - if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) return 0; +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) { + if (a->limbs > b->limbs) { + return 0; + } + if (a->limbs < b->limbs) { + return 0; + } + if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) { + return 0; + } return mpn_cmp(a->data, b->data, a->limbs) == 0; } -static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) { +static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) { if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ r->neg = a->neg; if (a->limbs >= b->limbs) { @@ -170,23 +220,23 @@ static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, c } } -static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { secp256k1_num_sanity(a); secp256k1_num_sanity(b); secp256k1_num_subadd(r, a, b, 0); } -static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { secp256k1_num_sanity(a); secp256k1_num_sanity(b); secp256k1_num_subadd(r, a, b, 1); } -static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { + mp_limb_t tmp[2*NUM_LIMBS+1]; secp256k1_num_sanity(a); secp256k1_num_sanity(b); - mp_limb_t tmp[2*NUM_LIMBS+1]; VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1); if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) { r->limbs = 1; @@ -194,26 +244,30 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons r->data[0] = 0; return; } - if (a->limbs >= b->limbs) + if (a->limbs >= b->limbs) { mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); - else + } else { mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); + } r->limbs = a->limbs + b->limbs; - if (r->limbs > 1 && tmp[r->limbs - 1]==0) r->limbs--; + if (r->limbs > 1 && tmp[r->limbs - 1]==0) { + r->limbs--; + } VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); mpn_copyi(r->data, tmp, r->limbs); r->neg = a->neg ^ b->neg; memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { +static void secp256k1_num_shift(secp256k1_num *r, int bits) { if (bits % GMP_NUMB_BITS) { - // Shift within limbs. + /* Shift within limbs. */ mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); } if (bits >= GMP_NUMB_BITS) { - // Shift full limbs. - for (int i = 0; i < r->limbs; i++) { + int i; + /* Shift full limbs. */ + for (i = 0; i < r->limbs; i++) { int index = i + (bits / GMP_NUMB_BITS); if (index < r->limbs && index < 2*NUM_LIMBS) { r->data[i] = r->data[index]; @@ -222,11 +276,13 @@ static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { } } } - while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs>1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } -static void secp256k1_num_negate(secp256k1_num_t *r) { +static void secp256k1_num_negate(secp256k1_num *r) { r->neg ^= 1; } -#endif +#endif /* SECP256K1_NUM_REPR_IMPL_H */ diff --git a/src/secp256k1/src/num_impl.h b/src/secp256k1/src/num_impl.h index 0b0e3a072a15..c45193b033da 100644 --- a/src/secp256k1/src/num_impl.h +++ b/src/secp256k1/src/num_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_IMPL_H_ -#define _SECP256K1_NUM_IMPL_H_ +#ifndef SECP256K1_NUM_IMPL_H +#define SECP256K1_NUM_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -21,4 +21,4 @@ #error "Please select num implementation" #endif -#endif +#endif /* SECP256K1_NUM_IMPL_H */ diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index 2f5ba0d447ad..59304cb66e90 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_ -#define _SECP256K1_SCALAR_ +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H #include "num.h" @@ -13,7 +13,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32.h" @@ -21,76 +23,84 @@ #error "Please select scalar implementation" #endif -static void secp256k1_scalar_start(void); -static void secp256k1_scalar_stop(void); - /** Clear a scalar to prevent the leak of sensitive data. */ -static void secp256k1_scalar_clear(secp256k1_scalar_t *r); +static void secp256k1_scalar_clear(secp256k1_scalar *r); /** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ -static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); +static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Access bits from a scalar. Not constant time. */ -static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); +static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Set a scalar from a big endian byte array. */ -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow); +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); /** Set a scalar to an unsigned integer. */ -static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v); +static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); /** Convert a scalar to a byte array. */ -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a); +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); /** Add two scalars together (modulo the group order). Returns whether it overflowed. */ -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); -/** Add a power of two to a scalar. The result is not allowed to overflow. */ -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit); +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); /** Multiply two scalars (modulo the group order). */ -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Shift a scalar right by some amount strictly between 0 and 16, returning + * the low bits that were shifted off */ +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); /** Compute the square of a scalar (modulo the group order). */ -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the inverse of a scalar (modulo the group order). */ -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ -static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the complement of a scalar (modulo the group order). */ -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); /** Check whether a scalar equals zero. */ -static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); /** Check whether a scalar equals one. */ -static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_one(const secp256k1_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_scalar_is_even(const secp256k1_scalar *a); /** Check whether a scalar is higher than the group order divided by 2. */ -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_high(const secp256k1_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); #ifndef USE_NUM_NONE /** Convert a scalar to a number. */ -static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a); /** Get the order of the group as a number. */ -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r); +static void secp256k1_scalar_order_get_num(secp256k1_num *r); #endif /** Compare two scalars. */ -static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); - -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); #ifdef USE_ENDOMORPHISM +/** Find r1 and r2 such that r1+r2*2^128 = a. */ +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); /** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); #endif /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ -static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift); +static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); -#endif +#endif /* SECP256K1_SCALAR_H */ diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h index 5a751c686223..19c7495d1c8e 100644 --- a/src/secp256k1/src/scalar_4x64.h +++ b/src/secp256k1/src/scalar_4x64.h @@ -4,14 +4,16 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint64_t d[4]; -} secp256k1_scalar_t; +} secp256k1_scalar; -#endif +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index d14477522029..db1ebf94bee0 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -4,10 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ - -typedef unsigned __int128 uint128_t; +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) @@ -26,26 +24,26 @@ typedef unsigned __int128 uint128_t; #define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) #define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { r->d[0] = 0; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); if ((offset + count - 1) >> 6 == offset >> 6) { @@ -56,7 +54,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256 } } -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ @@ -68,9 +66,10 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal return yes; } -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) { +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { + uint128_t t; VERIFY_CHECK(overflow <= 1); - uint128_t t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; + t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; @@ -81,7 +80,8 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig return overflow; } -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + int overflow; uint128_t t = (uint128_t)a->d[0] + b->d[0]; r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)a->d[1] + b->d[1]; @@ -90,15 +90,17 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)a->d[3] + b->d[3]; r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - int overflow = t + secp256k1_scalar_check_overflow(r); + overflow = t + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + uint128_t t; VERIFY_CHECK(bit < 256); - uint128_t t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; @@ -112,29 +114,30 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { #endif } -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int over; r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; - int over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); if (overflow) { *overflow = over; } } -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; } -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; } -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; r->d[0] = t & nonzero; t >>= 64; @@ -146,11 +149,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala r->d[3] = t & nonzero; } -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; } -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[3] < SECP256K1_N_H_3); @@ -162,6 +165,22 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint64_t mask = !flag - 1; + uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; + uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; + return 2 * (mask == 0) - 1; +} + /* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ /** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ @@ -195,16 +214,16 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { /** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ #define muladd2(a,b) { \ - uint64_t tl, th; \ + uint64_t tl, th, th2, tl2; \ { \ uint128_t t = (uint128_t)a * b; \ th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ tl = t; \ } \ - uint64_t th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ + th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - uint64_t tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ + tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ c0 += tl2; /* overflow is handled on the next line */ \ th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ @@ -217,8 +236,9 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ + unsigned int over; \ c0 += (a); /* overflow is handled on the next line */ \ - unsigned int over = (c0 < (a)) ? 1 : 0; \ + over = (c0 < (a)) ? 1 : 0; \ c1 += over; /* overflow is handled on the next line */ \ c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ } @@ -247,64 +267,302 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { VERIFY_CHECK(c2 == 0); \ } -static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) { - uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { +#ifdef USE_ASM_X86_64 + /* Reduce 512 bits into 385. */ + uint64_t m0, m1, m2, m3, m4, m5, m6; + uint64_t p0, p1, p2, p3, p4; + uint64_t c; + + __asm__ __volatile__( + /* Preload. */ + "movq 32(%%rsi), %%r11\n" + "movq 40(%%rsi), %%r12\n" + "movq 48(%%rsi), %%r13\n" + "movq 56(%%rsi), %%r14\n" + /* Initialize r8,r9,r10 */ + "movq 0(%%rsi), %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += n0 * c0 */ + "movq %8, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract m0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += l1 */ + "addq 8(%%rsi), %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += n1 * c0 */ + "movq %8, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n0 * c1 */ + "movq %9, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract m1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += l2 */ + "addq 16(%%rsi), %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n2 * c0 */ + "movq %8, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n1 * c1 */ + "movq %9, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n0 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract m2 */ + "movq %%r10, %q2\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += l3 */ + "addq 24(%%rsi), %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n3 * c0 */ + "movq %8, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n2 * c1 */ + "movq %9, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n1 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* extract m3 */ + "movq %%r8, %q3\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += n3 * c1 */ + "movq %9, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n2 */ + "addq %%r13, %%r9\n" + "adcq $0, %%r10\n" + "adcq $0, %%r8\n" + /* extract m4 */ + "movq %%r9, %q4\n" + /* (r10,r8) += n3 */ + "addq %%r14, %%r10\n" + "adcq $0, %%r8\n" + /* extract m5 */ + "movq %%r10, %q5\n" + /* extract m6 */ + "movq %%r8, %q6\n" + : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); - /* 160 bit accumulator. */ - uint64_t c0, c1; - uint32_t c2; + /* Reduce 385 bits into 258. */ + __asm__ __volatile__( + /* Preload */ + "movq %q9, %%r11\n" + "movq %q10, %%r12\n" + "movq %q11, %%r13\n" + /* Initialize (r8,r9,r10) */ + "movq %q5, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += m4 * c0 */ + "movq %12, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract p0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += m1 */ + "addq %q6, %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += m5 * c0 */ + "movq %12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += m4 * c1 */ + "movq %13, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract p1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += m2 */ + "addq %q7, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m6 * c0 */ + "movq %12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m5 * c1 */ + "movq %13, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m4 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract p2 */ + "movq %%r10, %q2\n" + /* (r8,r9) += m3 */ + "addq %q8, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += m6 * c1 */ + "movq %13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* (r8,r9) += m5 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + /* extract p3 */ + "movq %%r8, %q3\n" + /* (r9) += m6 */ + "addq %%r13, %%r9\n" + /* extract p4 */ + "movq %%r9, %q4\n" + : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + + /* Reduce 258 bits into 256. */ + __asm__ __volatile__( + /* Preload */ + "movq %q5, %%r10\n" + /* (rax,rdx) = p4 * c0 */ + "movq %7, %%rax\n" + "mulq %%r10\n" + /* (rax,rdx) += p0 */ + "addq %q1, %%rax\n" + "adcq $0, %%rdx\n" + /* extract r0 */ + "movq %%rax, 0(%q6)\n" + /* Move to (r8,r9) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p1 */ + "addq %q2, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += p4 * c1 */ + "movq %8, %%rax\n" + "mulq %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* Extract r1 */ + "movq %%r8, 8(%q6)\n" + "xorq %%r8, %%r8\n" + /* (r9,r8) += p4 */ + "addq %%r10, %%r9\n" + "adcq $0, %%r8\n" + /* (r9,r8) += p2 */ + "addq %q3, %%r9\n" + "adcq $0, %%r8\n" + /* Extract r2 */ + "movq %%r9, 16(%q6)\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p3 */ + "addq %q4, %%r8\n" + "adcq $0, %%r9\n" + /* Extract r3 */ + "movq %%r8, 24(%q6)\n" + /* Extract c */ + "movq %%r9, %q0\n" + : "=g"(c) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); +#else + uint128_t c; + uint64_t c0, c1, c2; + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + uint64_t m0, m1, m2, m3, m4, m5; + uint32_t m6; + uint64_t p0, p1, p2, p3; + uint32_t p4; /* Reduce 512 bits into 385. */ /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ c0 = l[0]; c1 = 0; c2 = 0; muladd_fast(n0, SECP256K1_N_C_0); - uint64_t m0; extract_fast(m0); + extract_fast(m0); sumadd_fast(l[1]); muladd(n1, SECP256K1_N_C_0); muladd(n0, SECP256K1_N_C_1); - uint64_t m1; extract(m1); + extract(m1); sumadd(l[2]); muladd(n2, SECP256K1_N_C_0); muladd(n1, SECP256K1_N_C_1); sumadd(n0); - uint64_t m2; extract(m2); + extract(m2); sumadd(l[3]); muladd(n3, SECP256K1_N_C_0); muladd(n2, SECP256K1_N_C_1); sumadd(n1); - uint64_t m3; extract(m3); + extract(m3); muladd(n3, SECP256K1_N_C_1); sumadd(n2); - uint64_t m4; extract(m4); + extract(m4); sumadd_fast(n3); - uint64_t m5; extract_fast(m5); + extract_fast(m5); VERIFY_CHECK(c0 <= 1); - uint32_t m6 = c0; + m6 = c0; /* Reduce 385 bits into 258. */ /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ c0 = m0; c1 = 0; c2 = 0; muladd_fast(m4, SECP256K1_N_C_0); - uint64_t p0; extract_fast(p0); + extract_fast(p0); sumadd_fast(m1); muladd(m5, SECP256K1_N_C_0); muladd(m4, SECP256K1_N_C_1); - uint64_t p1; extract(p1); + extract(p1); sumadd(m2); muladd(m6, SECP256K1_N_C_0); muladd(m5, SECP256K1_N_C_1); sumadd(m4); - uint64_t p2; extract(p2); + extract(p2); sumadd_fast(m3); muladd_fast(m6, SECP256K1_N_C_1); sumadd_fast(m5); - uint64_t p3; extract_fast(p3); - uint32_t p4 = c0 + m6; + extract_fast(p3); + p4 = c0 + m6; VERIFY_CHECK(p4 <= 2); /* Reduce 258 bits into 256. */ /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ - uint128_t c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; + c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; @@ -312,12 +570,146 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; c += p3; r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; +#endif /* Final reduction of r. */ secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) { +#ifdef USE_ASM_X86_64 + const uint64_t *pb = b->d; + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r15\n" + "movq 8(%%rdi), %%rbx\n" + "movq 16(%%rdi), %%rcx\n" + "movq 0(%%rdx), %%r11\n" + "movq 8(%%rdx), %%r12\n" + "movq 16(%%rdx), %%r13\n" + "movq 24(%%rdx), %%r14\n" + /* (rax,rdx) = a0 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a0 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a1 * b0 */ + "movq %%rbx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a0 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * b1 */ + "movq %%rbx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a2 * b0 */ + "movq %%rcx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += a0 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Preload a3 */ + "movq 24(%%rdi), %%r15\n" + /* (r10,r8,r9) += a1 * b2 */ + "movq %%rbx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a2 * b1 */ + "movq %%rcx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a3 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a1 * b3 */ + "movq %%rbx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * b2 */ + "movq %%rcx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a3 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a2 * b3 */ + "movq %%rcx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a3 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : "+d"(pb) + : "S"(l), "D"(a->d) + : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); +#else /* 160 bit accumulator. */ uint64_t c0 = 0, c1 = 0; uint32_t c2 = 0; @@ -346,11 +738,121 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, extract(l[5]); muladd_fast(a->d[3], b->d[3]); extract_fast(l[6]); - VERIFY_CHECK(c1 <= 0); + VERIFY_CHECK(c1 == 0); l[7] = c0; +#endif } -static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) { +static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { +#ifdef USE_ASM_X86_64 + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r11\n" + "movq 8(%%rdi), %%r12\n" + "movq 16(%%rdi), %%r13\n" + "movq 24(%%rdi), %%r14\n" + /* (rax,rdx) = a0 * a0 */ + "movq %%r11, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx,0) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a0 * a1 */ + "movq %%r11, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a0 * a2 */ + "movq %%r11, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * a1 */ + "movq %%r12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += 2 * a0 * a3 */ + "movq %%r11, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += 2 * a1 * a2 */ + "movq %%r12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a1 * a3 */ + "movq %%r12, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * a2 */ + "movq %%r13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a2 * a3 */ + "movq %%r13, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * a3 */ + "movq %%r14, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : + : "S"(l), "D"(a->d) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); +#else /* 160 bit accumulator. */ uint64_t c0 = 0, c1 = 0; uint32_t c2 = 0; @@ -375,6 +877,7 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) extract_fast(l[6]); VERIFY_CHECK(c1 == 0); l[7] = c0; +#endif } #undef sumadd @@ -385,19 +888,32 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) #undef extract #undef extract_fast -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint64_t l[8]; secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); + r->d[3] = (r->d[3] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t l[8]; secp256k1_scalar_sqr_512(l, a); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; r1->d[2] = 0; @@ -407,25 +923,27 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ r2->d[2] = 0; r2->d[3] = 0; } +#endif -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; } -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { - VERIFY_CHECK(shift >= 256); +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { uint64_t l[8]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); secp256k1_scalar_mul_512(l, a, b); - unsigned int shiftlimbs = shift >> 6; - unsigned int shiftlow = shift & 0x3F; - unsigned int shifthigh = 64 - shiftlow; + shiftlimbs = shift >> 6; + shiftlow = shift & 0x3F; + shifthigh = 64 - shiftlow; r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h index f70328cfc933..2c9a348e2476 100644 --- a/src/secp256k1/src/scalar_8x32.h +++ b/src/secp256k1/src/scalar_8x32.h @@ -4,14 +4,16 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint32_t d[8]; -} secp256k1_scalar_t; +} secp256k1_scalar; -#endif +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index 915cbcddbe80..4f9ed61feaec 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) @@ -34,7 +34,7 @@ #define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) #define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { r->d[0] = 0; r->d[1] = 0; r->d[2] = 0; @@ -45,7 +45,7 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { r->d[7] = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; @@ -56,12 +56,12 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, uns r->d[7] = 0; } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); if ((offset + count - 1) >> 5 == offset >> 5) { @@ -72,7 +72,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256 } } -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ @@ -90,9 +90,10 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal return yes; } -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) { +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { + uint64_t t; VERIFY_CHECK(overflow <= 1); - uint64_t t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; @@ -111,7 +112,8 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3 return overflow; } -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + int overflow; uint64_t t = (uint64_t)a->d[0] + b->d[0]; r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)a->d[1] + b->d[1]; @@ -128,15 +130,17 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)a->d[7] + b->d[7]; r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; - int overflow = t + secp256k1_scalar_check_overflow(r); + overflow = t + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + uint64_t t; VERIFY_CHECK(bit < 256); - uint64_t t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; @@ -158,7 +162,8 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { #endif } -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int over; r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; @@ -167,13 +172,13 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; - int over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); if (overflow) { *overflow = over; } } -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; @@ -184,11 +189,11 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_ bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; } -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; r->d[0] = t & nonzero; t >>= 32; @@ -208,11 +213,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala r->d[7] = t & nonzero; } -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_H_7); @@ -230,6 +235,31 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint32_t mask = !flag - 1; + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); + uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); + r->d[7] = t & nonzero; + return 2 * (mask == 0) - 1; +} + + /* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ /** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ @@ -263,16 +293,16 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { /** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ #define muladd2(a,b) { \ - uint32_t tl, th; \ + uint32_t tl, th, th2, tl2; \ { \ uint64_t t = (uint64_t)a * b; \ th = t >> 32; /* at most 0xFFFFFFFE */ \ tl = t; \ } \ - uint32_t th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ + th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - uint32_t tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ + tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ c0 += tl2; /* overflow is handled on the next line */ \ th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ @@ -285,8 +315,9 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ + unsigned int over; \ c0 += (a); /* overflow is handled on the next line */ \ - unsigned int over = (c0 < (a)) ? 1 : 0; \ + over = (c0 < (a)) ? 1 : 0; \ c1 += over; /* overflow is handled on the next line */ \ c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ } @@ -315,8 +346,11 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { VERIFY_CHECK(c2 == 0); \ } -static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) { +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { + uint64_t c; uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; + uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; + uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; /* 96 bit accumulator. */ uint32_t c0, c1, c2; @@ -325,115 +359,115 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ c0 = l[0]; c1 = 0; c2 = 0; muladd_fast(n0, SECP256K1_N_C_0); - uint32_t m0; extract_fast(m0); + extract_fast(m0); sumadd_fast(l[1]); muladd(n1, SECP256K1_N_C_0); muladd(n0, SECP256K1_N_C_1); - uint32_t m1; extract(m1); + extract(m1); sumadd(l[2]); muladd(n2, SECP256K1_N_C_0); muladd(n1, SECP256K1_N_C_1); muladd(n0, SECP256K1_N_C_2); - uint32_t m2; extract(m2); + extract(m2); sumadd(l[3]); muladd(n3, SECP256K1_N_C_0); muladd(n2, SECP256K1_N_C_1); muladd(n1, SECP256K1_N_C_2); muladd(n0, SECP256K1_N_C_3); - uint32_t m3; extract(m3); + extract(m3); sumadd(l[4]); muladd(n4, SECP256K1_N_C_0); muladd(n3, SECP256K1_N_C_1); muladd(n2, SECP256K1_N_C_2); muladd(n1, SECP256K1_N_C_3); sumadd(n0); - uint32_t m4; extract(m4); + extract(m4); sumadd(l[5]); muladd(n5, SECP256K1_N_C_0); muladd(n4, SECP256K1_N_C_1); muladd(n3, SECP256K1_N_C_2); muladd(n2, SECP256K1_N_C_3); sumadd(n1); - uint32_t m5; extract(m5); + extract(m5); sumadd(l[6]); muladd(n6, SECP256K1_N_C_0); muladd(n5, SECP256K1_N_C_1); muladd(n4, SECP256K1_N_C_2); muladd(n3, SECP256K1_N_C_3); sumadd(n2); - uint32_t m6; extract(m6); + extract(m6); sumadd(l[7]); muladd(n7, SECP256K1_N_C_0); muladd(n6, SECP256K1_N_C_1); muladd(n5, SECP256K1_N_C_2); muladd(n4, SECP256K1_N_C_3); sumadd(n3); - uint32_t m7; extract(m7); + extract(m7); muladd(n7, SECP256K1_N_C_1); muladd(n6, SECP256K1_N_C_2); muladd(n5, SECP256K1_N_C_3); sumadd(n4); - uint32_t m8; extract(m8); + extract(m8); muladd(n7, SECP256K1_N_C_2); muladd(n6, SECP256K1_N_C_3); sumadd(n5); - uint32_t m9; extract(m9); + extract(m9); muladd(n7, SECP256K1_N_C_3); sumadd(n6); - uint32_t m10; extract(m10); + extract(m10); sumadd_fast(n7); - uint32_t m11; extract_fast(m11); + extract_fast(m11); VERIFY_CHECK(c0 <= 1); - uint32_t m12 = c0; + m12 = c0; /* Reduce 385 bits into 258. */ /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ c0 = m0; c1 = 0; c2 = 0; muladd_fast(m8, SECP256K1_N_C_0); - uint32_t p0; extract_fast(p0); + extract_fast(p0); sumadd_fast(m1); muladd(m9, SECP256K1_N_C_0); muladd(m8, SECP256K1_N_C_1); - uint32_t p1; extract(p1); + extract(p1); sumadd(m2); muladd(m10, SECP256K1_N_C_0); muladd(m9, SECP256K1_N_C_1); muladd(m8, SECP256K1_N_C_2); - uint32_t p2; extract(p2); + extract(p2); sumadd(m3); muladd(m11, SECP256K1_N_C_0); muladd(m10, SECP256K1_N_C_1); muladd(m9, SECP256K1_N_C_2); muladd(m8, SECP256K1_N_C_3); - uint32_t p3; extract(p3); + extract(p3); sumadd(m4); muladd(m12, SECP256K1_N_C_0); muladd(m11, SECP256K1_N_C_1); muladd(m10, SECP256K1_N_C_2); muladd(m9, SECP256K1_N_C_3); sumadd(m8); - uint32_t p4; extract(p4); + extract(p4); sumadd(m5); muladd(m12, SECP256K1_N_C_1); muladd(m11, SECP256K1_N_C_2); muladd(m10, SECP256K1_N_C_3); sumadd(m9); - uint32_t p5; extract(p5); + extract(p5); sumadd(m6); muladd(m12, SECP256K1_N_C_2); muladd(m11, SECP256K1_N_C_3); sumadd(m10); - uint32_t p6; extract(p6); + extract(p6); sumadd_fast(m7); muladd_fast(m12, SECP256K1_N_C_3); sumadd_fast(m11); - uint32_t p7; extract_fast(p7); - uint32_t p8 = c0 + m12; + extract_fast(p7); + p8 = c0 + m12; VERIFY_CHECK(p8 <= 2); /* Reduce 258 bits into 256. */ /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ - uint64_t c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; + c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; @@ -454,7 +488,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint32_t l[16], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -542,7 +576,7 @@ static void secp256k1_scalar_mul_512(uint32_t l[16], const secp256k1_scalar_t *a l[15] = c0; } -static void secp256k1_scalar_sqr_512(uint32_t l[16], const secp256k1_scalar_t *a) { +static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -610,19 +644,36 @@ static void secp256k1_scalar_sqr_512(uint32_t l[16], const secp256k1_scalar_t *a #undef extract #undef extract_fast -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint32_t l[16]; secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); + r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); + r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); + r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); + r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); + r->d[7] = (r->d[7] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t l[16]; secp256k1_scalar_sqr_512(l, a); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; r1->d[2] = a->d[2]; @@ -640,18 +691,22 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ r2->d[6] = 0; r2->d[7] = 0; } +#endif -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; } -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { - VERIFY_CHECK(shift >= 256); +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { uint32_t l[16]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); secp256k1_scalar_mul_512(l, a, b); - unsigned int shiftlimbs = shift >> 5; - unsigned int shiftlow = shift & 0x1F; - unsigned int shifthigh = 32 - shiftlow; + shiftlimbs = shift >> 5; + shiftlow = shift & 0x1F; + shifthigh = 32 - shiftlow; r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; @@ -660,9 +715,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h index 7fc159df7727..fa790570ff83 100644 --- a/src/secp256k1/src/scalar_impl.h +++ b/src/secp256k1/src/scalar_impl.h @@ -4,10 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_IMPL_H_ -#define _SECP256K1_SCALAR_IMPL_H_ - -#include +#ifndef SECP256K1_SCALAR_IMPL_H +#define SECP256K1_SCALAR_IMPL_H #include "group.h" #include "scalar.h" @@ -16,7 +14,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low_impl.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64_impl.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32_impl.h" @@ -24,313 +24,310 @@ #error "Please select scalar implementation" #endif -typedef struct { #ifndef USE_NUM_NONE - secp256k1_num_t order; -#endif -#ifdef USE_ENDOMORPHISM - secp256k1_scalar_t minus_lambda, minus_b1, minus_b2, g1, g2; -#endif -} secp256k1_scalar_consts_t; - -static const secp256k1_scalar_consts_t *secp256k1_scalar_consts = NULL; - -static void secp256k1_scalar_start(void) { - if (secp256k1_scalar_consts != NULL) - return; - - /* Allocate. */ - secp256k1_scalar_consts_t *ret = (secp256k1_scalar_consts_t*)malloc(sizeof(secp256k1_scalar_consts_t)); +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) { + unsigned char c[32]; + secp256k1_scalar_get_b32(c, a); + secp256k1_num_set_bin(r, c, 32); +} -#ifndef USE_NUM_NONE - static const unsigned char secp256k1_scalar_consts_order[] = { +/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ +static void secp256k1_scalar_order_get_num(secp256k1_num *r) { +#if defined(EXHAUSTIVE_TEST_ORDER) + static const unsigned char order[32] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER + }; +#else + static const unsigned char order[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 }; - secp256k1_num_set_bin(&ret->order, secp256k1_scalar_consts_order, sizeof(secp256k1_scalar_consts_order)); #endif -#ifdef USE_ENDOMORPHISM - /** - * Lambda is a scalar which has the property for secp256k1 that point multiplication by - * it is efficiently computable (see secp256k1_gej_mul_lambda). */ - static const unsigned char secp256k1_scalar_consts_lambda[32] = { - 0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0, - 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, - 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78, - 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72 - }; - /** - * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm - * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 - * and k2 have a small size. - * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: - * - * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} - * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} - * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} - * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} - * - * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives - * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and - * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. - * - * g1, g2 are precomputed constants used to replace division with a rounded multiplication - * when decomposing the scalar for an endomorphism-based point multiplication. - * - * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve - * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. - * - * The derivation is described in the paper "Efficient Software Implementation of Public-Key - * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), - * Section 4.3 (here we use a somewhat higher-precision estimate): - * d = a1*b2 - b1*a2 - * g1 = round((2^272)*b2/d) - * g2 = round((2^272)*b1/d) - * - * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found - * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). - */ - static const unsigned char secp256k1_scalar_consts_minus_b1[32] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28, - 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3 - }; - static const unsigned char secp256k1_scalar_consts_b2[32] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd, - 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15 - }; - static const unsigned char secp256k1_scalar_consts_g1[32] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x86, - 0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c, - 0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab - }; - static const unsigned char secp256k1_scalar_consts_g2[32] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x43, - 0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54, - 0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12 - }; - - secp256k1_scalar_set_b32(&ret->minus_lambda, secp256k1_scalar_consts_lambda, NULL); - secp256k1_scalar_negate(&ret->minus_lambda, &ret->minus_lambda); - secp256k1_scalar_set_b32(&ret->minus_b1, secp256k1_scalar_consts_minus_b1, NULL); - secp256k1_scalar_set_b32(&ret->minus_b2, secp256k1_scalar_consts_b2, NULL); - secp256k1_scalar_negate(&ret->minus_b2, &ret->minus_b2); - secp256k1_scalar_set_b32(&ret->g1, secp256k1_scalar_consts_g1, NULL); - secp256k1_scalar_set_b32(&ret->g2, secp256k1_scalar_consts_g2, NULL); -#endif - - /* Set the global pointer. */ - secp256k1_scalar_consts = ret; -} - -static void secp256k1_scalar_stop(void) { - if (secp256k1_scalar_consts == NULL) - return; - - secp256k1_scalar_consts_t *c = (secp256k1_scalar_consts_t*)secp256k1_scalar_consts; - secp256k1_scalar_consts = NULL; - free(c); -} - -#ifndef USE_NUM_NONE -static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) { - unsigned char c[32]; - secp256k1_scalar_get_b32(c, a); - secp256k1_num_set_bin(r, c, 32); -} - -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { - *r = secp256k1_scalar_consts->order; + secp256k1_num_set_bin(r, order, 32); } #endif -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { - /* First compute x ^ (2^N - 1) for some values of N. */ - secp256k1_scalar_t x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; - - secp256k1_scalar_sqr(&x2, x); - secp256k1_scalar_mul(&x2, &x2, x); - - secp256k1_scalar_sqr(&x3, &x2); - secp256k1_scalar_mul(&x3, &x3, x); - - secp256k1_scalar_sqr(&x4, &x3); - secp256k1_scalar_mul(&x4, &x4, x); - - secp256k1_scalar_sqr(&x6, &x4); +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { +#if defined(EXHAUSTIVE_TEST_ORDER) + int i; + *r = 0; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) + *r = i; + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(*r != 0); +} +#else + secp256k1_scalar *t; + int i; + /* First compute xN as x ^ (2^N - 1) for some values of N, + * and uM as x ^ M for some values of M. */ + secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126; + secp256k1_scalar u2, u5, u9, u11, u13; + + secp256k1_scalar_sqr(&u2, x); + secp256k1_scalar_mul(&x2, &u2, x); + secp256k1_scalar_mul(&u5, &u2, &x2); + secp256k1_scalar_mul(&x3, &u5, &u2); + secp256k1_scalar_mul(&u9, &x3, &u2); + secp256k1_scalar_mul(&u11, &u9, &u2); + secp256k1_scalar_mul(&u13, &u11, &u2); + + secp256k1_scalar_sqr(&x6, &u13); secp256k1_scalar_sqr(&x6, &x6); - secp256k1_scalar_mul(&x6, &x6, &x2); - - secp256k1_scalar_sqr(&x7, &x6); - secp256k1_scalar_mul(&x7, &x7, x); - - secp256k1_scalar_sqr(&x8, &x7); - secp256k1_scalar_mul(&x8, &x8, x); - - secp256k1_scalar_sqr(&x15, &x8); - for (int i=0; i<6; i++) - secp256k1_scalar_sqr(&x15, &x15); - secp256k1_scalar_mul(&x15, &x15, &x7); - - secp256k1_scalar_sqr(&x30, &x15); - for (int i=0; i<14; i++) - secp256k1_scalar_sqr(&x30, &x30); - secp256k1_scalar_mul(&x30, &x30, &x15); - - secp256k1_scalar_sqr(&x60, &x30); - for (int i=0; i<29; i++) - secp256k1_scalar_sqr(&x60, &x60); - secp256k1_scalar_mul(&x60, &x60, &x30); - - secp256k1_scalar_sqr(&x120, &x60); - for (int i=0; i<59; i++) - secp256k1_scalar_sqr(&x120, &x120); - secp256k1_scalar_mul(&x120, &x120, &x60); - - secp256k1_scalar_sqr(&x127, &x120); - for (int i=0; i<6; i++) - secp256k1_scalar_sqr(&x127, &x127); - secp256k1_scalar_mul(&x127, &x127, &x7); - - /* Then accumulate the final result (t starts at x127). */ - secp256k1_scalar_t *t = &x127; - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<4; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(&x6, &x6, &u11); + + secp256k1_scalar_sqr(&x8, &x6); + secp256k1_scalar_sqr(&x8, &x8); + secp256k1_scalar_mul(&x8, &x8, &x2); + + secp256k1_scalar_sqr(&x14, &x8); + for (i = 0; i < 5; i++) { + secp256k1_scalar_sqr(&x14, &x14); + } + secp256k1_scalar_mul(&x14, &x14, &x6); + + secp256k1_scalar_sqr(&x28, &x14); + for (i = 0; i < 13; i++) { + secp256k1_scalar_sqr(&x28, &x28); + } + secp256k1_scalar_mul(&x28, &x28, &x14); + + secp256k1_scalar_sqr(&x56, &x28); + for (i = 0; i < 27; i++) { + secp256k1_scalar_sqr(&x56, &x56); + } + secp256k1_scalar_mul(&x56, &x56, &x28); + + secp256k1_scalar_sqr(&x112, &x56); + for (i = 0; i < 55; i++) { + secp256k1_scalar_sqr(&x112, &x112); + } + secp256k1_scalar_mul(&x112, &x112, &x56); + + secp256k1_scalar_sqr(&x126, &x112); + for (i = 0; i < 13; i++) { + secp256k1_scalar_sqr(&x126, &x126); + } + secp256k1_scalar_mul(&x126, &x126, &x14); + + /* Then accumulate the final result (t starts at x126). */ + t = &x126; + for (i = 0; i < 3; i++) { + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (int i=0; i<2; i++) /* 0 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<4; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (int i=0; i<3; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (int i=0; i<4; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (int i=0; i<5; i++) /* 00 */ + for (i = 0; i < 5; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (int i=0; i<4; i++) /* 00 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (int i=0; i<2; i++) /* 0 */ + for (i = 0; i < 6; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<2; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<5; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 3; i++) { secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<3; i++) /* 00 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<4; i++) /* 000 */ + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<2; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 000 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<10; i++) /* 0000000 */ + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 10; i++) { /* 0000000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (int i=0; i<4; i++) /* 0 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (int i=0; i<9; i++) /* 0 */ + for (i = 0; i < 9; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<3; i++) /* 00 */ + for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<3; i++) /* 00 */ + } + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<5; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<5; i++) /* 000 */ + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 5; i++) { secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (int i=0; i<4; i++) /* 00 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (int i=0; i<2; i++) /* 0 */ - secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<8; i++) /* 000000 */ + for (i = 0; i < 6; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (int i=0; i<3; i++) /* 0 */ + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 10; i++) { /* 000000 */ secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (int i=0; i<3; i++) /* 00 */ + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { secp256k1_scalar_sqr(t, t); - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<6; i++) /* 00000 */ + } + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 00000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (int i=0; i<8; i++) /* 00 */ + for (i = 0; i < 8; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(r, t, &x6); /* 111111 */ } -static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + return !(a->d[0] & 1); +} +#endif + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { #if defined(USE_SCALAR_INV_BUILTIN) secp256k1_scalar_inverse(r, x); #elif defined(USE_SCALAR_INV_NUM) unsigned char b[32]; - secp256k1_scalar_get_b32(b, x); - secp256k1_num_t n; + secp256k1_num n, m; + secp256k1_scalar t = *x; + secp256k1_scalar_get_b32(b, &t); secp256k1_num_set_bin(&n, b, 32); - secp256k1_num_mod_inverse(&n, &n, &secp256k1_scalar_consts->order); + secp256k1_scalar_order_get_num(&m); + secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); secp256k1_scalar_set_b32(r, b, NULL); + /* Verify that the inverse was computed correctly, without GMP code. */ + secp256k1_scalar_mul(&t, &t, r); + CHECK(secp256k1_scalar_is_one(&t)); #else #error "Please select scalar inverse implementation" #endif } #ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +#if defined(EXHAUSTIVE_TEST_ORDER) +/** + * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the + * full case we don't bother making k1 and k2 be small, we just want them to be + * nontrivial to get full test coverage for the exhaustive tests. We therefore + * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; +} +#else +/** + * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where + * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, + * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} + * + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 have a small size. + * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * + * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} + * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} + * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * + * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and + * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * + * g1, g2 are precomputed constants used to replace division with a rounded multiplication + * when decomposing the scalar for an endomorphism-based point multiplication. + * + * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve + * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. + * + * The derivation is described in the paper "Efficient Software Implementation of Public-Key + * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), + * Section 4.3 (here we use a somewhat higher-precision estimate): + * d = a1*b2 - b1*a2 + * g1 = round((2^272)*b2/d) + * g2 = round((2^272)*b1/d) + * + * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found + * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). + * + * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). + */ + +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + secp256k1_scalar c1, c2; + static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( + 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, + 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL + ); + static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL + ); + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL + ); + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, + 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + ); + static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, + 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL + ); VERIFY_CHECK(r1 != a); VERIFY_CHECK(r2 != a); - secp256k1_scalar_t c1, c2; - secp256k1_scalar_mul_shift_var(&c1, a, &secp256k1_scalar_consts->g1, 272); - secp256k1_scalar_mul_shift_var(&c2, a, &secp256k1_scalar_consts->g2, 272); - secp256k1_scalar_mul(&c1, &c1, &secp256k1_scalar_consts->minus_b1); - secp256k1_scalar_mul(&c2, &c2, &secp256k1_scalar_consts->minus_b2); + /* these _var calls are constant time since the shift amount is constant */ + secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); + secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); + secp256k1_scalar_mul(&c1, &c1, &minus_b1); + secp256k1_scalar_mul(&c2, &c2, &minus_b2); secp256k1_scalar_add(r2, &c1, &c2); - secp256k1_scalar_mul(r1, r2, &secp256k1_scalar_consts->minus_lambda); + secp256k1_scalar_mul(r1, r2, &minus_lambda); secp256k1_scalar_add(r1, r1, a); } #endif - #endif + +#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/src/secp256k1/src/field_gmp.h b/src/secp256k1/src/scalar_low.h similarity index 51% rename from src/secp256k1/src/field_gmp.h rename to src/secp256k1/src/scalar_low.h index b390fd9de8d4..5836febc5b72 100644 --- a/src/secp256k1/src/field_gmp.h +++ b/src/secp256k1/src/scalar_low.h @@ -1,18 +1,15 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2015 Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H -#include +#include -#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS) +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t secp256k1_scalar; -typedef struct { - mp_limb_t n[FIELD_LIMBS+1]; -} secp256k1_fe_t; - -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h new file mode 100644 index 000000000000..c80e70c5a2ad --- /dev/null +++ b/src/secp256k1/src/scalar_low_impl.h @@ -0,0 +1,114 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "scalar.h" + +#include + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + return !(*a & 1); +} + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + if (offset < 32) + return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); + else + return 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + return secp256k1_scalar_get_bits(a, offset, count); +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + return *r < *b; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + if (flag && bit < 32) + *r += (1 << bit); +#ifdef VERIFY + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; + int i; + *r = 0; + for (i = 0; i < 32; i++) { + *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + } + /* just deny overflow, it basically always happens */ + if (overflow) *overflow = 0; +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + return *a == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + return *a == 1; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + if (flag) secp256k1_scalar_negate(r, r); + return flag ? -1 : 1; +} + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; +} + +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = *r & ((1 << n) - 1); + *r >>= n; + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r1 = *a; + *r2 = 0; +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + return *a == *b; +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scratch.h b/src/secp256k1/src/scratch.h new file mode 100644 index 000000000000..e876d0c3e02b --- /dev/null +++ b/src/secp256k1/src/scratch.h @@ -0,0 +1,39 @@ +/********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCRATCH_ +#define _SECP256K1_SCRATCH_ + +#define SECP256K1_SCRATCH_MAX_FRAMES 5 + +/* The typedef is used internally; the struct name is used in the public API + * (where it is exposed as a different typedef) */ +typedef struct secp256k1_scratch_space_struct { + void *data[SECP256K1_SCRATCH_MAX_FRAMES]; + size_t offset[SECP256K1_SCRATCH_MAX_FRAMES]; + size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES]; + size_t frame; + size_t max_size; + const secp256k1_callback* error_callback; +} secp256k1_scratch; + +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); + +static void secp256k1_scratch_destroy(secp256k1_scratch* scratch); + +/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */ +static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects); + +/** Deallocates a stack frame */ +static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch); + +/** Returns the maximum allocation the scratch space will allow */ +static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects); + +/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ +static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n); + +#endif diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h new file mode 100644 index 000000000000..abed713b21d2 --- /dev/null +++ b/src/secp256k1/src/scratch_impl.h @@ -0,0 +1,86 @@ +/********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCRATCH_IMPL_H_ +#define _SECP256K1_SCRATCH_IMPL_H_ + +#include "scratch.h" + +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. + * TODO: Determine this at configure time. */ +#define ALIGNMENT 16 + +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) { + secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret)); + if (ret != NULL) { + memset(ret, 0, sizeof(*ret)); + ret->max_size = max_size; + ret->error_callback = error_callback; + } + return ret; +} + +static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) { + if (scratch != NULL) { + VERIFY_CHECK(scratch->frame == 0); + free(scratch); + } +} + +static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) { + size_t i = 0; + size_t allocated = 0; + for (i = 0; i < scratch->frame; i++) { + allocated += scratch->frame_size[i]; + } + if (scratch->max_size - allocated <= objects * ALIGNMENT) { + return 0; + } + return scratch->max_size - allocated - objects * ALIGNMENT; +} + +static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) { + VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES); + + if (n <= secp256k1_scratch_max_allocation(scratch, objects)) { + n += objects * ALIGNMENT; + scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n); + if (scratch->data[scratch->frame] == NULL) { + return 0; + } + scratch->frame_size[scratch->frame] = n; + scratch->offset[scratch->frame] = 0; + scratch->frame++; + return 1; + } else { + return 0; + } +} + +static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) { + VERIFY_CHECK(scratch->frame > 0); + scratch->frame -= 1; + free(scratch->data[scratch->frame]); +} + +static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) { + void *ret; + size_t frame = scratch->frame - 1; + size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + + if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) { + return NULL; + } + ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]); + memset(ret, 0, size); + scratch->offset[frame] += size; + + return ret; +} + +#endif diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index 20fc27df74aa..cd0972dfaf46 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -1,11 +1,9 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#define SECP256K1_BUILD (1) - #include "include/secp256k1.h" #include "util.h" @@ -14,217 +12,472 @@ #include "scalar_impl.h" #include "group_impl.h" #include "ecmult_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_gen_impl.h" #include "ecdsa_impl.h" #include "eckey_impl.h" +#include "hash_impl.h" +#include "scratch_impl.h" + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +static void default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} + +static const secp256k1_callback default_illegal_callback = { + default_illegal_callback_fn, + NULL +}; + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} -void secp256k1_start(unsigned int flags) { - secp256k1_fe_start(); - secp256k1_ge_start(); - secp256k1_scalar_start(); - secp256k1_ecdsa_start(); - if (flags & SECP256K1_START_SIGN) { - secp256k1_ecmult_gen_start(); +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + + +struct secp256k1_context_struct { + secp256k1_ecmult_context ecmult_ctx; + secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_callback illegal_callback; + secp256k1_callback error_callback; +}; + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&ret->illegal_callback, + "Invalid flags"); + free(ret); + return NULL; } - if (flags & SECP256K1_START_VERIFY) { - secp256k1_ecmult_start(); + + secp256k1_ecmult_context_init(&ret->ecmult_ctx); + secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); + + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); } + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); + } + + return ret; } -void secp256k1_stop(void) { - secp256k1_ecmult_stop(); - secp256k1_ecmult_gen_stop(); - secp256k1_ecdsa_stop(); - secp256k1_scalar_stop(); - secp256k1_ge_stop(); - secp256k1_fe_stop(); -} - -int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); - DEBUG_CHECK(msg != NULL); - DEBUG_CHECK(msglen <= 32); - DEBUG_CHECK(sig != NULL); - DEBUG_CHECK(pubkey != NULL); - - unsigned char msg32[32] = {0}; - memcpy(msg32 + 32 - msglen, msg, msglen); - int ret = -3; - secp256k1_scalar_t m; - secp256k1_ecdsa_sig_t s; - secp256k1_ge_t q; - secp256k1_scalar_set_b32(&m, msg32, NULL); +secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = ctx->illegal_callback; + ret->error_callback = ctx->error_callback; + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); + return ret; +} - if (!secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { - ret = -1; - goto end; +void secp256k1_context_destroy(secp256k1_context* ctx) { + if (ctx != NULL) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + + free(ctx); } - if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { - ret = -2; - goto end; +} + +void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_illegal_callback_fn; } - if (!secp256k1_ecdsa_sig_verify(&s, &q, &m)) { - ret = 0; - goto end; + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_error_callback_fn; } - ret = 1; -end: - return ret; + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; } -int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) { - DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); - DEBUG_CHECK(message != NULL); - DEBUG_CHECK(messagelen <= 32); - DEBUG_CHECK(signature != NULL); - DEBUG_CHECK(signaturelen != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(nonce != NULL); +secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { + VERIFY_CHECK(ctx != NULL); + return secp256k1_scratch_create(&ctx->error_callback, max_size); +} - secp256k1_scalar_t sec, non, msg; - secp256k1_scalar_set_b32(&sec, seckey, NULL); - int overflow = 0; - secp256k1_scalar_set_b32(&non, nonce, &overflow); - { - unsigned char c[32] = {0}; - memcpy(c + 32 - messagelen, message, messagelen); - secp256k1_scalar_set_b32(&msg, c, NULL); - memset(c, 0, 32); +void secp256k1_scratch_space_destroy(secp256k1_scratch_space* scratch) { + secp256k1_scratch_destroy(scratch); +} + +static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { + if (sizeof(secp256k1_ge_storage) == 64) { + /* When the secp256k1_ge_storage type is exactly 64 byte, use its + * representation inside secp256k1_pubkey, as conversion is very fast. + * Note that secp256k1_pubkey_save must use the same representation. */ + secp256k1_ge_storage s; + memcpy(&s, &pubkey->data[0], sizeof(s)); + secp256k1_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe x, y; + secp256k1_fe_set_b32(&x, pubkey->data); + secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_ge_set_xy(ge, &x, &y); } - int ret = !secp256k1_scalar_is_zero(&non) && !overflow; - secp256k1_ecdsa_sig_t sig; - if (ret) { - ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL); + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { + if (sizeof(secp256k1_ge_storage) == 64) { + secp256k1_ge_storage s; + secp256k1_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, sizeof(s)); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(pubkey->data, &ge->x); + secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); } - if (ret) { - secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + secp256k1_pubkey_save(pubkey, &Q); + secp256k1_ge_clear(&Q); + return 1; +} + +int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { + secp256k1_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } } - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) { - DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); - DEBUG_CHECK(message != NULL); - DEBUG_CHECK(messagelen <= 32); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(nonce != NULL); +static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } +} - secp256k1_scalar_t sec, non, msg; - secp256k1_scalar_set_b32(&sec, seckey, NULL); - int overflow = 0; - secp256k1_scalar_set_b32(&non, nonce, &overflow); - { - unsigned char c[32] = {0}; - memcpy(c + 32 - messagelen, message, messagelen); - secp256k1_scalar_set_b32(&msg, c, NULL); - memset(c, 0, 32); +static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); } - int ret = !secp256k1_scalar_is_zero(&non) && !overflow; - secp256k1_ecdsa_sig_t sig; - if (ret) { - ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid); +} + +int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; } +} + +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; if (ret) { - secp256k1_scalar_get_b32(sig64, &sig.r); - secp256k1_scalar_get_b32(sig64 + 32, &sig.s); + secp256k1_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); } - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); - DEBUG_CHECK(msg != NULL); - DEBUG_CHECK(msglen <= 32); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(recid >= 0 && recid <= 3); +int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; int ret = 0; - unsigned char msg32[32] = {0}; - memcpy(msg32 + 32 - msglen, msg, msglen); - secp256k1_scalar_t m; - secp256k1_ecdsa_sig_t sig; - int overflow = 0; - secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); - if (overflow) { - return 0; - } - secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow); - if (overflow) { - return 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); } + + return ret; +} + +int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + secp256k1_scalar_set_b32(&m, msg32, NULL); + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && + secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); +} + +static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { + memcpy(buf + *offset, data, len); + *offset += len; +} - secp256k1_ge_t q; - if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) { - ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + unsigned int offset = 0; + secp256k1_rfc6979_hmac_sha256 rng; + unsigned int i; + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + buffer_append(keydata, &offset, key32, 32); + buffer_append(keydata, &offset, msg32, 32); + if (data != NULL) { + buffer_append(keydata, &offset, data, 32); + } + if (algo16 != NULL) { + buffer_append(keydata, &offset, algo16, 16); + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + memset(keydata, 0, sizeof(keydata)); + for (i = 0; i <= counter; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + return 1; +} + +const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; + +int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; + unsigned int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + if (!overflow && !secp256k1_scalar_is_zero(&non)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { + break; + } + } + count++; + } + memset(nonce32, 0, 32); + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); } return ret; } -int secp256k1_ec_seckey_verify(const unsigned char *seckey) { - DEBUG_CHECK(seckey != NULL); - - secp256k1_scalar_t sec; +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; + int ret; int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + secp256k1_scalar_set_b32(&sec, seckey, &overflow); - int ret = !secp256k1_scalar_is_zero(&sec) && !overflow; + ret = !overflow && !secp256k1_scalar_is_zero(&sec); secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_pubkey_verify(const unsigned char *pubkey, int pubkeylen) { - DEBUG_CHECK(pubkey != NULL); +int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { + secp256k1_gej pj; + secp256k1_ge p; + secp256k1_scalar sec; + int overflow; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); - secp256k1_ge_t q; - return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + if (ret) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_pubkey_save(pubkey, &p); + } + secp256k1_scalar_clear(&sec); + return ret; } -int secp256k1_ec_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { - DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(seckey != NULL); +int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { + secp256k1_scalar sec; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); - secp256k1_scalar_t sec; secp256k1_scalar_set_b32(&sec, seckey, NULL); - secp256k1_gej_t pj; - secp256k1_ecmult_gen(&pj, &sec); - secp256k1_scalar_clear(&sec); - secp256k1_ge_t p; - secp256k1_ge_set_gej(&p, &pj); - return secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); + secp256k1_scalar_negate(&sec, &sec); + secp256k1_scalar_get_b32(seckey, &sec); + + return 1; } -int secp256k1_ec_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) { - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); +int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { + int ret = 0; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); - secp256k1_ge_t p; - if (!secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) - return 0; - return secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); + ret = secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + secp256k1_ge_neg(&p, &p); + secp256k1_pubkey_save(pubkey, &p); + } + return ret; } -int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) { - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); - - secp256k1_scalar_t term; +int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar term; + secp256k1_scalar sec; + int ret = 0; int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); + secp256k1_scalar_set_b32(&term, tweak, &overflow); - secp256k1_scalar_t sec; secp256k1_scalar_set_b32(&sec, seckey, NULL); - int ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow; + ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -234,41 +487,43 @@ int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *t return ret; } -int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); - - secp256k1_scalar_t term; +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar term; + int ret = 0; int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); + secp256k1_scalar_set_b32(&term, tweak, &overflow); - if (overflow) { - return 0; - } - secp256k1_ge_t p; - int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_add(&p, &term); - } + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } } return ret; } -int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) { - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); - - secp256k1_scalar_t factor; +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar factor; + secp256k1_scalar sec; + int ret = 0; int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); + secp256k1_scalar_set_b32(&factor, tweak, &overflow); - secp256k1_scalar_t sec; secp256k1_scalar_set_b32(&sec, seckey, NULL); - int ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow; + ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -278,51 +533,65 @@ int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *t return ret; } -int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); - - secp256k1_scalar_t factor; +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar factor; + int ret = 0; int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); + secp256k1_scalar_set_b32(&factor, tweak, &overflow); - if (overflow) { - return 0; - } - secp256k1_ge_t p; - int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); if (ret) { - ret = secp256k1_eckey_pubkey_tweak_mul(&p, &factor); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } } return ret; } -int secp256k1_ec_privkey_export(const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - DEBUG_CHECK(privkeylen != NULL); - - secp256k1_scalar_t key; - secp256k1_scalar_set_b32(&key, seckey, NULL); - int ret = secp256k1_eckey_privkey_serialize(privkey, privkeylen, &key, compressed); - secp256k1_scalar_clear(&key); - return ret; +int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + return 1; } -int secp256k1_ec_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) { - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); +int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { + size_t i; + secp256k1_gej Qj; + secp256k1_ge Q; - secp256k1_scalar_t key; - int ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); - if (ret) - secp256k1_scalar_get_b32(seckey, &key); - secp256k1_scalar_clear(&key); - return ret; + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_gej_add_ge(&Qj, &Qj, &Q); + } + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(pubnonce, &Q); + return 1; } + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h index 018b65cd53f1..f1f9be077e37 100644 --- a/src/secp256k1/src/testrand.h +++ b/src/secp256k1/src/testrand.h @@ -4,23 +4,35 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_TESTRAND_H_ -#define _SECP256K1_TESTRAND_H_ +#ifndef SECP256K1_TESTRAND_H +#define SECP256K1_TESTRAND_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" #endif -/** Seed the pseudorandom number generator. */ -SECP256K1_INLINE static void secp256k1_rand_seed(uint64_t v); +/* A non-cryptographic RNG used only for test infrastructure. */ -/** Generate a pseudorandom 32-bit number. */ +/** Seed the pseudorandom number generator for testing. */ +SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); + +/** Generate a pseudorandom number in the range [0..2**32-1]. */ static uint32_t secp256k1_rand32(void); +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +static uint32_t secp256k1_rand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t secp256k1_rand_int(uint32_t range); + /** Generate a pseudorandom 32-byte array. */ static void secp256k1_rand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ static void secp256k1_rand256_test(unsigned char *b32); -#endif +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); + +#endif /* SECP256K1_TESTRAND_H */ diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h index 677c4b9a0e4c..30a91e529613 100644 --- a/src/secp256k1/src/testrand_impl.h +++ b/src/secp256k1/src/testrand_impl.h @@ -1,60 +1,110 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_TESTRAND_IMPL_H_ -#define _SECP256K1_TESTRAND_IMPL_H_ +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H #include #include #include "testrand.h" +#include "hash.h" -static uint32_t secp256k1_Rz = 11, secp256k1_Rw = 11; +static secp256k1_rfc6979_hmac_sha256 secp256k1_test_rng; +static uint32_t secp256k1_test_rng_precomputed[8]; +static int secp256k1_test_rng_precomputed_used = 8; +static uint64_t secp256k1_test_rng_integer; +static int secp256k1_test_rng_integer_bits_left = 0; -SECP256K1_INLINE static void secp256k1_rand_seed(uint64_t v) { - secp256k1_Rz = v >> 32; - secp256k1_Rw = v; +SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); +} - if (secp256k1_Rz == 0 || secp256k1_Rz == 0x9068ffffU) { - secp256k1_Rz = 111; +SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { + if (secp256k1_test_rng_precomputed_used == 8) { + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed)); + secp256k1_test_rng_precomputed_used = 0; } - if (secp256k1_Rw == 0 || secp256k1_Rw == 0x464fffffU) { - secp256k1_Rw = 111; + return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; +} + +static uint32_t secp256k1_rand_bits(int bits) { + uint32_t ret; + if (secp256k1_test_rng_integer_bits_left < bits) { + secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); + secp256k1_test_rng_integer_bits_left += 32; } + ret = secp256k1_test_rng_integer; + secp256k1_test_rng_integer >>= bits; + secp256k1_test_rng_integer_bits_left -= bits; + ret &= ((~((uint32_t)0)) >> (32 - bits)); + return ret; } -SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { - secp256k1_Rz = 36969 * (secp256k1_Rz & 0xFFFF) + (secp256k1_Rz >> 16); - secp256k1_Rw = 18000 * (secp256k1_Rw & 0xFFFF) + (secp256k1_Rw >> 16); - return (secp256k1_Rw << 16) + (secp256k1_Rw >> 16) + secp256k1_Rz; +static uint32_t secp256k1_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; + uint32_t trange, mult; + int bits = 0; + if (range <= 1) { + return 0; + } + trange = range - 1; + while (trange > 0) { + trange >>= 1; + bits++; + } + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); + } + } } static void secp256k1_rand256(unsigned char *b32) { - for (int i=0; i<8; i++) { - uint32_t r = secp256k1_rand32(); - b32[i*4 + 0] = (r >> 0) & 0xFF; - b32[i*4 + 1] = (r >> 8) & 0xFF; - b32[i*4 + 2] = (r >> 16) & 0xFF; - b32[i*4 + 3] = (r >> 24) & 0xFF; - } + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } -static void secp256k1_rand256_test(unsigned char *b32) { - int bits=0; - memset(b32, 0, 32); - while (bits < 256) { - uint32_t ent = secp256k1_rand32(); - int now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31; - uint32_t val = 1 & (ent >> 11); - while (now > 0 && bits < 256) { - b32[bits / 8] |= val << (bits % 8); +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { + int now; + uint32_t val; + now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; + val = secp256k1_rand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); now--; bits++; } } } -#endif +static void secp256k1_rand256_test(unsigned char *b32) { + secp256k1_rand_bytes_test(b32, 32); +} + +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 28db456952c6..15f44914b2e5 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * 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.* **********************************************************************/ @@ -10,8 +10,12 @@ #include #include +#include + +#include #include "secp256k1.c" +#include "include/secp256k1.h" #include "testrand_impl.h" #ifdef ENABLE_OPENSSL_TESTS @@ -19,11 +23,45 @@ #include "openssl/ec.h" #include "openssl/ecdsa.h" #include "openssl/obj_mac.h" +# if OPENSSL_VERSION_NUMBER < 0x10100000L +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {*pr = sig->r; *ps = sig->s;} +# endif +#endif + +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" + +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include +# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +# else +# define VG_UNDEF(x,y) +# define VG_CHECK(x,y) +# endif #endif static int count = 64; +static secp256k1_context *ctx = NULL; + +static void counting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + (*p)--; +} -void random_field_element_test(secp256k1_fe_t *fe) { +void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; secp256k1_rand256_test(b32); @@ -33,85 +71,443 @@ void random_field_element_test(secp256k1_fe_t *fe) { } while(1); } -void random_field_element_magnitude(secp256k1_fe_t *fe) { +void random_field_element_magnitude(secp256k1_fe *fe) { + secp256k1_fe zero; + int n = secp256k1_rand_int(9); secp256k1_fe_normalize(fe); - int n = secp256k1_rand32() % 4; - for (int i = 0; i < n; i++) { - secp256k1_fe_negate(fe, fe, 1 + 2*i); - secp256k1_fe_negate(fe, fe, 2 + 2*i); + if (n == 0) { + return; } + secp256k1_fe_clear(&zero); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int(&zero, n - 1); + secp256k1_fe_add(fe, &zero); + VERIFY_CHECK(fe->magnitude == n); } -void random_group_element_test(secp256k1_ge_t *ge) { - secp256k1_fe_t fe; +void random_group_element_test(secp256k1_ge *ge) { + secp256k1_fe fe; do { random_field_element_test(&fe); - if (secp256k1_ge_set_xo(ge, &fe, secp256k1_rand32() & 1)) + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { + secp256k1_fe_normalize(&ge->y); break; + } } while(1); } -void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) { +void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; do { random_field_element_test(&gej->z); if (!secp256k1_fe_is_zero(&gej->z)) { break; } } while(1); - secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &gej->z); - secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &z2, &gej->z); + secp256k1_fe_sqr(&z2, &gej->z); + secp256k1_fe_mul(&z3, &z2, &gej->z); secp256k1_fe_mul(&gej->x, &ge->x, &z2); secp256k1_fe_mul(&gej->y, &ge->y, &z3); gej->infinity = ge->infinity; } -void random_scalar_order_test(secp256k1_scalar_t *num) { +void random_scalar_order_test(secp256k1_scalar *num) { do { unsigned char b32[32]; - secp256k1_rand256_test(b32); int overflow = 0; + secp256k1_rand256_test(b32); secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) + if (overflow || secp256k1_scalar_is_zero(num)) { continue; + } break; } while(1); } -void random_scalar_order(secp256k1_scalar_t *num) { +void random_scalar_order(secp256k1_scalar *num) { do { unsigned char b32[32]; - secp256k1_rand256(b32); int overflow = 0; + secp256k1_rand256(b32); secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) + if (overflow || secp256k1_scalar_is_zero(num)) { continue; + } break; } while(1); } +void run_context_tests(void) { + secp256k1_pubkey pubkey; + secp256k1_pubkey zero_pubkey; + secp256k1_ecdsa_signature sig; + unsigned char ctmp[32]; + int32_t ecount; + int32_t ecount2; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar msg, key, nonce; + secp256k1_scalar sigr, sigs; + + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + + ecount = 0; + ecount2 = 10; + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_context *ctx_tmp; + + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + } + + /* Verify that the error callback makes it across the clone. */ + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* And that it resets back to default. */ + secp256k1_context_set_error_callback(sign, NULL, NULL); + CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + + /*** attempt to use them ***/ + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + + /* Verify context-type checking illegal-argument errors. */ + memset(ctmp, 1, 32); + CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); + CHECK(ecount == 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); + CHECK(ecount == 2); + VG_UNDEF(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + VG_CHECK(&sig, sizeof(sig)); + CHECK(ecount2 == 10); + CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); + CHECK(ecount2 == 11); + CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 12); + CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 13); + CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0); + CHECK(ecount2 == 14); + CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 14); + secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); + secp256k1_context_set_illegal_callback(sign, NULL, NULL); + + /* This shouldn't leak memory, due to already-set tests. */ + secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); + secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); + + /* obtain a working nonce */ + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); + /* Defined as no-op. */ + secp256k1_context_destroy(NULL); +} + +void run_scratch_tests(void) { + int32_t ecount = 0; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_scratch_space *scratch; + + /* Test public API */ + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + + scratch = secp256k1_scratch_space_create(none, 1000); + CHECK(scratch != NULL); + CHECK(ecount == 0); + + /* Test internal API */ + CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); + CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 1000); + + /* Allocating 500 bytes with no frame fails */ + CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); + CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); + + /* ...but pushing a new stack frame does affect the max allocation */ + CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1 == 1)); + CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 500); /* 500 - ALIGNMENT */ + CHECK(secp256k1_scratch_alloc(scratch, 500) != NULL); + CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); + + CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1) == 0); + + /* ...and this effect is undone by popping the frame */ + secp256k1_scratch_deallocate_frame(scratch); + CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); + CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); + + /* cleanup */ + secp256k1_scratch_space_destroy(scratch); + secp256k1_context_destroy(none); +} + +/***** HASH TESTS *****/ + +void run_sha256_tests(void) { + static const char *inputs[8] = { + "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "For this sample, this 63-byte string will be used as input data", + "This is exactly 64 bytes long, not counting the terminating byte" + }; + static const unsigned char outputs[8][32] = { + {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, + {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, + {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, + {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, + {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, + {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} + }; + int i; + for (i = 0; i < 8; i++) { + unsigned char out[32]; + secp256k1_sha256 hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_rand_int(strlen(inputs[i])); + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_hmac_sha256_tests(void) { + static const char *keys[6] = { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "\x4a\x65\x66\x65", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + }; + static const char *inputs[6] = { + "\x48\x69\x20\x54\x68\x65\x72\x65", + "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" + }; + static const unsigned char outputs[6][32] = { + {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, + {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, + {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, + {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, + {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, + {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} + }; + int i; + for (i = 0; i < 6; i++) { + secp256k1_hmac_sha256 hasher; + unsigned char out[32]; + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_rand_int(strlen(inputs[i])); + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_rfc6979_hmac_sha256_tests(void) { + static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; + static const unsigned char out1[3][32] = { + {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, + {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, + {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} + }; + + static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char out2[3][32] = { + {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, + {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, + {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} + }; + + secp256k1_rfc6979_hmac_sha256 rng; + unsigned char out[32]; + int i; + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) != 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out2[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); +} + +/***** RANDOM TESTS *****/ + +void test_rand_bits(int rand32, int bits) { + /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to + * get a false negative chance below once in a billion */ + static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; + /* We try multiplying the results with various odd numbers, which shouldn't + * influence the uniform distribution modulo a power of 2. */ + static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; + /* We only select up to 6 bits from the output to analyse */ + unsigned int usebits = bits > 6 ? 6 : bits; + unsigned int maxshift = bits - usebits; + /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit + number, track all observed outcomes, one per bit in a uint64_t. */ + uint64_t x[6][27] = {{0}}; + unsigned int i, shift, m; + /* Multiply the output of all rand calls with the odd number m, which + should not change the uniformity of its distribution. */ + for (i = 0; i < rounds[usebits]; i++) { + uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); + CHECK((((uint64_t)r) >> bits) == 0); + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + uint32_t rm = r * mults[m]; + for (shift = 0; shift <= maxshift; shift++) { + x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); + } + } + } + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + for (shift = 0; shift <= maxshift; shift++) { + /* Test that the lower usebits bits of x[shift] are 1 */ + CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + } + } +} + +/* Subrange must be a whole divisor of range, and at most 64 */ +void test_rand_int(uint32_t range, uint32_t subrange) { + /* (1-1/subrange)^rounds < 1/10^9 */ + int rounds = (subrange * 2073) / 100; + int i; + uint64_t x = 0; + CHECK((range % subrange) == 0); + for (i = 0; i < rounds; i++) { + uint32_t r = secp256k1_rand_int(range); + CHECK(r < range); + r = r % subrange; + x |= (((uint64_t)1) << r); + } + /* Test that the lower subrange bits of x are 1. */ + CHECK(((~x) << (64 - subrange)) == 0); +} + +void run_rand_bits(void) { + size_t b; + test_rand_bits(1, 32); + for (b = 1; b <= 32; b++) { + test_rand_bits(0, b); + } +} + +void run_rand_int(void) { + static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; + static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; + unsigned int m, s; + for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { + for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { + test_rand_int(ms[m] * ss[s], ss[s]); + } + } +} + /***** NUM TESTS *****/ #ifndef USE_NUM_NONE -void random_num_negate(secp256k1_num_t *num) { - if (secp256k1_rand32() & 1) +void random_num_negate(secp256k1_num *num) { + if (secp256k1_rand_bits(1)) { secp256k1_num_negate(num); + } } -void random_num_order_test(secp256k1_num_t *num) { - secp256k1_scalar_t sc; +void random_num_order_test(secp256k1_num *num) { + secp256k1_scalar sc; random_scalar_order_test(&sc); secp256k1_scalar_get_num(num, &sc); } -void random_num_order(secp256k1_num_t *num) { - secp256k1_scalar_t sc; +void random_num_order(secp256k1_num *num) { + secp256k1_scalar sc; random_scalar_order(&sc); secp256k1_scalar_get_num(num, &sc); } void test_num_negate(void) { - secp256k1_num_t n1; - secp256k1_num_t n2; + secp256k1_num n1; + secp256k1_num n2; random_num_order_test(&n1); /* n1 = R */ random_num_negate(&n1); secp256k1_num_copy(&n2, &n1); /* n2 = R */ @@ -130,18 +526,19 @@ void test_num_negate(void) { } void test_num_add_sub(void) { - int r = secp256k1_rand32(); - secp256k1_num_t n1; - secp256k1_num_t n2; + int i; + secp256k1_scalar s; + secp256k1_num n1; + secp256k1_num n2; + secp256k1_num n1p2, n2p1, n1m2, n2m1; random_num_order_test(&n1); /* n1 = R1 */ - if (r & 1) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n1); } random_num_order_test(&n2); /* n2 = R2 */ - if (r & 2) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n2); } - secp256k1_num_t n1p2, n2p1, n1m2, n2m1; secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */ secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */ @@ -156,12 +553,119 @@ void test_num_add_sub(void) { CHECK(!secp256k1_num_eq(&n2p1, &n1)); secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ CHECK(secp256k1_num_eq(&n2p1, &n1)); + + /* check is_one */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&n1, &s); + CHECK(secp256k1_num_is_one(&n1)); + /* check that 2^n + 1 is never 1 */ + secp256k1_scalar_get_num(&n2, &s); + for (i = 0; i < 250; ++i) { + secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */ + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ + CHECK(!secp256k1_num_is_one(&n1p2)); + } +} + +void test_num_mod(void) { + int i; + secp256k1_scalar s; + secp256k1_num order, n; + + /* check that 0 mod anything is 0 */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_set_int(&s, 0); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that anything mod 1 is 0 */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that increasing the number past 2^256 does not break this */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&n, &s); + /* multiply by 2^8, which'll test this case with high probability */ + for (i = 0; i < 8; ++i) { + secp256k1_num_add(&n, &n, &n); + } + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); +} + +void test_num_jacobi(void) { + secp256k1_scalar sqr; + secp256k1_scalar small; + secp256k1_scalar five; /* five is not a quadratic residue */ + secp256k1_num order, n; + int i; + /* squares mod 5 are 1, 4 */ + const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + + /* check some small values with 5 as the order */ + secp256k1_scalar_set_int(&five, 5); + secp256k1_scalar_get_num(&order, &five); + for (i = 0; i < 10; ++i) { + secp256k1_scalar_set_int(&small, i); + secp256k1_scalar_get_num(&n, &small); + CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]); + } + + /** test large values with 5 as group order */ + secp256k1_scalar_get_num(&order, &five); + /* we first need a scalar which is not a multiple of 5 */ + do { + secp256k1_num fiven; + random_scalar_order_test(&sqr); + secp256k1_scalar_get_num(&fiven, &five); + secp256k1_scalar_get_num(&n, &sqr); + secp256k1_num_mod(&n, &fiven); + } while (secp256k1_num_is_zero(&n)); + /* next force it to be a residue. 2 is a nonresidue mod 5 so we can + * just multiply by two, i.e. add the number to itself */ + if (secp256k1_num_jacobi(&n, &order) == -1) { + secp256k1_num_add(&n, &n, &n); + } + + /* test residue */ + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_num_add(&n, &n, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + + /** test with secp group order as order */ + secp256k1_scalar_order_get_num(&order); + random_scalar_order_test(&sqr); + secp256k1_scalar_sqr(&sqr, &sqr); + /* test residue */ + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_scalar_mul(&sqr, &sqr, &five); + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + /* test multiple of the order*/ + CHECK(secp256k1_num_jacobi(&order, &order) == 0); + + /* check one less than the order */ + secp256k1_scalar_set_int(&small, 1); + secp256k1_scalar_get_num(&n, &small); + secp256k1_num_sub(&n, &order, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ } void run_num_smalltests(void) { - for (int i=0; i<100*count; i++) { + int i; + for (i = 0; i < 100*count; i++) { test_num_negate(); test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); } } #endif @@ -169,41 +673,45 @@ void run_num_smalltests(void) { /***** SCALAR TESTS *****/ void scalar_test(void) { + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; +#ifndef USE_NUM_NONE + secp256k1_num snum, s1num, s2num; + secp256k1_num order, half_order; +#endif unsigned char c[32]; /* Set 's' to a random scalar, with value 'snum'. */ - secp256k1_scalar_t s; random_scalar_order_test(&s); /* Set 's1' to a random scalar, with value 's1num'. */ - secp256k1_scalar_t s1; random_scalar_order_test(&s1); /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ - secp256k1_scalar_t s2; random_scalar_order_test(&s2); secp256k1_scalar_get_b32(c, &s2); #ifndef USE_NUM_NONE - secp256k1_num_t snum, s1num, s2num; secp256k1_scalar_get_num(&snum, &s); secp256k1_scalar_get_num(&s1num, &s1); secp256k1_scalar_get_num(&s2num, &s2); - secp256k1_num_t order; secp256k1_scalar_order_get_num(&order); - secp256k1_num_t half_order = order; + half_order = order; secp256k1_num_shift(&half_order, 1); #endif { + int i; /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar_t n; + secp256k1_scalar n; secp256k1_scalar_set_int(&n, 0); - for (int i = 0; i < 256; i += 4) { - secp256k1_scalar_t t; + for (i = 0; i < 256; i += 4) { + secp256k1_scalar t; + int j; secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); - for (int j = 0; j < 4; j++) { + for (j = 0; j < 4; j++) { secp256k1_scalar_add(&n, &n, &n); } secp256k1_scalar_add(&n, &n, &t); @@ -213,17 +721,18 @@ void scalar_test(void) { { /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar_t n; - secp256k1_scalar_set_int(&n, 0); + secp256k1_scalar n; int i = 0; + secp256k1_scalar_set_int(&n, 0); while (i < 256) { - int now = (secp256k1_rand32() % 15) + 1; + secp256k1_scalar t; + int j; + int now = secp256k1_rand_int(15) + 1; if (now + i > 256) { now = 256 - i; } - secp256k1_scalar_t t; secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now)); - for (int j = 0; j < now; j++) { + for (j = 0; j < now; j++) { secp256k1_scalar_add(&n, &n, &n); } secp256k1_scalar_add(&n, &n, &t); @@ -235,24 +744,24 @@ void scalar_test(void) { #ifndef USE_NUM_NONE { /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ - secp256k1_num_t rnum; + secp256k1_num rnum; + secp256k1_num r2num; + secp256k1_scalar r; secp256k1_num_add(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); - secp256k1_scalar_t r; secp256k1_scalar_add(&r, &s, &s2); - secp256k1_num_t r2num; secp256k1_scalar_get_num(&r2num, &r); CHECK(secp256k1_num_eq(&rnum, &r2num)); } { - /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ - secp256k1_num_t rnum; + /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ + secp256k1_scalar r; + secp256k1_num r2num; + secp256k1_num rnum; secp256k1_num_mul(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); - secp256k1_scalar_t r; secp256k1_scalar_mul(&r, &s, &s2); - secp256k1_num_t r2num; secp256k1_scalar_get_num(&r2num, &r); CHECK(secp256k1_num_eq(&rnum, &r2num)); /* The result can only be zero if at least one of the factors was zero. */ @@ -263,20 +772,20 @@ void scalar_test(void) { } { + secp256k1_scalar neg; + secp256k1_num negnum; + secp256k1_num negnum2; /* Check that comparison with zero matches comparison with zero on the number. */ CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); /* Check that comparison with the half order is equal to testing for high scalar. */ CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0)); - secp256k1_scalar_t neg; secp256k1_scalar_negate(&neg, &s); - secp256k1_num_t negnum; secp256k1_num_sub(&negnum, &order, &snum); secp256k1_num_mod(&negnum, &order); /* Check that comparison with the half order is equal to testing for high scalar after negation. */ CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0)); /* Negating should change the high property, unless the value was already zero. */ CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s)); - secp256k1_num_t negnum2; secp256k1_scalar_get_num(&negnum2, &neg); /* Negating a scalar should be equal to (order - n) mod order on the number. */ CHECK(secp256k1_num_eq(&negnum, &negnum2)); @@ -290,32 +799,48 @@ void scalar_test(void) { { /* Test secp256k1_scalar_mul_shift_var. */ - secp256k1_scalar_t r; - unsigned int shift = 256 + (secp256k1_rand32() % 257); + secp256k1_scalar r; + secp256k1_num one; + secp256k1_num rnum; + secp256k1_num rnum2; + unsigned char cone[1] = {0x01}; + unsigned int shift = 256 + secp256k1_rand_int(257); secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); - secp256k1_num_t rnum; secp256k1_num_mul(&rnum, &s1num, &s2num); secp256k1_num_shift(&rnum, shift - 1); - secp256k1_num_t one; - unsigned char cone[1] = {0x01}; secp256k1_num_set_bin(&one, cone, 1); secp256k1_num_add(&rnum, &rnum, &one); secp256k1_num_shift(&rnum, 1); - secp256k1_num_t rnum2; secp256k1_scalar_get_num(&rnum2, &r); CHECK(secp256k1_num_eq(&rnum, &rnum2)); } + + { + /* test secp256k1_scalar_shr_int */ + secp256k1_scalar r; + int i; + random_scalar_order_test(&r); + for (i = 0; i < 100; ++i) { + int low; + int shift = 1 + secp256k1_rand_int(15); + int expected = r.d[0] % (1 << shift); + low = secp256k1_scalar_shr_int(&r, shift); + CHECK(expected == low); + } + } #endif { /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ if (!secp256k1_scalar_is_zero(&s)) { - secp256k1_scalar_t inv; + secp256k1_scalar inv; +#ifndef USE_NUM_NONE + secp256k1_num invnum; + secp256k1_num invnum2; +#endif secp256k1_scalar_inverse(&inv, &s); #ifndef USE_NUM_NONE - secp256k1_num_t invnum; secp256k1_num_mod_inverse(&invnum, &snum, &order); - secp256k1_num_t invnum2; secp256k1_scalar_get_num(&invnum2, &inv); CHECK(secp256k1_num_eq(&invnum, &invnum2)); #endif @@ -325,37 +850,47 @@ void scalar_test(void) { secp256k1_scalar_inverse(&inv, &inv); /* Inverting one must result in one. */ CHECK(secp256k1_scalar_is_one(&inv)); +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_num_is_one(&invnum)); +#endif } } { /* Test commutativity of add. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_add(&r2, &s2, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); } { + secp256k1_scalar r1, r2; + secp256k1_scalar b; + int i; /* Test add_bit. */ - int bit = secp256k1_rand32() % 256; - secp256k1_scalar_t b; + int bit = secp256k1_rand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); - for (int i = 0; i < bit; i++) { + for (i = 0; i < bit; i++) { secp256k1_scalar_add(&b, &b, &b); } - secp256k1_scalar_t r1 = s1, r2 = s1; + r1 = s1; + r2 = s1; if (!secp256k1_scalar_add(&r1, &r1, &b)) { /* No overflow happened. */ - secp256k1_scalar_add_bit(&r2, bit); + secp256k1_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_scalar_cadd_bit(&r2, bit, 0); CHECK(secp256k1_scalar_eq(&r1, &r2)); } } { /* Test commutativity of mul. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_mul(&r1, &s1, &s2); secp256k1_scalar_mul(&r2, &s2, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); @@ -363,7 +898,7 @@ void scalar_test(void) { { /* Test associativity of add. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_add(&r1, &r1, &s); secp256k1_scalar_add(&r2, &s2, &s); @@ -373,7 +908,7 @@ void scalar_test(void) { { /* Test associativity of mul. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_mul(&r1, &s1, &s2); secp256k1_scalar_mul(&r1, &r1, &s); secp256k1_scalar_mul(&r2, &s2, &s); @@ -383,7 +918,7 @@ void scalar_test(void) { { /* Test distributitivity of mul over add. */ - secp256k1_scalar_t r1, r2, t; + secp256k1_scalar r1, r2, t; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_mul(&r1, &r1, &s); secp256k1_scalar_mul(&r2, &s1, &s); @@ -394,47 +929,669 @@ void scalar_test(void) { { /* Test square. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_sqr(&r1, &s1); secp256k1_scalar_mul(&r2, &s1, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); } + { + /* Test multiplicative identity. */ + secp256k1_scalar r1, v1; + secp256k1_scalar_set_int(&v1,1); + secp256k1_scalar_mul(&r1, &s1, &v1); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test additive identity. */ + secp256k1_scalar r1, v0; + secp256k1_scalar_set_int(&v0,0); + secp256k1_scalar_add(&r1, &s1, &v0); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test zero product property. */ + secp256k1_scalar r1, v0; + secp256k1_scalar_set_int(&v0,0); + secp256k1_scalar_mul(&r1, &s1, &v0); + CHECK(secp256k1_scalar_eq(&r1, &v0)); + } + } void run_scalar_tests(void) { - for (int i = 0; i < 128 * count; i++) { + int i; + for (i = 0; i < 128 * count; i++) { scalar_test(); } { /* (-1)+1 should be zero. */ - secp256k1_scalar_t s, o; + secp256k1_scalar s, o; secp256k1_scalar_set_int(&s, 1); + CHECK(secp256k1_scalar_is_one(&s)); secp256k1_scalar_negate(&o, &s); secp256k1_scalar_add(&o, &o, &s); CHECK(secp256k1_scalar_is_zero(&o)); + secp256k1_scalar_negate(&o, &o); + CHECK(secp256k1_scalar_is_zero(&o)); } #ifndef USE_NUM_NONE { /* A scalar with value of the curve order should be 0. */ - secp256k1_num_t order; - secp256k1_scalar_order_get_num(&order); + secp256k1_num order; + secp256k1_scalar zero; unsigned char bin[32]; - secp256k1_num_get_bin(bin, 32, &order); - secp256k1_scalar_t zero; int overflow = 0; + secp256k1_scalar_order_get_num(&order); + secp256k1_num_get_bin(bin, 32, &order); secp256k1_scalar_set_b32(&zero, bin, &overflow); CHECK(overflow == 1); CHECK(secp256k1_scalar_is_zero(&zero)); } #endif + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_scalar x; + secp256k1_scalar y; + secp256k1_scalar z; + secp256k1_scalar zz; + secp256k1_scalar one; + secp256k1_scalar r1; + secp256k1_scalar r2; +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar zzv; +#endif + int overflow; + unsigned char chal[33][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} + }; + unsigned char res[33][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} + }; + secp256k1_scalar_set_int(&one, 1); + for (i = 0; i < 33; i++) { + secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_mul(&z, &x, &y); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&r1, &z)); + if (!secp256k1_scalar_is_zero(&y)) { + secp256k1_scalar_inverse(&zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_scalar_eq(&zzv, &zz)); +#endif + secp256k1_scalar_mul(&z, &z, &zz); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&x, &z)); + secp256k1_scalar_mul(&zz, &zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&one, &zz)); + } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_scalar_check_overflow(&z)); + secp256k1_scalar_sqr(&zz, &x); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&zz, &z)); + CHECK(secp256k1_scalar_eq(&r2, &zz)); + } + } } /***** FIELD TESTS *****/ -void random_fe(secp256k1_fe_t *x) { +void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_rand256(bin); @@ -444,41 +1601,167 @@ void random_fe(secp256k1_fe_t *x) { } while(1); } -void random_fe_non_zero(secp256k1_fe_t *nz) { +void random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256_test(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_non_zero(secp256k1_fe *nz) { int tries = 10; while (--tries >= 0) { random_fe(nz); secp256k1_fe_normalize(nz); - if (!secp256k1_fe_is_zero(nz)) + if (!secp256k1_fe_is_zero(nz)) { break; + } } /* Infinitesimal probability of spurious failure here */ CHECK(tries >= 0); } -void random_fe_non_square(secp256k1_fe_t *ns) { +void random_fe_non_square(secp256k1_fe *ns) { + secp256k1_fe r; random_fe_non_zero(ns); - secp256k1_fe_t r; if (secp256k1_fe_sqrt(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } } -int check_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t an = *a; secp256k1_fe_normalize(&an); - secp256k1_fe_t bn = *b; secp256k1_fe_normalize(&bn); - return secp256k1_fe_equal(&an, &bn); +int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe an = *a; + secp256k1_fe bn = *b; + secp256k1_fe_normalize_weak(&an); + secp256k1_fe_normalize_var(&bn); + return secp256k1_fe_equal_var(&an, &bn); } -int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) { - secp256k1_fe_t x; secp256k1_fe_mul(&x, a, ai); - secp256k1_fe_t one; secp256k1_fe_set_int(&one, 1); +int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) { + secp256k1_fe x; + secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe_mul(&x, a, ai); return check_fe_equal(&x, &one); } +void run_field_convert(void) { + static const unsigned char b32[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 + }; + static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + static const secp256k1_fe fe = SECP256K1_FE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + secp256k1_fe fe2; + unsigned char b322[32]; + secp256k1_fe_storage fes2; + /* Check conversions to fe. */ + CHECK(secp256k1_fe_set_b32(&fe2, b32)); + CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + secp256k1_fe_from_storage(&fe2, &fes); + CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + /* Check conversion from fe. */ + secp256k1_fe_get_b32(b322, &fe); + CHECK(memcmp(b322, b32, 32) == 0); + secp256k1_fe_to_storage(&fes2, &fe); + CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); +} + +int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe t = *b; +#ifdef VERIFY + t.magnitude = a->magnitude; + t.normalized = a->normalized; +#endif + return memcmp(a, &t, sizeof(secp256k1_fe)); +} + +void run_field_misc(void) { + secp256k1_fe x; + secp256k1_fe y; + secp256k1_fe z; + secp256k1_fe q; + secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i, j; + for (i = 0; i < 5*count; i++) { + secp256k1_fe_storage xs, ys, zs; + random_fe(&x); + random_fe_non_zero(&y); + /* Test the fe equality and comparison operations. */ + CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); + CHECK(secp256k1_fe_equal_var(&x, &x)); + z = x; + secp256k1_fe_add(&z,&y); + /* Test fe conditional move; z is not normalized here. */ + q = x; + secp256k1_fe_cmov(&x, &z, 0); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); + secp256k1_fe_cmov(&x, &x, 1); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); + secp256k1_fe_cmov(&q, &z, 1); + VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(fe_memcmp(&q, &z) == 0); + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&z); + CHECK(!secp256k1_fe_equal_var(&x, &z)); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (i&1)); + VERIFY_CHECK(q.normalized && q.magnitude == 1); + for (j = 0; j < 6; j++) { + secp256k1_fe_negate(&z, &z, j+1); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (j&1)); + VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); + } + secp256k1_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ + secp256k1_fe_to_storage(&xs, &x); + secp256k1_fe_to_storage(&ys, &y); + secp256k1_fe_to_storage(&zs, &z); + secp256k1_fe_storage_cmov(&zs, &xs, 0); + secp256k1_fe_storage_cmov(&zs, &zs, 1); + CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); + secp256k1_fe_storage_cmov(&ys, &xs, 1); + CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); + secp256k1_fe_from_storage(&x, &xs); + secp256k1_fe_from_storage(&y, &ys); + secp256k1_fe_from_storage(&z, &zs); + /* Test that mul_int, mul, and add agree. */ + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&y, &x); + z = x; + secp256k1_fe_mul_int(&z, 3); + CHECK(check_fe_equal(&y, &z)); + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&z, &x); + CHECK(check_fe_equal(&z, &y)); + z = x; + secp256k1_fe_mul_int(&z, 5); + secp256k1_fe_mul(&q, &x, &fe5); + CHECK(check_fe_equal(&z, &q)); + secp256k1_fe_negate(&x, &x, 1); + secp256k1_fe_add(&z, &x); + secp256k1_fe_add(&q, &x); + CHECK(check_fe_equal(&y, &z)); + CHECK(check_fe_equal(&q, &y)); + } +} + void run_field_inv(void) { - secp256k1_fe_t x, xi, xii; - for (int i=0; i<10*count; i++) { + secp256k1_fe x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); secp256k1_fe_inv(&xi, &x); CHECK(check_fe_inverse(&x, &xi)); @@ -488,8 +1771,9 @@ void run_field_inv(void) { } void run_field_inv_var(void) { - secp256k1_fe_t x, xi, xii; - for (int i=0; i<10*count; i++) { + secp256k1_fe x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); secp256k1_fe_inv_var(&xi, &x); CHECK(check_fe_inverse(&x, &xi)); @@ -498,48 +1782,37 @@ void run_field_inv_var(void) { } } -void run_field_inv_all(void) { - secp256k1_fe_t x[16], xi[16], xii[16]; - /* Check it's safe to call for 0 elements */ - secp256k1_fe_inv_all(0, xi, x); - for (int i=0; iinfinity && b->infinity) - return 1; - return check_fe_equal(&a->x, &b->x) && check_fe_equal(&a->y, &b->y); +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); } -void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { - secp256k1_ge_t bb; - secp256k1_gej_t bj = *b; - secp256k1_ge_set_gej_var(&bb, &bj); - CHECK(ge_equals_ge(a, &bb)); +/* This compares jacobian points including their Z, not just their geometric meaning. */ +int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej a2; + secp256k1_gej b2; + int ret = 1; + ret &= a->infinity == b->infinity; + if (ret && !a->infinity) { + a2 = *a; + b2 = *b; + secp256k1_fe_normalize(&a2.x); + secp256k1_fe_normalize(&a2.y); + secp256k1_fe_normalize(&a2.z); + secp256k1_fe_normalize(&b2.x); + secp256k1_fe_normalize(&b2.y); + secp256k1_fe_normalize(&b2.z); + ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; + } + return ret; } -void gej_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { - secp256k1_ge_t aa, bb; - secp256k1_gej_t aj = *a, bj = *b; - secp256k1_ge_set_gej_var(&aa, &aj); - secp256k1_ge_set_gej_var(&bb, &bj); - CHECK(ge_equals_ge(&aa, &bb)); +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); } void test_ge(void) { - char ca[135]; - char cb[68]; - int rlen; - secp256k1_ge_t a, b, i, n; - random_group_element_test(&a); - random_group_element_test(&b); - rlen = sizeof(ca); - secp256k1_ge_get_hex(ca,&rlen,&a); - CHECK(rlen > 4 && rlen <= (int)sizeof(ca)); - rlen = sizeof(cb); - secp256k1_ge_get_hex(cb,&rlen,&b); /* Intentionally undersized buffer. */ - n = a; - secp256k1_fe_normalize(&a.y); - secp256k1_fe_negate(&n.y, &a.y, 1); - secp256k1_ge_set_infinity(&i); - random_field_element_magnitude(&a.x); - random_field_element_magnitude(&a.y); - random_field_element_magnitude(&b.x); - random_field_element_magnitude(&b.y); - random_field_element_magnitude(&n.x); - random_field_element_magnitude(&n.y); - - secp256k1_gej_t aj, bj, ij, nj; - random_group_element_jacobian_test(&aj, &a); - random_group_element_jacobian_test(&bj, &b); - secp256k1_gej_set_infinity(&ij); - random_group_element_jacobian_test(&nj, &n); - random_field_element_magnitude(&aj.x); - random_field_element_magnitude(&aj.y); - random_field_element_magnitude(&aj.z); - random_field_element_magnitude(&bj.x); - random_field_element_magnitude(&bj.y); - random_field_element_magnitude(&bj.z); - random_field_element_magnitude(&nj.x); - random_field_element_magnitude(&nj.y); - random_field_element_magnitude(&nj.z); - - /* gej + gej adds */ - secp256k1_gej_t aaj; secp256k1_gej_add_var(&aaj, &aj, &aj); - secp256k1_gej_t abj; secp256k1_gej_add_var(&abj, &aj, &bj); - secp256k1_gej_t aij; secp256k1_gej_add_var(&aij, &aj, &ij); - secp256k1_gej_t anj; secp256k1_gej_add_var(&anj, &aj, &nj); - secp256k1_gej_t iaj; secp256k1_gej_add_var(&iaj, &ij, &aj); - secp256k1_gej_t iij; secp256k1_gej_add_var(&iij, &ij, &ij); - - /* gej + ge adds */ - secp256k1_gej_t aa; secp256k1_gej_add_ge_var(&aa, &aj, &a); - secp256k1_gej_t ab; secp256k1_gej_add_ge_var(&ab, &aj, &b); - secp256k1_gej_t ai; secp256k1_gej_add_ge_var(&ai, &aj, &i); - secp256k1_gej_t an; secp256k1_gej_add_ge_var(&an, &aj, &n); - secp256k1_gej_t ia; secp256k1_gej_add_ge_var(&ia, &ij, &a); - secp256k1_gej_t ii; secp256k1_gej_add_ge_var(&ii, &ij, &i); - - /* const gej + ge adds */ - secp256k1_gej_t aac; secp256k1_gej_add_ge(&aac, &aj, &a); - secp256k1_gej_t abc; secp256k1_gej_add_ge(&abc, &aj, &b); - secp256k1_gej_t anc; secp256k1_gej_add_ge(&anc, &aj, &n); - secp256k1_gej_t iac; secp256k1_gej_add_ge(&iac, &ij, &a); - - CHECK(secp256k1_gej_is_infinity(&an)); - CHECK(secp256k1_gej_is_infinity(&anj)); - CHECK(secp256k1_gej_is_infinity(&anc)); - gej_equals_gej(&aa, &aaj); - gej_equals_gej(&aa, &aac); - gej_equals_gej(&ab, &abj); - gej_equals_gej(&ab, &abc); - gej_equals_gej(&an, &anj); - gej_equals_gej(&an, &anc); - gej_equals_gej(&ia, &iaj); - gej_equals_gej(&ai, &aij); - gej_equals_gej(&ii, &iij); - ge_equals_gej(&a, &ai); - ge_equals_gej(&a, &ai); - ge_equals_gej(&a, &iaj); - ge_equals_gej(&a, &iaj); - ge_equals_gej(&a, &iac); -} + int i, i1; +#ifdef USE_ENDOMORPHISM + int runs = 6; +#else + int runs = 4; +#endif + /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). + * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. + * All magnitudes are randomized. + * All 17*17 combinations of points are added to each other, using all applicable methods. + * + * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. + */ + secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs)); + secp256k1_fe zf; + secp256k1_fe zfi2, zfi3; -void run_ge(void) { - for (int i = 0; i < 2000*count; i++) { - test_ge(); + secp256k1_gej_set_infinity(&gej[0]); + secp256k1_ge_clear(&ge[0]); + secp256k1_ge_set_gej_var(&ge[0], &gej[0]); + for (i = 0; i < runs; i++) { + int j; + secp256k1_ge g; + random_group_element_test(&g); +#ifdef USE_ENDOMORPHISM + if (i >= runs - 2) { + secp256k1_ge_mul_lambda(&g, &ge[1]); + } + if (i >= runs - 1) { + secp256k1_ge_mul_lambda(&g, &g); + } +#endif + ge[1 + 4 * i] = g; + ge[2 + 4 * i] = g; + secp256k1_ge_neg(&ge[3 + 4 * i], &g); + secp256k1_ge_neg(&ge[4 + 4 * i], &g); + secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + for (j = 0; j < 4; j++) { + random_field_element_magnitude(&ge[1 + j + 4 * i].x); + random_field_element_magnitude(&ge[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].x); + random_field_element_magnitude(&gej[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].z); + } } -} -/***** ECMULT TESTS *****/ + /* Compute z inverses. */ + { + secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs)); + for (i = 0; i < 4 * runs + 1; i++) { + if (i == 0) { + /* The point at infinity does not have a meaningful z inverse. Any should do. */ + do { + random_field_element_test(&zs[i]); + } while(secp256k1_fe_is_zero(&zs[i])); + } else { + zs[i] = gej[i].z; + } + } + secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1); + free(zs); + } -void run_ecmult_chain(void) { - /* random starting point A (on the curve) */ - secp256k1_fe_t ax; VERIFY_CHECK(secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64)); - secp256k1_fe_t ay; VERIFY_CHECK(secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64)); - secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay); - /* two random initial factors xn and gn */ - static const unsigned char xni[32] = { - 0x84, 0xcc, 0x54, 0x52, 0xf7, 0xfd, 0xe1, 0xed, - 0xb4, 0xd3, 0x8a, 0x8c, 0xe9, 0xb1, 0xb8, 0x4c, - 0xce, 0xf3, 0x1f, 0x14, 0x6e, 0x56, 0x9b, 0xe9, - 0x70, 0x5d, 0x35, 0x7a, 0x42, 0x98, 0x54, 0x07 - }; - secp256k1_scalar_t xn; - secp256k1_scalar_set_b32(&xn, xni, NULL); - static const unsigned char gni[32] = { - 0xa1, 0xe5, 0x8d, 0x22, 0x55, 0x3d, 0xcd, 0x42, - 0xb2, 0x39, 0x80, 0x62, 0x5d, 0x4c, 0x57, 0xa9, - 0x6e, 0x93, 0x23, 0xd4, 0x2b, 0x31, 0x52, 0xe5, - 0xca, 0x2c, 0x39, 0x90, 0xed, 0xc7, 0xc9, 0xde - }; - secp256k1_scalar_t gn; - secp256k1_scalar_set_b32(&gn, gni, NULL); - /* two small multipliers to be applied to xn and gn in every iteration: */ - static const unsigned char xfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x13,0x37}; - secp256k1_scalar_t xf; - secp256k1_scalar_set_b32(&xf, xfi, NULL); - static const unsigned char gfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x71,0x13}; - secp256k1_scalar_t gf; - secp256k1_scalar_set_b32(&gf, gfi, NULL); - /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar_t ae; - secp256k1_scalar_set_int(&ae, 1); - secp256k1_scalar_t ge; - secp256k1_scalar_set_int(&ge, 0); - /* the point being computed */ - secp256k1_gej_t x = a; - for (int i=0; i<200*count; i++) { - /* in each iteration, compute X = xn*X + gn*G; */ - secp256k1_ecmult(&x, &x, &xn, &gn); - /* also compute ae and ge: the actual accumulated factors for A and G */ - /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ - secp256k1_scalar_mul(&ae, &ae, &xn); - secp256k1_scalar_mul(&ge, &ge, &xn); - secp256k1_scalar_add(&ge, &ge, &gn); - /* modify xn and gn */ - secp256k1_scalar_mul(&xn, &xn, &xf); - secp256k1_scalar_mul(&gn, &gn, &gf); + /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ + do { + random_field_element_test(&zf); + } while(secp256k1_fe_is_zero(&zf)); + random_field_element_magnitude(&zf); + secp256k1_fe_inv_var(&zfi3, &zf); + secp256k1_fe_sqr(&zfi2, &zfi3); + secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); - /* verify */ - if (i == 51474) { - char res[132]; int resl = 132; - secp256k1_gej_get_hex(res, &resl, &x); - CHECK(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0); + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { + int i2; + for (i2 = 0; i2 < 1 + 4 * runs; i2++) { + /* Compute reference result using gej + gej (var). */ + secp256k1_gej refj, resj; + secp256k1_ge ref; + secp256k1_fe zr; + secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + /* Check Z ratio. */ + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); + } + secp256k1_ge_set_gej_var(&ref, &refj); + + /* Test gej + ge with Z ratio result (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + ge_equals_gej(&ref, &resj); + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); + } + + /* Test gej + ge (var, with additional Z factor). */ + { + secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + random_field_element_magnitude(&ge2_zfi.x); + random_field_element_magnitude(&ge2_zfi.y); + secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + ge_equals_gej(&ref, &resj); + } + + /* Test gej + ge (const). */ + if (i2 != 0) { + /* secp256k1_gej_add_ge does not support its second argument being infinity. */ + secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test doubling (var). */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); + ge_equals_gej(&ref, &resj); + /* Check Z ratio. */ + secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i2], NULL); + ge_equals_gej(&ref, &resj); + } + + /* Test adding opposites. */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { + CHECK(secp256k1_ge_is_infinity(&ref)); + } + + /* Test adding infinity. */ + if (i1 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i1])); + CHECK(secp256k1_gej_is_infinity(&gej[i1])); + ge_equals_gej(&ref, &gej[i2]); + } + if (i2 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i2])); + CHECK(secp256k1_gej_is_infinity(&gej[i2])); + ge_equals_gej(&ref, &gej[i1]); + } } } - /* redo the computation, but directly with the resulting ae and ge coefficients: */ - secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge); - char res[132]; int resl = 132; - char res2[132]; int resl2 = 132; - secp256k1_gej_get_hex(res, &resl, &x); - secp256k1_gej_get_hex(res2, &resl2, &x2); - CHECK(strcmp(res, res2) == 0); - CHECK(strlen(res) == 131); -} -void test_point_times_order(const secp256k1_gej_t *point) { - /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - secp256k1_scalar_t x; - random_scalar_order_test(&x); - secp256k1_scalar_t nx; - secp256k1_scalar_negate(&nx, &x); - secp256k1_gej_t res1, res2; - secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ - secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ - secp256k1_gej_add_var(&res1, &res1, &res2); - CHECK(secp256k1_gej_is_infinity(&res1)); - CHECK(secp256k1_gej_is_valid(&res1) == 0); - secp256k1_ge_t res3; - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_ge_is_infinity(&res3)); - CHECK(secp256k1_ge_is_valid(&res3) == 0); -} + /* Test adding all points together in random order equals infinity. */ + { + secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); + for (i = 0; i < 4 * runs + 1; i++) { + gej_shuffled[i] = gej[i]; + } + for (i = 0; i < 4 * runs + 1; i++) { + int swap = i + secp256k1_rand_int(4 * runs + 1 - i); + if (swap != i) { + secp256k1_gej t = gej_shuffled[i]; + gej_shuffled[i] = gej_shuffled[swap]; + gej_shuffled[swap] = t; + } + } + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); + } + CHECK(secp256k1_gej_is_infinity(&sum)); + free(gej_shuffled); + } -void run_point_times_order(void) { - secp256k1_fe_t x; VERIFY_CHECK(secp256k1_fe_set_hex(&x, "02", 2)); - for (int i=0; i<500; i++) { - secp256k1_ge_t p; - if (secp256k1_ge_set_xo(&p, &x, 1)) { - CHECK(secp256k1_ge_is_valid(&p)); - secp256k1_gej_t j; - secp256k1_gej_set_ge(&j, &p); - CHECK(secp256k1_gej_is_valid(&j)); - test_point_times_order(&j); + /* Test batch gej -> ge conversion with and without known z ratios. */ + { + secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe)); + secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + for (i = 0; i < 4 * runs + 1; i++) { + /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ + if (i < 4 * runs) { + secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); + } } - secp256k1_fe_sqr(&x, &x); + secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1); + secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe s; + random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); + ge_equals_gej(&ge_set_table[i], &gej[i]); + ge_equals_gej(&ge_set_all[i], &gej[i]); + } + free(ge_set_table); + free(ge_set_all); + free(zr); } - char c[65]; int cl=65; - secp256k1_fe_get_hex(c, &cl, &x); - CHECK(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0); + + free(ge); + free(gej); + free(zinv); } -void test_wnaf(const secp256k1_scalar_t *number, int w) { - secp256k1_scalar_t x, two, t; +void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. + * + * These points were generated in sage as + * # secp256k1 params + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (7)]) + * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) + * N = FiniteField(G.order()) + * + * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) + * x = polygen(N) + * lam = (1 - x^3).roots()[1][0] + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(lam) * P + * print " P: %x %x" % P.xy() + * print " Q: %x %x" % Q.xy() + * print "P + Q: %x %x" % (P + Q).xy() + */ + secp256k1_gej aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_gej bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_gej sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_ge b; + secp256k1_gej resj; + secp256k1_ge res; + secp256k1_ge_set_gej(&b, &bj); + + secp256k1_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge(&resj, &aj, &b); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); +} + +void run_ge(void) { + int i; + for (i = 0; i < count * 32; i++) { + test_ge(); + } + test_add_neg_y_diff_x(); +} + +void test_ec_combine(void) { + secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_pubkey data[6]; + const secp256k1_pubkey* d[6]; + secp256k1_pubkey sd; + secp256k1_pubkey sd2; + secp256k1_gej Qj; + secp256k1_ge Q; + int i; + for (i = 1; i <= 6; i++) { + secp256k1_scalar s; + random_scalar_order_test(&s); + secp256k1_scalar_add(&sum, &sum, &s); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&sd, &Q); + CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); + CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + } +} + +void run_ec_combine(void) { + int i; + for (i = 0; i < count * 8; i++) { + test_ec_combine(); + } +} + +void test_group_decompress(const secp256k1_fe* x) { + /* The input itself, normalized. */ + secp256k1_fe fex = *x; + secp256k1_fe fez; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_quad, ge_even, ge_odd; + secp256k1_gej gej_quad; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex); + res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_quad == res_even); + CHECK(res_quad == res_odd); + + if (res_quad) { + secp256k1_fe_normalize_var(&ge_quad.x); + secp256k1_fe_normalize_var(&ge_odd.x); + secp256k1_fe_normalize_var(&ge_even.x); + secp256k1_fe_normalize_var(&ge_quad.y); + secp256k1_fe_normalize_var(&ge_odd.y); + secp256k1_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_quad.infinity); + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + + /* Check that the Y coordinate result in ge_quad is a square. */ + CHECK(secp256k1_fe_is_quad_var(&ge_quad.y)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + + /* Check secp256k1_gej_has_quad_y_var. */ + secp256k1_gej_set_ge(&gej_quad, &ge_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + } +} + +void run_group_decompress(void) { + int i; + for (i = 0; i < count * 4; i++) { + secp256k1_fe fe; + random_fe_test(&fe); + test_group_decompress(&fe); + } +} + +/***** ECMULT TESTS *****/ + +void run_ecmult_chain(void) { + /* random starting point A (on the curve) */ + secp256k1_gej a = SECP256K1_GEJ_CONST( + 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, + 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, + 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, + 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f + ); + /* two random initial factors xn and gn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, + 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 + ); + secp256k1_scalar gn = SECP256K1_SCALAR_CONST( + 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, + 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de + ); + /* two small multipliers to be applied to xn and gn in every iteration: */ + static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + /* accumulators with the resulting coefficients to A and G */ + secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + /* actual points */ + secp256k1_gej x; + secp256k1_gej x2; + int i; + + /* the point being computed */ + x = a; + for (i = 0; i < 200*count; i++) { + /* in each iteration, compute X = xn*X + gn*G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); + /* also compute ae and ge: the actual accumulated factors for A and G */ + /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ + secp256k1_scalar_mul(&ae, &ae, &xn); + secp256k1_scalar_mul(&ge, &ge, &xn); + secp256k1_scalar_add(&ge, &ge, &gn); + /* modify xn and gn */ + secp256k1_scalar_mul(&xn, &xn, &xf); + secp256k1_scalar_mul(&gn, &gn, &gf); + + /* verify */ + if (i == 19999) { + /* expected result after 19999 iterations */ + secp256k1_gej rp = SECP256K1_GEJ_CONST( + 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, + 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, + 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, + 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 + ); + + secp256k1_gej_neg(&rp, &rp); + secp256k1_gej_add_var(&rp, &rp, &x, NULL); + CHECK(secp256k1_gej_is_infinity(&rp)); + } + } + /* redo the computation, but directly with the resulting ae and ge coefficients: */ + secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); + secp256k1_gej_neg(&x2, &x2); + secp256k1_gej_add_var(&x2, &x2, &x, NULL); + CHECK(secp256k1_gej_is_infinity(&x2)); +} + +void test_point_times_order(const secp256k1_gej *point) { + /* X * (point + G) + (order-X) * (pointer + G) = 0 */ + secp256k1_scalar x; + secp256k1_scalar nx; + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_gej res1, res2; + secp256k1_ge res3; + unsigned char pub[65]; + size_t psize = 65; + random_scalar_order_test(&x); + secp256k1_scalar_negate(&nx, &x); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); + CHECK(secp256k1_gej_is_infinity(&res1)); + CHECK(secp256k1_gej_is_valid_var(&res1) == 0); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + CHECK(secp256k1_ge_is_valid_var(&res3) == 0); + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); + psize = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + /* check zero/one edge cases */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_gej(&res3, point); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_ge(&res3, &secp256k1_ge_const_g); +} + +void run_point_times_order(void) { + int i; + secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_fe xr = SECP256K1_FE_CONST( + 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, + 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 + ); + for (i = 0; i < 500; i++) { + secp256k1_ge p; + if (secp256k1_ge_set_xo_var(&p, &x, 1)) { + secp256k1_gej j; + CHECK(secp256k1_ge_is_valid_var(&p)); + secp256k1_gej_set_ge(&j, &p); + CHECK(secp256k1_gej_is_valid_var(&j)); + test_point_times_order(&j); + } + secp256k1_fe_sqr(&x, &x); + } + secp256k1_fe_normalize_var(&x); + CHECK(secp256k1_fe_equal_var(&x, &xr)); +} + +void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_ge a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_ge expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_gej b; + secp256k1_ecmult_const(&b, &a, &xn, 256); + + CHECK(secp256k1_ge_is_valid_var(&a)); + ge_equals_gej(&expected_b, &b); +} + +void ecmult_const_commutativity(void) { + secp256k1_scalar a; + secp256k1_scalar b; + secp256k1_gej res1; + secp256k1_gej res2; + secp256k1_ge mid1; + secp256k1_ge mid2; + random_scalar_order_test(&a); + random_scalar_order_test(&b); + + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b, 256); + secp256k1_ecmult_const(&res2, &mid2, &a, 256); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + ge_equals_ge(&mid1, &mid2); +} + +void ecmult_const_mult_zero_one(void) { + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar negone; + secp256k1_gej res1; + secp256k1_ge res2; + secp256k1_ge point; + secp256k1_scalar_negate(&negone, &one); + + random_group_element_test(&point); + secp256k1_ecmult_const(&res1, &point, &zero, 3); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_is_infinity(&res2)); + secp256k1_ecmult_const(&res1, &point, &one, 2); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_ecmult_const(&res1, &point, &negone, 256); + secp256k1_gej_neg(&res1, &res1); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); +} + +void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_gej point; + secp256k1_ge res; + int i; + + secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_ge tmp; + secp256k1_ge_set_gej(&tmp, &point); + secp256k1_ecmult_const(&point, &tmp, &scalar, 256); + } + secp256k1_ge_set_gej(&res, &point); + ge_equals_gej(&res, &expected_point); +} + +void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); +} + +typedef struct { + secp256k1_scalar *sc; + secp256k1_ge *pt; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + (void)sc; + (void)pt; + (void)idx; + (void)cbdata; + return 0; +} + +void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) { + int ncount; + secp256k1_scalar szero; + secp256k1_scalar sc[32]; + secp256k1_ge pt[32]; + secp256k1_gej r; + secp256k1_gej r2; + ecmult_multi_data data; + secp256k1_scratch *scratch_empty; + + data.sc = sc; + data.pt = pt; + secp256k1_scalar_set_int(&szero, 0); + + /* No points to multiply */ + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); + + /* Check 1- and 2-point multiplies against ecmult */ + for (ncount = 0; ncount < count; ncount++) { + secp256k1_ge ptg; + secp256k1_gej ptgj; + random_scalar_order(&sc[0]); + random_scalar_order(&sc[1]); + + random_group_element_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + pt[0] = ptg; + pt[1] = secp256k1_ge_const_g; + + /* only G scalar */ + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); + secp256k1_gej_neg(&r2, &r2); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + + /* 1-point */ + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); + secp256k1_gej_neg(&r2, &r2); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + + /* Try to multiply 1 point, but scratch space is empty */ + scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0); + CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1)); + secp256k1_scratch_destroy(scratch_empty); + + /* Try to multiply 1 point, but callback returns false */ + CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); + + /* 2-point */ + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); + secp256k1_gej_neg(&r2, &r2); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + + /* 2-point with G scalar */ + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); + secp256k1_gej_neg(&r2, &r2); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + /* Check infinite outputs of various forms */ + for (ncount = 0; ncount < count; ncount++) { + secp256k1_ge ptg; + size_t i, j; + size_t sizes[] = { 2, 10, 32 }; + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + random_scalar_order(&sc[i]); + secp256k1_ge_set_infinity(&pt[i]); + } + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + random_group_element_test(&ptg); + pt[i] = ptg; + secp256k1_scalar_set_int(&sc[i], 0); + } + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + random_group_element_test(&ptg); + for (i = 0; i < 16; i++) { + random_scalar_order(&sc[2*i]); + secp256k1_scalar_negate(&sc[2*i + 1], &sc[2*i]); + pt[2 * i] = ptg; + pt[2 * i + 1] = ptg; + } + + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + + random_scalar_order(&sc[0]); + for (i = 0; i < 16; i++) { + random_group_element_test(&ptg); + + sc[2*i] = sc[0]; + sc[2*i+1] = sc[0]; + pt[2 * i] = ptg; + secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]); + } + + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + random_group_element_test(&ptg); + secp256k1_scalar_set_int(&sc[0], 0); + pt[0] = ptg; + for (i = 1; i < 32; i++) { + pt[i] = ptg; + + random_scalar_order(&sc[i]); + secp256k1_scalar_add(&sc[0], &sc[0], &sc[i]); + secp256k1_scalar_negate(&sc[i], &sc[i]); + } + + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32)); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + /* Check random points, constant scalar */ + for (ncount = 0; ncount < count; ncount++) { + size_t i; + secp256k1_gej_set_infinity(&r); + + random_scalar_order(&sc[0]); + for (i = 0; i < 20; i++) { + secp256k1_ge ptg; + sc[i] = sc[0]; + random_group_element_test(&ptg); + pt[i] = ptg; + secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL); + } + + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + secp256k1_gej_neg(&r2, &r2); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + /* Check random scalars, constant point */ + for (ncount = 0; ncount < count; ncount++) { + size_t i; + secp256k1_ge ptg; + secp256k1_gej p0j; + secp256k1_scalar rs; + secp256k1_scalar_set_int(&rs, 0); + + random_group_element_test(&ptg); + for (i = 0; i < 20; i++) { + random_scalar_order(&sc[i]); + pt[i] = ptg; + secp256k1_scalar_add(&rs, &rs, &sc[i]); + } + + secp256k1_gej_set_ge(&p0j, &pt[0]); + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + secp256k1_gej_neg(&r2, &r2); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + /* Sanity check that zero scalars don't cause problems */ + for (ncount = 0; ncount < 20; ncount++) { + random_scalar_order(&sc[ncount]); + random_group_element_test(&pt[ncount]); + } + + secp256k1_scalar_clear(&sc[0]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + secp256k1_scalar_clear(&sc[1]); + secp256k1_scalar_clear(&sc[2]); + secp256k1_scalar_clear(&sc[3]); + secp256k1_scalar_clear(&sc[4]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6)); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5)); + CHECK(secp256k1_gej_is_infinity(&r)); + + /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ + { + const size_t TOP = 8; + size_t s0i, s1i; + size_t t0i, t1i; + secp256k1_ge ptg; + secp256k1_gej ptgj; + + random_group_element_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + + for(t0i = 0; t0i < TOP; t0i++) { + for(t1i = 0; t1i < TOP; t1i++) { + secp256k1_gej t0p, t1p; + secp256k1_scalar t0, t1; + + secp256k1_scalar_set_int(&t0, (t0i + 1) / 2); + secp256k1_scalar_cond_negate(&t0, t0i & 1); + secp256k1_scalar_set_int(&t1, (t1i + 1) / 2); + secp256k1_scalar_cond_negate(&t1, t1i & 1); + + secp256k1_ecmult(&ctx->ecmult_ctx, &t0p, &ptgj, &t0, &szero); + secp256k1_ecmult(&ctx->ecmult_ctx, &t1p, &ptgj, &t1, &szero); + + for(s0i = 0; s0i < TOP; s0i++) { + for(s1i = 0; s1i < TOP; s1i++) { + secp256k1_scalar tmp1, tmp2; + secp256k1_gej expected, actual; + + secp256k1_ge_set_gej(&pt[0], &t0p); + secp256k1_ge_set_gej(&pt[1], &t1p); + + secp256k1_scalar_set_int(&sc[0], (s0i + 1) / 2); + secp256k1_scalar_cond_negate(&sc[0], s0i & 1); + secp256k1_scalar_set_int(&sc[1], (s1i + 1) / 2); + secp256k1_scalar_cond_negate(&sc[1], s1i & 1); + + secp256k1_scalar_mul(&tmp1, &t0, &sc[0]); + secp256k1_scalar_mul(&tmp2, &t1, &sc[1]); + secp256k1_scalar_add(&tmp1, &tmp1, &tmp2); + + secp256k1_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); + secp256k1_gej_neg(&expected, &expected); + secp256k1_gej_add_var(&actual, &actual, &expected, NULL); + CHECK(secp256k1_gej_is_infinity(&actual)); + } + } + } + } + } +} + +void test_secp256k1_pippenger_bucket_window_inv(void) { + int i; + + CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0); + for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { +#ifdef USE_ENDOMORPHISM + /* Bucket_window of 8 is not used with endo */ + if (i == 8) { + continue; + } +#endif + CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)) == i); + if (i != PIPPENGER_MAX_BUCKET_WINDOW) { + CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)+1) > i); + } + } +} + +/** + * Probabilistically test the function returning the maximum number of possible points + * for a given scratch space. + */ +void test_ecmult_multi_pippenger_max_points(void) { + size_t scratch_size = secp256k1_rand_int(256); + size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); + secp256k1_scratch *scratch; + size_t n_points_supported; + int bucket_window = 0; + + for(; scratch_size < max_size; scratch_size+=256) { + scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size); + CHECK(scratch != NULL); + n_points_supported = secp256k1_pippenger_max_points(scratch); + if (n_points_supported == 0) { + secp256k1_scratch_destroy(scratch); + continue; + } + bucket_window = secp256k1_pippenger_bucket_window(n_points_supported); + CHECK(secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS)); + secp256k1_scratch_deallocate_frame(scratch); + secp256k1_scratch_destroy(scratch); + } + CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); +} + +/** + * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to + * 1 <= i <= num points. + */ +void test_ecmult_multi_batching(void) { + static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; + secp256k1_scalar scG; + secp256k1_scalar szero; + secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_scalar) * n_points); + secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * n_points); + secp256k1_gej r; + secp256k1_gej r2; + ecmult_multi_data data; + int i; + secp256k1_scratch *scratch; + + secp256k1_gej_set_infinity(&r2); + secp256k1_scalar_set_int(&szero, 0); + + /* Get random scalars and group elements and compute result */ + random_scalar_order(&scG); + secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r2, &szero, &scG); + for(i = 0; i < n_points; i++) { + secp256k1_ge ptg; + secp256k1_gej ptgj; + random_group_element_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + pt[i] = ptg; + random_scalar_order(&sc[i]); + secp256k1_ecmult(&ctx->ecmult_ctx, &ptgj, &ptgj, &sc[i], NULL); + secp256k1_gej_add_var(&r2, &r2, &ptgj, NULL); + } + data.sc = sc; + data.pt = pt; + + /* Test with empty scratch space */ + scratch = secp256k1_scratch_create(&ctx->error_callback, 0); + CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); + secp256k1_scratch_destroy(scratch); + + /* Test with space for 1 point in pippenger. That's not enough because + * ecmult_multi selects strauss which requires more memory. */ + scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); + secp256k1_scratch_destroy(scratch); + + secp256k1_gej_neg(&r2, &r2); + for(i = 1; i <= n_points; i++) { + if (i > ECMULT_PIPPENGER_THRESHOLD) { + int bucket_window = secp256k1_pippenger_bucket_window(i); + size_t scratch_size = secp256k1_pippenger_scratch_size(i, bucket_window); + scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + } else { + size_t scratch_size = secp256k1_strauss_scratch_size(i); + scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + } + CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(scratch); + } + free(sc); + free(pt); +} + +void run_ecmult_multi_tests(void) { + secp256k1_scratch *scratch; + + test_secp256k1_pippenger_bucket_window_inv(); + test_ecmult_multi_pippenger_max_points(); + scratch = secp256k1_scratch_create(&ctx->error_callback, 819200); + test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); + test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single); + test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single); + secp256k1_scratch_destroy(scratch); + + /* Run test_ecmult_multi with space for exactly one point */ + scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); + secp256k1_scratch_destroy(scratch); + + test_ecmult_multi_batching(); +} + +void test_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, two, t; + int wnaf[256]; + int zeroes = -1; + int i; + int bits; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&two, 2); - int wnaf[256]; - int bits = secp256k1_ecmult_wnaf(wnaf, number, w); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); CHECK(bits <= 256); - int zeroes = -1; - for (int i=bits-1; i>=0; i--) { - secp256k1_scalar_mul(&x, &x, &two); + for (i = bits-1; i >= 0; i--) { int v = wnaf[i]; + secp256k1_scalar_mul(&x, &x, &two); if (v) { CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ zeroes=0; @@ -836,55 +2956,1049 @@ void test_wnaf(const secp256k1_scalar_t *number, int w) { CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ } +void test_constant_wnaf_negate(const secp256k1_scalar *number) { + secp256k1_scalar neg1 = *number; + secp256k1_scalar neg2 = *number; + int sign1 = 1; + int sign2 = 1; + + if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { + secp256k1_scalar_negate(&neg1, &neg1); + sign1 = -1; + } + sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); + CHECK(sign1 == sign2); + CHECK(secp256k1_scalar_eq(&neg1, &neg2)); +} + +void test_constant_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + int bits = 256; + secp256k1_scalar num = *number; + + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_scalar_shr_int(&num, 8); + } + bits = 128; +#endif + skew = secp256k1_wnaf_const(wnaf, num, w, bits); + + for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) { + secp256k1_scalar t; + int v = wnaf[i]; + CHECK(v != 0); /* check nonzero */ + CHECK(v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + /* Skew num because when encoding numbers as odd we use an offset */ + secp256k1_scalar_cadd_bit(&num, skew == 2, 1); + CHECK(secp256k1_scalar_eq(&x, &num)); +} + +void test_fixed_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num = *number; + + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_scalar_shr_int(&num, 8); + } +#endif + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + secp256k1_scalar t; + int v = wnaf[i]; + CHECK(v == 0 || v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + /* If skew is 1 then add 1 to num */ + secp256k1_scalar_cadd_bit(&num, 0, skew == 1); + CHECK(secp256k1_scalar_eq(&x, &num)); +} + +/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the + * rest is 0.*/ +void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { + int i; + for (i = WNAF_SIZE(w)-1; i >= 8; --i) { + CHECK(wnaf[i] == 0); + } + for (i = 7; i >= 0; --i) { + CHECK(wnaf[i] == wnaf_expected[i]); + } +} + +void test_fixed_wnaf_small(void) { + int w = 4; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num; + + secp256k1_scalar_set_int(&num, 0); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(skew == 0); + + secp256k1_scalar_set_int(&num, 1); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 1; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(wnaf[0] == 1); + CHECK(skew == 0); + + { + int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; + secp256k1_scalar_set_int(&num, 0xffffffff); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf }; + secp256k1_scalar_set_int(&num, 0xeeeeeeee); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 1); + } + { + int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; + secp256k1_scalar_set_int(&num, 0x01010101); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 }; + secp256k1_scalar_set_int(&num, 0x01ef1ef1); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } +} + void run_wnaf(void) { - secp256k1_scalar_t n; - for (int i=0; iecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&secp256k1_ge_const_g, &r); + } + secp256k1_gej_add_ge(&r, &r, &ng); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } + for (i = 1; i <= 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_scalar_negate(&x, &x); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&ng, &r); + } + secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } +} + +void run_ecmult_constants(void) { + test_ecmult_constants(); +} + +void test_ecmult_gen_blind(void) { + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ + secp256k1_scalar key; + secp256k1_scalar b; + unsigned char seed32[32]; + secp256k1_gej pgej; + secp256k1_gej pgej2; + secp256k1_gej i; + secp256k1_ge pge; + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); + secp256k1_rand256(seed32); + b = ctx->ecmult_gen_ctx.blind; + i = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); + CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); + secp256k1_ge_set_gej(&pge, &pgej); + ge_equals_gej(&pge, &pgej2); +} + +void test_ecmult_gen_blind_reset(void) { + /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ + secp256k1_scalar b; + secp256k1_gej initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + b = ctx->ecmult_gen_ctx.blind; + initial = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); +} + +void run_ecmult_gen_blind(void) { + int i; + test_ecmult_gen_blind_reset(); + for (i = 0; i < 10; i++) { + test_ecmult_gen_blind(); + } +} + +#ifdef USE_ENDOMORPHISM +/***** ENDOMORPHISH TESTS *****/ +void test_scalar_split(void) { + secp256k1_scalar full; + secp256k1_scalar s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; + + random_scalar_order_test(&full); + secp256k1_scalar_split_lambda(&s1, &slam, &full); + + /* check that both are <= 128 bits in size */ + if (secp256k1_scalar_is_high(&s1)) { + secp256k1_scalar_negate(&s1, &s1); } + if (secp256k1_scalar_is_high(&slam)) { + secp256k1_scalar_negate(&slam, &slam); + } + + secp256k1_scalar_get_b32(tmp, &s1); + CHECK(memcmp(zero, tmp, 16) == 0); + secp256k1_scalar_get_b32(tmp, &slam); + CHECK(memcmp(zero, tmp, 16) == 0); } -void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { - secp256k1_scalar_t nonce; +void run_endomorphism_tests(void) { + test_scalar_split(); +} +#endif + +void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + size_t pubkeyclen; + int32_t ecount; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + ecount = 0; + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + secp256k1_pubkey_save(&pubkey, &ge); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + } + CHECK(ecount == 0); + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + } + } + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2]; + secp256k1_ge ge; + secp256k1_pubkey pubkey; + size_t len; + int32_t i; + int32_t ecount; + int32_t ecount2; + ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ + VG_UNDEF(&pubkeyc[65], 1); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(shortkey, 2); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i; + VG_UNDEF(&shortkey[1], 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); + CHECK(ecount == 2); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 1); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 2); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + VG_UNDEF(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + VG_CHECK(&ge.x, sizeof(ge.x)); + VG_CHECK(&ge.y, sizeof(ge.y)); + VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + ge_equals_ge(&secp256k1_ge_const_g, &ge); + CHECK(ecount == 0); + /* secp256k1_ec_pubkey_serialize illegal args. */ + ecount = 0; + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 1); + CHECK(len == 0); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 2); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + VG_CHECK(sout, 65); + CHECK(ecount == 3); + CHECK(len == 0); + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); + CHECK(ecount == 4); + CHECK(len == 0); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(sout, 65); + CHECK(ecount == 4); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + ecount = 0; + ecount2 = 11; + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + /* Does the illegal arg callback actually change the behavior? */ + secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + CHECK(ecount2 == 10); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey2; + secp256k1_pubkey pubkey_one; + secp256k1_pubkey pubkey_negone; + const secp256k1_pubkey *pubkeys[3]; + size_t len; + int32_t ecount; + /* Group order is too large, reject. */ + CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value unchanged. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); + CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Overflowing key tweak zeroizes. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Private key tweaks results in a key of zero. */ + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); + CHECK(memcmp(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); + CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Test argument errors. */ + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(ecount == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + ecount = 0; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); + CHECK(ecount == 1); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); + CHECK(ecount == 1); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* secp256k1_ec_pubkey_combine tests. */ + ecount = 0; + pubkeys[0] = &pubkey_one; + VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 2); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { + secp256k1_scalar nonce; do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(sig, key, msg, &nonce, recid)); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } void test_ecdsa_sign_verify(void) { + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar one; + secp256k1_scalar msg, key; + secp256k1_scalar sigr, sigs; int recid; int getrec; - secp256k1_scalar_t msg, key; random_scalar_order_test(&msg); random_scalar_order_test(&key); - secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key); - secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj); - secp256k1_ecdsa_sig_t sig; - getrec = secp256k1_rand32()&1; - random_sign(&sig, &key, &msg, getrec?&recid:NULL); - if (getrec) CHECK(recid >= 0 && recid < 4); - CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg)); - secp256k1_scalar_t one; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + getrec = secp256k1_rand_bits(1); + random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); + if (getrec) { + CHECK(recid >= 0 && recid < 4); + } + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); } void run_ecdsa_sign_verify(void) { - for (int i=0; i<10*count; i++) { + int i; + for (i = 0; i < 10*count; i++) { test_ecdsa_sign_verify(); } } +/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void)msg32; + (void)key32; + (void)algo16; + memcpy(nonce32, data, 32); + return (counter == 0); +} + +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that has a fatal error on the first counter value. */ + if (counter == 0) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); +} + +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ + if (counter < 3) { + memset(nonce32, counter==0 ? 0 : 255, 32); + if (counter == 2) { + nonce32[31]--; + } + return 1; + } + if (counter < 5) { + static const unsigned char order[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + memcpy(nonce32, order, 32); + if (counter == 4) { + nonce32[31]++; + } + return 1; + } + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ + /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ + if (counter > 5) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); +} + +int is_empty_signature(const secp256k1_ecdsa_signature *sig) { + static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; + return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; +} + void test_ecdsa_end_to_end(void) { + unsigned char extra[32] = {0x00}; unsigned char privkey[32]; unsigned char message[32]; + unsigned char privkey2[32]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; + unsigned char sig[74]; + size_t siglen = 74; + unsigned char pubkeyc[65]; + size_t pubkeyclen = 65; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey_tmp; + unsigned char seckey[300]; + size_t seckeylen = 300; /* Generate a random key and message. */ { - secp256k1_scalar_t msg, key; + secp256k1_scalar msg, key; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); @@ -892,195 +4006,882 @@ void test_ecdsa_end_to_end(void) { } /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(privkey) == 1); - unsigned char pubkey[65]; int pubkeylen = 65; - CHECK(secp256k1_ec_pubkey_create(pubkey, &pubkeylen, privkey, secp256k1_rand32() % 2) == 1); - CHECK(secp256k1_ec_pubkey_verify(pubkey, pubkeylen)); + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + + /* Verify negation changes the key and changes it back */ + memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); + CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); + CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); /* Verify private key import and export. */ - unsigned char seckey[300]; int seckeylen = 300; - CHECK(secp256k1_ec_privkey_export(privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); - unsigned char privkey2[32]; - CHECK(secp256k1_ec_privkey_import(privkey2, seckey, seckeylen) == 1); + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); + CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); CHECK(memcmp(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { + int ret1; + int ret2; unsigned char rnd[32]; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); - int ret1 = secp256k1_ec_privkey_tweak_add(privkey, rnd); - int ret2 = secp256k1_ec_pubkey_tweak_add(pubkey, pubkeylen, rnd); + ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); CHECK(ret1 == ret2); - if (ret1 == 0) return; - unsigned char pubkey2[65]; int pubkeylen2 = 65; - CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { + int ret1; + int ret2; unsigned char rnd[32]; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); - int ret1 = secp256k1_ec_privkey_tweak_mul(privkey, rnd); - int ret2 = secp256k1_ec_pubkey_tweak_mul(pubkey, pubkeylen, rnd); + ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); CHECK(ret1 == ret2); - if (ret1 == 0) return; - unsigned char pubkey2[65]; int pubkeylen2 = 65; - CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - unsigned char signature[72]; int signaturelen = 72; - while(1) { - unsigned char rnd[32]; - secp256k1_rand256_test(rnd); - if (secp256k1_ecdsa_sign(message, 32, signature, &signaturelen, privkey, rnd) == 1) { - break; - } - } + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ - CHECK(secp256k1_ecdsa_verify(message, 32, signature, signaturelen, pubkey, pubkeylen) == 1); - /* Destroy signature and verify again. */ - signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_verify(message, 32, signature, signaturelen, pubkey, pubkeylen) != 1); - - /* Compact sign. */ - unsigned char csignature[64]; int recid = 0; - while(1) { - unsigned char rnd[32]; - secp256k1_rand256_test(rnd); - if (secp256k1_ecdsa_sign_compact(message, 32, csignature, privkey, rnd, &recid) == 1) { - break; + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + siglen = 74; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); +} + +void test_random_pubkeys(void) { + secp256k1_ge elem; + secp256k1_ge elem2; + unsigned char in[65]; + /* Generate some randomly sized pubkeys. */ + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); + } + if (len == 65) { + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); + } else { + in[0] = secp256k1_rand_bits(1) ? 2 : 3; + } + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); + } + if (len > 1) { + secp256k1_rand256(&in[1]); + } + if (len > 33) { + secp256k1_rand256(&in[33]); + } + if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { + unsigned char out[65]; + unsigned char firstb; + int res; + size_t size = len; + firstb = in[0]; + /* If the pubkey can be parsed, it should round-trip... */ + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); + CHECK(size == len); + CHECK(memcmp(&in[1], &out[1], len-1) == 0); + /* ... except for the type of hybrid inputs. */ + if ((in[0] != 6) && (in[0] != 7)) { + CHECK(in[0] == out[0]); + } + size = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); + CHECK(size == 65); + CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); + ge_equals_ge(&elem,&elem2); + /* Check that the X9.62 hybrid type is checked. */ + in[0] = secp256k1_rand_bits(1) ? 6 : 7; + res = secp256k1_eckey_pubkey_parse(&elem2, in, size); + if (firstb == 2 || firstb == 3) { + if (in[0] == firstb + 4) { + CHECK(res); + } else { + CHECK(!res); + } + } + if (res) { + ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); + CHECK(memcmp(&in[1], &out[1], 64) == 0); } } - /* Recover. */ - unsigned char recpubkey[65]; int recpubkeylen = 0; - CHECK(secp256k1_ecdsa_recover_compact(message, 32, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); - CHECK(recpubkeylen == pubkeylen); - CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); - /* Destroy signature and verify again. */ - csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_recover_compact(message, 32, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || - memcmp(pubkey, recpubkey, pubkeylen) != 0); - CHECK(recpubkeylen == pubkeylen); +} +void run_random_pubkeys(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_random_pubkeys(); + } } void run_ecdsa_end_to_end(void) { - for (int i=0; i<64*count; i++) { + int i; + for (i = 0; i < 64*count; i++) { test_ecdsa_end_to_end(); } } -/* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { - const unsigned char msg32[32] = { - 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', - 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', - 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', - 's', 's', 'a', 'g', 'e', '.', '.', '.' - }; - const unsigned char sig64[64] = { - /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 0. */ - 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, - 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, - 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, - 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, - 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, - 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, - 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, - 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 - }; - unsigned char pubkey[65]; - int pubkeylen = 65; - CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 0)); - CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 1)); - CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 2)); - CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 3)); - - /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ - const unsigned char sigb64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, +int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; +#ifdef ENABLE_OPENSSL_TESTS + static const unsigned char max_scalar[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 }; - unsigned char pubkeyb[33]; - int pubkeyblen = 33; - for (int recid = 0; recid < 4; recid++) { - /* (4,4) encoded in DER. */ - unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; - /* (order + r,4) encoded in DER. */ - unsigned char sigbderlong[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, - 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, - 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 - }; - CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); - CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); - for (int recid2 = 0; recid2 < 4; recid2++) { - unsigned char pubkey2b[33]; - int pubkey2blen = 33; - CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); - /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); +#endif + + int ret = 0; + + secp256k1_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + +#ifdef ENABLE_OPENSSL_TESTS + ECDSA_SIG *sig_openssl; + const BIGNUM *r = NULL, *s = NULL; + const unsigned char *sigptr; + unsigned char roundtrip_openssl[2048]; + int len_openssl = 2048; + int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; +#endif + + parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; + valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + +#ifdef ENABLE_OPENSSL_TESTS + sig_openssl = ECDSA_SIG_new(); + sigptr = sig; + parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); + if (parsed_openssl) { + ECDSA_SIG_get0(sig_openssl, &r, &s); + valid_openssl = !BN_is_negative(r) && !BN_is_negative(s) && BN_num_bits(r) > 0 && BN_num_bits(r) <= 256 && BN_num_bits(s) > 0 && BN_num_bits(s) <= 256; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(r, tmp + 32 - BN_num_bytes(r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(s, tmp + 32 - BN_num_bytes(s)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + } + len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); + if (len_openssl <= 2048) { + unsigned char *ptr = roundtrip_openssl; + CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + } else { + len_openssl = 0; + } + ECDSA_SIG_free(sig_openssl); + + ret |= (parsed_der && !parsed_openssl) << 4; + ret |= (valid_der && !valid_openssl) << 5; + ret |= (roundtrips_openssl && !parsed_der) << 6; + ret |= (roundtrips_der != roundtrips_openssl) << 7; + if (roundtrips_openssl) { + ret |= (len_der != (size_t)len_openssl) << 8; + ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + } +#endif + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = secp256k1_rand_bits(3); + if (action < 1 && *len > 3) { + /* Delete a byte. */ + pos = secp256k1_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2 && *len < 2048) { + /* Insert a byte. */ + pos = secp256k1_rand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = secp256k1_rand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = secp256k1_rand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : secp256k1_rand_int(10) == 0; + + for (n = 0; n < 2; n++) { + /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ + nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; } - /* Damage signature. */ - sigbder[7]++; - CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); + tlen += tlenlen; } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + secp256k1_rand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + secp256k1_rand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + secp256k1_rand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * count; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + +/* Tests several edge cases. */ +void test_ecdsa_edge_cases(void) { + int t; + secp256k1_ecdsa_signature sig; /* Test the case where ECDSA recomputes a point that is infinity. */ { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_set_int(&sig.s, 1); - secp256k1_scalar_negate(&sig.s, &sig.s); - secp256k1_scalar_inverse(&sig.s, &sig.s); - secp256k1_scalar_set_int(&sig.r, 1); - secp256k1_gej_t keyj; - secp256k1_ecmult_gen(&keyj, &sig.r); - secp256k1_ge_t key; + secp256k1_gej keyj; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_negate(&ss, &ss); + secp256k1_scalar_inverse(&ss, &ss); + secp256k1_scalar_set_int(&sr, 1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); secp256k1_ge_set_gej(&key, &keyj); - secp256k1_scalar_t msg = sig.s; - CHECK(secp256k1_ecdsa_sig_verify(&sig, &key, &msg) == 0); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } - /* Test r/s equal to zero */ + /* Verify signature with r of zero fails. */ { - /* (1,1) encoded in DER. */ - unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; - unsigned char sigc64[64] = { + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 0); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with s of zero fails. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 0); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 1); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 2); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_negate(&msg, &msg); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_set_int(&ss, 3); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_pubkey pubkey; + size_t siglen; + int32_t ecount; + unsigned char signature[72]; + static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }; - unsigned char pubkeyc[65]; - int pubkeyclen = 65; - CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); - CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + static const unsigned char nonce2[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; + const unsigned char key[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char msg[32] = { + 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, + 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, + 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, + 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, + }; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + msg[31] = 0xaa; + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 7); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); + CHECK(ecount == 8); + siglen = 72; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); + CHECK(ecount == 13); + siglen = 10; + /* Too little room for a signature does not fail via ARGCHECK. */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK(ecount == 13); + ecount = 0; + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); + CHECK(ecount == 5); + memset(signature, 255, 64); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); + CHECK(ecount == 5); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + } + + /* Nonce function corner cases. */ + for (t = 0; t < 2; t++) { + static const unsigned char zero[32] = {0x00}; + int i; + unsigned char key[32]; + unsigned char msg[32]; + secp256k1_ecdsa_signature sig2; + secp256k1_scalar sr[512], ss; + const unsigned char *extra; + extra = t == 0 ? NULL : zero; + memset(msg, 0, 32); + msg[31] = 1; + /* High key results in signature failure. */ + memset(key, 0xFF, 32); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Zero key results in signature failure. */ + memset(key, 0, 32); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Nonce function failure results in signature failure. */ + key[31] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* The retry loop successfully makes its way to the first good value. */ + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function is deterministic. */ + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function changes output with different messages. */ + for(i = 0; i < 256; i++) { + int j; + msg[0] = i; + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(i = 256; i < 512; i++) { + int j; + key[0] = i - 256; + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); + } + } + key[0] = 0; + } + + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + VG_UNDEF(nonce,32); + VG_UNDEF(nonce2,32); + VG_UNDEF(nonce3,32); + VG_UNDEF(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + VG_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + VG_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + VG_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + VG_CHECK(nonce4,32); + CHECK(memcmp(nonce, nonce2, 32) != 0); + CHECK(memcmp(nonce, nonce3, 32) != 0); + CHECK(memcmp(nonce, nonce4, 32) != 0); + CHECK(memcmp(nonce2, nonce3, 32) != 0); + CHECK(memcmp(nonce2, nonce4, 32) != 0); + CHECK(memcmp(nonce3, nonce4, 32) != 0); + } + + + /* Privkey export where pubkey is the point at infinity. */ + { + unsigned char privkey[300]; + unsigned char seckey[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, + }; + size_t outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); } } @@ -1089,90 +4890,128 @@ void run_ecdsa_edge_cases(void) { } #ifdef ENABLE_OPENSSL_TESTS -EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { +EC_KEY *get_openssl_key(const unsigned char *key32) { unsigned char privkey[300]; - int privkeylen; - int compr = secp256k1_rand32() & 1; + size_t privkeylen; const unsigned char* pbegin = privkey; + int compr = secp256k1_rand_bits(1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(secp256k1_eckey_privkey_serialize(privkey, &privkeylen, key, compr)); + CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); CHECK(EC_KEY_check_key(ec_key)); return ec_key; } void test_ecdsa_openssl(void) { - secp256k1_scalar_t key, msg; + secp256k1_gej qj; + secp256k1_ge q; + secp256k1_scalar sigr, sigs; + secp256k1_scalar one; + secp256k1_scalar msg2; + secp256k1_scalar key, msg; + EC_KEY *ec_key; + unsigned int sigsize = 80; + size_t secp_sigsize = 80; unsigned char message[32]; + unsigned char signature[80]; + unsigned char key32[32]; secp256k1_rand256_test(message); secp256k1_scalar_set_b32(&msg, message, NULL); random_scalar_order_test(&key); - secp256k1_gej_t qj; - secp256k1_ecmult_gen(&qj, &key); - secp256k1_ge_t q; + secp256k1_scalar_get_b32(key32, &key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); secp256k1_ge_set_gej(&q, &qj); - EC_KEY *ec_key = get_openssl_key(&key); - CHECK(ec_key); - unsigned char signature[80]; - unsigned int sigsize = 80; + ec_key = get_openssl_key(key32); + CHECK(ec_key != NULL); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - secp256k1_ecdsa_sig_t sig; - CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg)); - secp256k1_scalar_t one; + CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); secp256k1_scalar_set_int(&one, 1); - secp256k1_scalar_t msg2; secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg2)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); - random_sign(&sig, &key, &msg, NULL); - int secp_sigsize = 80; - CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); + random_sign(&sigr, &sigs, &key, &msg, NULL); + CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); EC_KEY_free(ec_key); } void run_ecdsa_openssl(void) { - for (int i=0; i<10*count; i++) { + int i; + for (i = 0; i < 10*count; i++) { test_ecdsa_openssl(); } } #endif +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" +#endif + int main(int argc, char **argv) { + unsigned char seed16[16] = {0}; + unsigned char run32[32] = {0}; /* find iteration count */ if (argc > 1) { count = strtol(argv[1], NULL, 0); } /* find random seed */ - uint64_t seed; if (argc > 2) { - seed = strtoull(argv[2], NULL, 0); + int pos = 0; + const char* ch = argv[2]; + while (pos < 16 && ch[0] != 0 && ch[1] != 0) { + unsigned short sh; + if (sscanf(ch, "%2hx", &sh)) { + seed16[pos] = sh; + } else { + break; + } + ch += 2; + pos++; + } } else { FILE *frand = fopen("/dev/urandom", "r"); - if (!frand || !fread(&seed, sizeof(seed), 1, frand)) { - seed = time(NULL) * 1337; + if ((frand == NULL) || fread(&seed16, sizeof(seed16), 1, frand) != sizeof(seed16)) { + uint64_t t = time(NULL) * (uint64_t)1337; + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + if (frand) { + fclose(frand); } - fclose(frand); } - secp256k1_rand_seed(seed); + secp256k1_rand_seed(seed16); printf("test count = %i\n", count); - printf("random seed = %llu\n", (unsigned long long)seed); + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); /* initialize */ - secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); + run_context_tests(); + run_scratch_tests(); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + if (secp256k1_rand_bits(1)) { + secp256k1_rand256(run32); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); + } - /* initializing a second time shouldn't cause any harm or memory leaks. */ - secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); + run_rand_bits(); + run_rand_int(); - /* Likewise, re-running the internal init functions should be harmless. */ - secp256k1_fe_start(); - secp256k1_ge_start(); - secp256k1_scalar_start(); - secp256k1_ecdsa_start(); + run_sha256_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); #ifndef USE_NUM_NONE /* num tests */ @@ -1185,20 +5024,45 @@ int main(int argc, char **argv) { /* field tests */ run_field_inv(); run_field_inv_var(); - run_field_inv_all(); run_field_inv_all_var(); + run_field_misc(); + run_field_convert(); run_sqr(); run_sqrt(); /* group tests */ run_ge(); + run_group_decompress(); /* ecmult tests */ run_wnaf(); run_point_times_order(); run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ecmult_multi_tests(); + run_ec_combine(); + + /* endomorphism tests */ +#ifdef USE_ENDOMORPHISM + run_endomorphism_tests(); +#endif + + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + +#ifdef ENABLE_MODULE_ECDH + /* ecdh tests */ + run_ecdh_tests(); +#endif /* ecdsa tests */ + run_random_pubkeys(); + run_ecdsa_der_parse(); run_ecdsa_sign_verify(); run_ecdsa_end_to_end(); run_ecdsa_edge_cases(); @@ -1206,18 +5070,17 @@ int main(int argc, char **argv) { run_ecdsa_openssl(); #endif - printf("random run = %llu\n", (unsigned long long)secp256k1_rand32() + ((unsigned long long)secp256k1_rand32() << 32)); +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif - /* shutdown */ - secp256k1_stop(); + secp256k1_rand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); - /* shutting down twice shouldn't cause any double frees. */ - secp256k1_stop(); + /* shutdown */ + secp256k1_context_destroy(ctx); - /* Same for the internal shutdown functions. */ - secp256k1_fe_stop(); - secp256k1_ge_stop(); - secp256k1_scalar_stop(); - secp256k1_ecdsa_stop(); + printf("no problems found\n"); return 0; } diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c new file mode 100644 index 000000000000..ab9779b02fc5 --- /dev/null +++ b/src/secp256k1/src/tests_exhaustive.c @@ -0,0 +1,511 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#undef USE_ECMULT_STATIC_PRECOMPUTATION + +#ifndef EXHAUSTIVE_TEST_ORDER +/* see group_impl.h for allowable values */ +#define EXHAUSTIVE_TEST_ORDER 13 +#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ +#endif + +#include "include/secp256k1.h" +#include "group.h" +#include "secp256k1.c" +#include "testrand_impl.h" + +#ifdef ENABLE_MODULE_RECOVERY +#include "src/modules/recovery/main_impl.h" +#include "include/secp256k1_recovery.h" +#endif + +/** stolen from tests.c */ +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); +} + +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); +} + +void random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} +/** END stolen from tests.c */ + +int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *algo16, + void *data, unsigned int attempt) { + secp256k1_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; + } + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +#ifdef USE_ENDOMORPHISM +void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { + int i; + for (i = 0; i < order; i++) { + secp256k1_ge res; + secp256k1_ge_mul_lambda(&res, &group[i]); + ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); + } +} +#endif + +void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + int i, j; + + /* Sanity-check (and check infinity functions) */ + CHECK(secp256k1_ge_is_infinity(&group[0])); + CHECK(secp256k1_gej_is_infinity(&groupj[0])); + for (i = 1; i < order; i++) { + CHECK(!secp256k1_ge_is_infinity(&group[i])); + CHECK(!secp256k1_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < order; j++) { + secp256k1_fe fe_inv; + secp256k1_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < order; i++) { + secp256k1_ge zless_gej; + secp256k1_gej tmp; + /* add_var */ + secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_ge */ + if (j > 0) { + secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + /* add_ge_var */ + secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_zinv_var */ + zless_gej.infinity = groupj[j].infinity; + zless_gej.x = groupj[j].x; + zless_gej.y = groupj[j].y; + secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + } + + /* Check doubling */ + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + if (i > 0) { + secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + secp256k1_gej_double_var(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + + /* Check negation */ + for (i = 1; i < order; i++) { + secp256k1_ge tmp; + secp256k1_gej tmpj; + secp256k1_ge_neg(&tmp, &group[i]); + ge_equals_ge(&group[order - i], &tmp); + secp256k1_gej_neg(&tmpj, &groupj[i]); + ge_equals_gej(&group[order - i], &tmpj); + } +} + +void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + int i, j, r_log; + for (r_log = 1; r_log < order; r_log++) { + for (j = 0; j < order; j++) { + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + secp256k1_scalar na, ng; + secp256k1_scalar_set_int(&na, i); + secp256k1_scalar_set_int(&ng, j); + + secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); + ge_equals_gej(&group[(i * r_log + j) % order], &tmp); + + if (i > 0) { + secp256k1_ecmult_const(&tmp, &group[i], &ng, 256); + ge_equals_gej(&group[(i * j) % order], &tmp); + } + } + } + } +} + +typedef struct { + secp256k1_scalar sc[2]; + secp256k1_ge pt[2]; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k, x, y; + secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); + for (i = 0; i < order; i++) { + for (j = 0; j < order; j++) { + for (k = 0; k < order; k++) { + for (x = 0; x < order; x++) { + for (y = 0; y < order; y++) { + secp256k1_gej tmp; + secp256k1_scalar g_sc; + ecmult_multi_data data; + + secp256k1_scalar_set_int(&data.sc[0], i); + secp256k1_scalar_set_int(&data.sc[1], j); + secp256k1_scalar_set_int(&g_sc, k); + data.pt[0] = group[x]; + data.pt[1] = group[y]; + + secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); + ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp); + } + } + } + } + } + secp256k1_scratch_destroy(scratch); +} + +void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { + secp256k1_fe x; + unsigned char x_bin[32]; + k %= EXHAUSTIVE_TEST_ORDER; + x = group[k].x; + secp256k1_fe_normalize(&x); + secp256k1_fe_get_b32(x_bin, &x); + secp256k1_scalar_set_b32(r, x_bin, NULL); +} + +void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* Verify by calling verify */ + secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + secp256k1_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +#ifdef ENABLE_MODULE_RECOVERY +void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_fe r_dot_y_normalized; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + /* In computing the recid, there is an overflow condition that is disabled in + * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value + * will exceed the group order, and our signing code always holds out for r + * values that don't overflow, so with a proper overflow check the tests would + * loop indefinitely. */ + r_dot_y_normalized = group[k].y; + secp256k1_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % order == (i + r * j) % order) { + expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; + } else { + expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + secp256k1_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} +#endif + +int main(void) { + int i; + secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + + /* Build context */ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + /* TODO set z = 1, then do num_tests runs with random z values */ + + /* Generate the entire group */ + secp256k1_gej_set_infinity(&groupj[0]); + secp256k1_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + /* Set a different random z-value for each Jacobian point */ + secp256k1_fe z; + random_fe(&z); + + secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); + secp256k1_ge_set_gej(&group[i], &groupj[i]); + secp256k1_gej_rescale(&groupj[i], &z); + + /* Verify against ecmult_gen */ + { + secp256k1_scalar scalar_i; + secp256k1_gej generatedj; + secp256k1_ge generated; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_ge_set_gej(&generated, &generatedj); + + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); + } + } + + /* Run the tests */ +#ifdef USE_ENDOMORPHISM + test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); +#endif + test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_ecmult_multi(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); +#endif + + secp256k1_context_destroy(ctx); + return 0; +} + diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index 08b23a9d38c2..e0147500f994 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_UTIL_H_ -#define _SECP256K1_UTIL_H_ +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -15,6 +15,15 @@ #include #include +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} secp256k1_callback; + +static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + #ifdef DETERMINISTIC #define TEST_FAILURE(msg) do { \ fprintf(stderr, "%s\n", msg); \ @@ -27,7 +36,7 @@ } while(0) #endif -#ifndef HAVE_BUILTIN_EXPECT +#ifdef HAVE_BUILTIN_EXPECT #define EXPECT(x,c) __builtin_expect((x),(c)) #else #define EXPECT(x,c) (x) @@ -47,20 +56,34 @@ } while(0) #endif -/* Like assert(), but safe to use on expressions with side effects. */ -#ifndef NDEBUG -#define DEBUG_CHECK CHECK -#else -#define DEBUG_CHECK(cond) do { (void)(cond); } while(0) -#endif - -/* Like DEBUG_CHECK(), but when VERIFY is defined instead of NDEBUG not defined. */ -#ifdef VERIFY +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ +#if defined(COVERAGE) +#define VERIFY_CHECK(check) +#define VERIFY_SETUP(stmt) +#elif defined(VERIFY) #define VERIFY_CHECK CHECK +#define VERIFY_SETUP(stmt) do { stmt; } while(0) #else #define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#define VERIFY_SETUP(stmt) #endif +static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { + void *ret = malloc(size); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } + return ret; +} + +static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void *ptr, size_t size) { + void *ret = realloc(ptr, size); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } + return ret; +} + /* Macro for restrict, when available and not in a VERIFY build. */ #if defined(SECP256K1_BUILD) && defined(VERIFY) # define SECP256K1_RESTRICT @@ -78,4 +101,21 @@ # endif #endif +#if defined(_WIN32) +# define I64FORMAT "I64d" +# define I64uFORMAT "I64u" +#else +# define I64FORMAT "lld" +# define I64uFORMAT "llu" +#endif + +#if defined(HAVE___INT128) +# if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +# else +# define SECP256K1_GNUC_EXT +# endif +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; #endif + +#endif /* SECP256K1_UTIL_H */ diff --git a/src/serialize.h b/src/serialize.h index b57a71529bfe..3d9350a564d8 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -4,8 +4,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_SERIALIZE_H -#define BITCOIN_SERIALIZE_H +#ifndef PHORE_SERIALIZE_H +#define PHORE_SERIALIZE_H #include #include @@ -45,35 +45,6 @@ inline T* NCONST_PTR(const T* val) return const_cast(val); } -/** - * Get begin pointer of vector (non-const version). - * @note These functions avoid the undefined case of indexing into an empty - * vector, as well as that of indexing after the end of the vector. - */ -template -inline T* begin_ptr(std::vector& v) -{ - return v.empty() ? NULL : &v[0]; -} -/** Get begin pointer of vector (const version) */ -template -inline const T* begin_ptr(const std::vector& v) -{ - return v.empty() ? NULL : &v[0]; -} -/** Get end pointer of vector (non-const version) */ -template -inline T* end_ptr(std::vector& v) -{ - return v.empty() ? NULL : (&v[0] + v.size()); -} -/** Get end pointer of vector (const version) */ -template -inline const T* end_ptr(const std::vector& v) -{ - return v.empty() ? NULL : (&v[0] + v.size()); -} - ///////////////////////////////////////////////////////////////// // // Templates for serializing to anything that looks like a stream, @@ -482,8 +453,8 @@ class CFlatData template explicit CFlatData(std::vector& v) { - pbegin = (char*)begin_ptr(v); - pend = (char*)end_ptr(v); + pbegin = (char*)v.data(); + pend = (char*)(v.data() + v.size()); } char* begin() { return pbegin; } const char* begin() const { return pbegin; } @@ -945,6 +916,12 @@ class CSizeComputer return *this; } + /** Pretend _nSize bytes are written, without specifying them. */ + void seek(size_t _nSize) + { + this->nSize += _nSize; + } + template CSizeComputer& operator<<(const T& obj) { @@ -966,4 +943,4 @@ class CSizeComputer } }; -#endif // BITCOIN_SERIALIZE_H +#endif // PHORE_SERIALIZE_H diff --git a/src/spork.cpp b/src/spork.cpp index ac6c3739bdb1..81c906d5b0ec 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -15,8 +15,6 @@ #include "sporkdb.h" #include "util.h" -using namespace std; -using namespace boost; class CSporkMessage; class CSporkManager; diff --git a/src/spork.h b/src/spork.h index 8e1b6e5ad11c..341a11e449ed 100644 --- a/src/spork.h +++ b/src/spork.h @@ -15,10 +15,6 @@ #include "obfuscation.h" #include "protocol.h" -#include - -using namespace std; -using namespace boost; /* Don't ever reuse these IDs for other sporks diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h index 7af71bf9a63a..1e010cb1ebaa 100644 --- a/src/support/lockedpool.h +++ b/src/support/lockedpool.h @@ -215,7 +215,7 @@ class LockedPool { * in std::allocator templates. * * Some implementations of the STL allocate memory in some constructors (i.e., - * see MSVC's vector implementation where it allocates 1 byte of memory in + * see MSVC's std::vector implementation where it allocates 1 byte of memory in * the allocator). Due to the unpredictable order of static initializers, we * have to make sure the LockedPoolManager instance exists before any other * STL-based objects that use secure_allocator are created. So instead of having diff --git a/src/swifttx.cpp b/src/swifttx.cpp index b9be4c343b4d..60caa8b64f4e 100644 --- a/src/swifttx.cpp +++ b/src/swifttx.cpp @@ -17,9 +17,7 @@ #include "sync.h" #include "util.h" #include "validationinterface.h" - -using namespace std; -using namespace boost; +#include std::map mapTxLockReq; std::map mapTxLockReqRejected; @@ -60,7 +58,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v return; } - BOOST_FOREACH (const CTxOut o, tx.vout) { + for (const CTxOut o : tx.vout) { // IX supports normal scripts and unspendable scripts (used in DS collateral and Budget collateral). // TODO: Look into other script types that are normal and can be included if (!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()) { @@ -84,7 +82,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v DoConsensusVote(tx, nBlockHeight); - mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); + mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx)); LogPrintf("ProcessMessageSwiftTX::ix - Transaction Lock Request: %s %s : accepted %s\n", pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), @@ -97,7 +95,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v return; } else { - mapTxLockReqRejected.insert(make_pair(tx.GetHash(), tx)); + mapTxLockReqRejected.insert(std::make_pair(tx.GetHash(), tx)); // can we get the conflicting transaction as proof? @@ -105,9 +103,9 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), tx.GetHash().ToString().c_str()); - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (!mapLockedInputs.count(in.prevout)) { - mapLockedInputs.insert(make_pair(in.prevout, tx.GetHash())); + mapLockedInputs.insert(std::make_pair(in.prevout, tx.GetHash())); } } @@ -121,7 +119,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v //reprocess the last 15 blocks ReprocessBlocks(15); - mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); + mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx)); } } } @@ -140,7 +138,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v return; } - mapTxLockVote.insert(make_pair(ctx.GetHash(), ctx)); + mapTxLockVote.insert(std::make_pair(ctx.GetHash(), ctx)); if (ProcessConsensusVote(pfrom, ctx)) { //Spam/Dos protection @@ -184,10 +182,10 @@ bool IsIXTXValid(const CTransaction& txCollateral) CAmount nValueOut = 0; bool missingTx = false; - BOOST_FOREACH (const CTxOut o, txCollateral.vout) + for (const CTxOut o : txCollateral.vout) nValueOut += o.nValue; - BOOST_FOREACH (const CTxIn i, txCollateral.vin) { + for (const CTxIn i : txCollateral.vin) { CTransaction tx2; uint256 hash; if (GetTransaction(i.prevout.hash, tx2, hash, true)) { @@ -249,7 +247,7 @@ int64_t CreateNewLock(CTransaction tx) newLock.nExpiration = GetTime() + (60 * 60); //locks expire after 60 minutes (24 confirmations) newLock.nTimeout = GetTime() + (60 * 5); newLock.txHash = tx.GetHash(); - mapTxLocks.insert(make_pair(tx.GetHash(), newLock)); + mapTxLocks.insert(std::make_pair(tx.GetHash(), newLock)); } else { mapTxLocks[tx.GetHash()].nBlockHeight = nBlockHeight; LogPrint("swiftx", "CreateNewLock - Transaction Lock Exists %s !\n", tx.GetHash().ToString().c_str()); @@ -336,7 +334,7 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx) newLock.nExpiration = GetTime() + (60 * 60); newLock.nTimeout = GetTime() + (60 * 5); newLock.txHash = ctx.txHash; - mapTxLocks.insert(make_pair(ctx.txHash, newLock)); + mapTxLocks.insert(std::make_pair(ctx.txHash, newLock)); } else LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Transaction Lock Exists %s !\n", ctx.txHash.ToString().c_str()); @@ -369,9 +367,9 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx) #endif if (mapTxLockReq.count(ctx.txHash)) { - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (!mapLockedInputs.count(in.prevout)) { - mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash)); + mapLockedInputs.insert(std::make_pair(in.prevout, ctx.txHash)); } } } @@ -401,7 +399,7 @@ bool CheckForConflictingLocks(CTransaction& tx) Blocks could have been rejected during this time, which is OK. After they cancel out, the client will rescan the blocks and find they're acceptable and then take the chain with the most work. */ - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { LogPrintf("SwiftX::CheckForConflictingLocks - found two complete conflicting locks - removing both. %s %s", tx.GetHash().ToString().c_str(), mapLockedInputs[in.prevout].ToString().c_str()); @@ -443,13 +441,13 @@ void CleanTransactionLocksList() if (mapTxLockReq.count(it->second.txHash)) { CTransaction& tx = mapTxLockReq[it->second.txHash]; - BOOST_FOREACH (const CTxIn& in, tx.vin) + for (const CTxIn& in : tx.vin) mapLockedInputs.erase(in.prevout); mapTxLockReq.erase(it->second.txHash); mapTxLockReqRejected.erase(it->second.txHash); - BOOST_FOREACH (CConsensusVote& v, it->second.vecConsensusVotes) + for (CConsensusVote& v : it->second.vecConsensusVotes) mapTxLockVote.erase(v.GetHash()); } @@ -529,7 +527,7 @@ bool CConsensusVote::Sign() bool CTransactionLock::SignaturesValid() { - BOOST_FOREACH (CConsensusVote vote, vecConsensusVotes) { + for (CConsensusVote vote : vecConsensusVotes) { int n = mnodeman.GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_SWIFTTX_PROTO_VERSION); if (n == -1) { @@ -566,7 +564,7 @@ int CTransactionLock::CountSignatures() if (nBlockHeight == 0) return -1; int n = 0; - BOOST_FOREACH (CConsensusVote v, vecConsensusVotes) { + for (CConsensusVote v : vecConsensusVotes) { if (v.nBlockHeight == nBlockHeight) { n++; } diff --git a/src/swifttx.h b/src/swifttx.h index c5dff6322e5d..e6eab74de15c 100644 --- a/src/swifttx.h +++ b/src/swifttx.h @@ -26,19 +26,16 @@ #define SWIFTTX_SIGNATURES_REQUIRED 6 #define SWIFTTX_SIGNATURES_TOTAL 10 -using namespace std; -using namespace boost; - class CConsensusVote; class CTransaction; class CTransactionLock; static const int MIN_SWIFTTX_PROTO_VERSION = 70103; -extern map mapTxLockReq; -extern map mapTxLockReqRejected; -extern map mapTxLockVote; -extern map mapTxLocks; +extern std::map mapTxLockReq; +extern std::map mapTxLockReqRejected; +extern std::map mapTxLockVote; +extern std::map mapTxLocks; extern std::map mapLockedInputs; extern int nCompleteTXLocks; diff --git a/src/sync.cpp b/src/sync.cpp index f2d75404f0b0..dd645dc3daf2 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -5,15 +5,18 @@ #include "sync.h" +#include +#include + #include "util.h" #include "utilstrencodings.h" #include -#include -#include - #ifdef DEBUG_LOCKCONTENTION +#if !defined(HAVE_THREAD_LOCAL) +static_assert(false, "thread_local is not supported"); +#endif void PrintLockContention(const char* pszName, const char* pszFile, int nLine) { LogPrintf("LOCKCONTENTION: %s\n", pszName); @@ -47,10 +50,8 @@ struct CLockLocation { return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); } - std::string MutexName() const { return mutexName; } - - bool fTry; private: + bool fTry; std::string mutexName; std::string sourceFile; int sourceLine; @@ -71,16 +72,16 @@ struct LockData { LockOrders lockorders; InvLockOrders invlockorders; - boost::mutex dd_mutex; + std::mutex dd_mutex; } static lockdata; -boost::thread_specific_ptr lockstack; +static thread_local LockStack g_lockstack; static void potential_deadlock_detected(const std::pair& mismatch, const LockStack& s1, const LockStack& s2) { LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); LogPrintf("Previous lock order was:\n"); - BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) { + for (const std::pair& i : s2) { if (i.first == mismatch.first) { LogPrintf(" (1)"); } @@ -90,7 +91,7 @@ static void potential_deadlock_detected(const std::pair& mismatch, LogPrintf(" %s\n", i.second.ToString()); } LogPrintf("Current lock order is:\n"); - BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) { + for (const std::pair& i : s1) { if (i.first == mismatch.first) { LogPrintf(" (1)"); } @@ -101,23 +102,20 @@ static void potential_deadlock_detected(const std::pair& mismatch, } } -static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) +static void push_lock(void* c, const CLockLocation& locklocation) { - if (lockstack.get() == NULL) - lockstack.reset(new LockStack); - - boost::unique_lock lock(lockdata.dd_mutex); + std::lock_guard lock(lockdata.dd_mutex); - (*lockstack).push_back(std::make_pair(c, locklocation)); + g_lockstack.push_back(std::make_pair(c, locklocation)); - BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) { + for (const std::pair& i : g_lockstack) { if (i.first == c) break; std::pair p1 = std::make_pair(i.first, c); if (lockdata.lockorders.count(p1)) continue; - lockdata.lockorders[p1] = (*lockstack); + lockdata.lockorders[p1] = g_lockstack; std::pair p2 = std::make_pair(c, i.first); lockdata.invlockorders.insert(p2); @@ -128,12 +126,12 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) static void pop_lock() { - (*lockstack).pop_back(); + g_lockstack.pop_back(); } void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry); + push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry)); } void LeaveCritical() @@ -144,14 +142,14 @@ void LeaveCritical() std::string LocksHeld() { std::string result; - BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack) + for (const std::pair& i : g_lockstack) result += i.second.ToString() + std::string("\n"); return result; } void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) { - BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack) + for (const std::pair& i : g_lockstack) if (i.first == cs) return; fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str()); @@ -164,8 +162,8 @@ void DeleteLock(void* cs) // We're already shutting down. return; } - boost::unique_lock lock(lockdata.dd_mutex); - std::pair item = std::make_pair(cs, (void*)0); + std::lock_guard lock(lockdata.dd_mutex); + std::pair item = std::make_pair(cs, nullptr); LockOrders::iterator it = lockdata.lockorders.lower_bound(item); while (it != lockdata.lockorders.end() && it->first.first == cs) { std::pair invitem = std::make_pair(it->first.second, it->first.first); diff --git a/src/sync.h b/src/sync.h index 4838dfe9d913..d83a03ff8f9f 100644 --- a/src/sync.h +++ b/src/sync.h @@ -9,10 +9,9 @@ #include "threadsafety.h" -#include -#include -#include -#include +#include +#include +#include ///////////////////////////////////////////////// @@ -23,17 +22,17 @@ /* CCriticalSection mutex; - boost::recursive_mutex mutex; + std::recursive_mutex mutex; LOCK(mutex); - boost::unique_lock criticalblock(mutex); + std::unique_lock criticalblock(mutex); LOCK2(mutex1, mutex2); - boost::unique_lock criticalblock1(mutex1); - boost::unique_lock criticalblock2(mutex2); + std::unique_lock criticalblock1(mutex1); + std::unique_lock criticalblock2(mutex2); TRY_LOCK(mutex, name); - boost::unique_lock name(mutex, boost::try_to_lock_t); + std::unique_lock name(mutex, std::try_to_lock_t); ENTER_CRITICAL_SECTION(mutex); // no RAII mutex.lock(); @@ -87,10 +86,10 @@ void static inline DeleteLock(void* cs) {} #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) /** - * Wrapped boost mutex: supports recursive locking, but no waiting + * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ -class CCriticalSection : public AnnotatedMixin +class CCriticalSection : public AnnotatedMixin { public: ~CCriticalSection() { @@ -98,22 +97,24 @@ class CCriticalSection : public AnnotatedMixin } }; -/** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin CWaitableCriticalSection; +/** Wrapped mutex: supports waiting but not recursive locking */ +typedef AnnotatedMixin CWaitableCriticalSection; -/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ -typedef boost::condition_variable CConditionVariable; +/** Just a typedef for std::condition_variable, can be wrapped later if desired */ +typedef std::condition_variable CConditionVariable; + +/** Just a typedef for std::unique_lock, can be wrapped later if desired */ +typedef std::unique_lock WaitableLock; #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around boost::unique_lock */ -template -class SCOPED_LOCKABLE CMutexLock +/** Wrapper around std::unique_lock */ +class SCOPED_LOCKABLE CCriticalBlock { private: - boost::unique_lock lock; + std::unique_lock lock; void Enter(const char* pszName, const char* pszFile, int nLine) { @@ -138,7 +139,7 @@ class SCOPED_LOCKABLE CMutexLock } public: - CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock) + CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -146,18 +147,18 @@ class SCOPED_LOCKABLE CMutexLock Enter(pszName, pszFile, nLine); } - CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) + CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; - lock = boost::unique_lock(*pmutexIn, boost::defer_lock); + lock = std::unique_lock(*pmutexIn, std::defer_lock); if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } - ~CMutexLock() UNLOCK_FUNCTION() + ~CCriticalBlock() UNLOCK_FUNCTION() { if (lock.owns_lock()) LeaveCritical(); @@ -169,8 +170,6 @@ class SCOPED_LOCKABLE CMutexLock } }; -typedef CMutexLock CCriticalBlock; - #define PASTE(x, y) x ## y #define PASTE2(x, y) PASTE(x, y) @@ -193,25 +192,23 @@ typedef CMutexLock CCriticalBlock; class CSemaphore { private: - boost::condition_variable condition; - boost::mutex mutex; + std::condition_variable condition; + std::mutex mutex; int value; public: - CSemaphore(int init) : value(init) {} + explicit CSemaphore(int init) : value(init) {} void wait() { - boost::unique_lock lock(mutex); - while (value < 1) { - condition.wait(lock); - } + std::unique_lock lock(mutex); + condition.wait(lock, [&]() { return value >= 1; }); value--; } bool try_wait() { - boost::unique_lock lock(mutex); + std::lock_guard lock(mutex); if (value < 1) return false; value--; @@ -221,7 +218,7 @@ class CSemaphore void post() { { - boost::unique_lock lock(mutex); + std::lock_guard lock(mutex); value++; } condition.notify_one(); @@ -264,13 +261,12 @@ class CSemaphoreGrant grant.Release(); grant.sem = sem; grant.fHaveGrant = fHaveGrant; - sem = NULL; fHaveGrant = false; } - CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {} + CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {} - CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false) + explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false) { if (fTry) TryAcquire(); @@ -283,7 +279,7 @@ class CSemaphoreGrant Release(); } - operator bool() + operator bool() const { return fHaveGrant; } diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index 94dd2ba666c6..3db9589a1264 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -9,12 +9,12 @@ #include "checkpoints.h" #include "uint256.h" +#include "test_phore.h" #include -using namespace std; -BOOST_AUTO_TEST_SUITE(Checkpoints_tests) +BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sanity) { diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 39102bf65f4c..8eeffd2ee166 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -16,11 +16,13 @@ #include "serialize.h" #include "util.h" +#include "test/test_phore.h" + #include #include // for 'map_list_of()' #include -#include + #include // Tests this internal-to-main.cpp method: @@ -41,7 +43,7 @@ CService ip(uint32_t i) return CService(CNetAddr(s), Params().GetDefaultPort()); } -BOOST_AUTO_TEST_SUITE(DoS_tests) +BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) BOOST_AUTO_TEST_CASE(DoS_banning) { diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 6074830be772..924edd10539a 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -5,14 +5,16 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" +#include "test/test_phore.h" + #include -#include + #include extern CWallet* pwalletMain; -BOOST_AUTO_TEST_SUITE(accounting_tests) +BOOST_FIXTURE_TEST_SUITE(accounting_tests, TestingSetup) static void GetResults(CWalletDB& walletdb, std::map& results) @@ -22,7 +24,7 @@ GetResults(CWalletDB& walletdb, std::map& results) results.clear(); BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK); walletdb.ListAccountCreditDebit("", aes); - BOOST_FOREACH(CAccountingEntry& ae, aes) + for (CAccountingEntry& ae : aes) { results[ae.nOrderPos] = ae; } diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp new file mode 100644 index 000000000000..f2aaa78a5bd4 --- /dev/null +++ b/src/test/addrman_tests.cpp @@ -0,0 +1,520 @@ +// Copyright (c) 2012-2013 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "addrman.h" +#include "test/test_pivx.h" +#include +#include +#include // for ReadLE64 + +#include "hash.h" +#include "random.h" + +class CAddrManTest : public CAddrMan +{ + uint64_t state; + +public: + CAddrManTest() + { + state = 1; + } + + //! Ensure that bucket placement is always the same for testing purposes. + void MakeDeterministic() + { + nKey.SetNull(); + seed_insecure_rand(true); + } + + int RandomInt(int nMax) + { + state = ReadLE64((CHashWriter(SER_GETHASH, 0) << state).GetHash().begin()); + return (unsigned int)(state % nMax); + } + + CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL) + { + return CAddrMan::Find(addr, pnId); + } + + CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = NULL) + { + return CAddrMan::Create(addr, addrSource, pnId); + } + + void Delete(int nId) + { + CAddrMan::Delete(nId); + } +}; + +BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(addrman_simple) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + // Test 1: Does Addrman respond correctly when empty. + BOOST_CHECK(addrman.size() == 0); + CAddrInfo addr_null = addrman.Select(); + BOOST_CHECK(addr_null.ToString() == "[::]:0"); + + // Test 2: Does Addrman::Add work as expected. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret1 = addrman.Select(); + BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); + + // Test 3: Does IP address deduplication work correctly. + // Expected dup IP should not be added. + CService addr1_dup = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1_dup), source); + BOOST_CHECK(addrman.size() == 1); + + + // Test 5: New table has one addr and we add a diff addr we should + // have two addrs. + CService addr2 = CService("250.1.1.2", 8333); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 2); + + // Test 6: AddrMan::Clear() should empty the new table. + addrman.Clear(); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo addr_null2 = addrman.Select(); + BOOST_CHECK(addr_null2.ToString() == "[::]:0"); +} + +BOOST_AUTO_TEST_CASE(addrman_ports) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + // Test 7; Addr with same IP but diff port does not replace existing addr. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + + CService addr1_port = CService("250.1.1.1", 8334); + addrman.Add(CAddress(addr1_port), source); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret2 = addrman.Select(); + BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333"); + + // Test 8: Add same IP but diff port to tried table, it doesn't get added. + // Perhaps this is not ideal behavior but it is the current behavior. + addrman.Good(CAddress(addr1_port)); + BOOST_CHECK(addrman.size() == 1); + bool newOnly = true; + CAddrInfo addr_ret3 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); +} + + +BOOST_AUTO_TEST_CASE(addrman_select) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + // Test 9: Select from new with 1 addr in new. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + + bool newOnly = true; + CAddrInfo addr_ret1 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); + + // Test 10: move addr to tried, select from new expected nothing returned. + addrman.Good(CAddress(addr1)); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret2 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret2.ToString() == "[::]:0"); + + CAddrInfo addr_ret3 = addrman.Select(); + BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); + + BOOST_CHECK(addrman.size() == 1); + + + // Add three addresses to new table. + CService addr2 = CService("250.3.1.1", 8333); + CService addr3 = CService("250.3.2.2", 9999); + CService addr4 = CService("250.3.3.3", 9999); + + addrman.Add(CAddress(addr2), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr3), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr4), CService("250.4.1.1", 8333)); + + // Add three addresses to tried table. + CService addr5 = CService("250.4.4.4", 8333); + CService addr6 = CService("250.4.5.5", 7777); + CService addr7 = CService("250.4.6.6", 8333); + + addrman.Add(CAddress(addr5), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr5)); + addrman.Add(CAddress(addr6), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr6)); + addrman.Add(CAddress(addr7), CService("250.1.1.3", 8333)); + addrman.Good(CAddress(addr7)); + + // Test 11: 6 addrs + 1 addr from last test = 7. + BOOST_CHECK(addrman.size() == 7); + + // Test 12: Select pulls from new and tried regardless of port number. + BOOST_CHECK(addrman.Select().ToString() == "250.4.6.6:8333"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.2.2:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.3.3:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.4.4.4:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_new_collisions) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + for (int i = 1; i < 18; i++) { + CService addr = CService("250.1.1." + boost::to_string(i)); + addrman.Add(CAddress(addr), source); + + //Test 13: No collision in new table yet. + BOOST_CHECK(addrman.size() == i); + } + + //Test 14: new table collision! + CService addr1 = CService("250.1.1.18"); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 17); + + CService addr2 = CService("250.1.1.19"); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 18); +} + +BOOST_AUTO_TEST_CASE(addrman_tried_collisions) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + for (int i = 1; i < 80; i++) { + CService addr = CService("250.1.1." + boost::to_string(i)); + addrman.Add(CAddress(addr), source); + addrman.Good(CAddress(addr)); + + //Test 15: No collision in tried table yet. + BOOST_TEST_MESSAGE(addrman.size()); + BOOST_CHECK(addrman.size() == i); + } + + //Test 16: tried table collision! + CService addr1 = CService("250.1.1.80"); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 79); + + CService addr2 = CService("250.1.1.81"); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 80); +} + +BOOST_AUTO_TEST_CASE(addrman_find) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + CAddress addr3 = CAddress(CService("251.255.2.1", 8333)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.1.2.2"); + + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + + // Test 17: ensure Find returns an IP matching what we searched on. + CAddrInfo* info1 = addrman.Find(addr1); + BOOST_CHECK(info1); + if (info1) + BOOST_CHECK(info1->ToString() == "250.1.2.1:8333"); + + // Test 18; Find does not discriminate by port number. + CAddrInfo* info2 = addrman.Find(addr2); + BOOST_CHECK(info2); + if (info2) + BOOST_CHECK(info2->ToString() == info1->ToString()); + + // Test 19: Find returns another IP matching what we searched on. + CAddrInfo* info3 = addrman.Find(addr3); + BOOST_CHECK(info3); + if (info3) + BOOST_CHECK(info3->ToString() == "251.255.2.1:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_create) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId); + + // Test 20: The result should be the same as the input addr. + BOOST_CHECK(pinfo->ToString() == "250.1.2.1:8333"); + + CAddrInfo* info2 = addrman.Find(addr1); + BOOST_CHECK(info2->ToString() == "250.1.2.1:8333"); +} + + +BOOST_AUTO_TEST_CASE(addrman_delete) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + addrman.Create(addr1, source1, &nId); + + // Test 21: Delete should actually delete the addr. + BOOST_CHECK(addrman.size() == 1); + addrman.Delete(nId); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo* info2 = addrman.Find(addr1); + BOOST_CHECK(info2 == NULL); +} + +BOOST_AUTO_TEST_CASE(addrman_getaddr) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + // Test 22: Sanity check, GetAddr should never return anything if addrman + // is empty. + BOOST_CHECK(addrman.size() == 0); + std::vector vAddr1 = addrman.GetAddr(); + BOOST_CHECK(vAddr1.size() == 0); + + CAddress addr1 = CAddress(CService("250.250.2.1", 8333)); + addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false + CAddress addr2 = CAddress(CService("250.251.2.2", 9999)); + addr2.nTime = GetAdjustedTime(); + CAddress addr3 = CAddress(CService("251.252.2.3", 8333)); + addr3.nTime = GetAdjustedTime(); + CAddress addr4 = CAddress(CService("252.253.3.4", 8333)); + addr4.nTime = GetAdjustedTime(); + CAddress addr5 = CAddress(CService("252.254.4.5", 8333)); + addr5.nTime = GetAdjustedTime(); + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.2.3.3"); + + // Test 23: Ensure GetAddr works with new addresses. + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + addrman.Add(addr4, source2); + addrman.Add(addr5, source1); + + // GetAddr returns 23% of addresses, 23% of 5 is 1 rounded down. + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 24: Ensure GetAddr works with new and tried addresses. + addrman.Good(CAddress(addr1)); + addrman.Good(CAddress(addr2)); + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 25: Ensure GetAddr still returns 23% when addrman has many addrs. + for (unsigned int i = 1; i < (8 * 256); i++) { + int octet1 = i % 256; + int octet2 = (i / 256) % 256; + int octet3 = (i / (256 * 2)) % 256; + std::string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; + CAddress addr = CAddress(CService(strAddr)); + + // Ensure that for all addrs in addrman, isTerrible == false. + addr.nTime = GetAdjustedTime(); + addrman.Add(addr, CNetAddr(strAddr)); + if (i % 8 == 0) + addrman.Good(addr); + } + std::vector vAddr = addrman.GetAddr(); + + size_t percent23 = (addrman.size() * 23) / 100; + BOOST_CHECK(vAddr.size() == percent23); + BOOST_CHECK(vAddr.size() == 461); + // (Addrman.size() < number of addresses added) due to address collisons. + BOOST_CHECK(addrman.size() == 2007); +} + + +BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.1.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.1.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.1.1"); + + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + + BOOST_CHECK(info1.GetTriedBucket(nKey1) == 40); + + // Test 26: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2)); + + // Test 27: Two addresses with same IP but different ports can map to + // different buckets because they have different keys. + CAddrInfo info2 = CAddrInfo(addr2, source1); + + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1)); + + std::set buckets; + for (int i = 0; i < 255; i++) { + CAddrInfo infoi = CAddrInfo( + CAddress(CService("250.1.1." + boost::to_string(i))), + CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 28: IP addresses in the same group (\16 prefix for IPv4) should + // never get more than 8 buckets + BOOST_CHECK(buckets.size() == 8); + + buckets.clear(); + for (int j = 0; j < 255; j++) { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250." + boost::to_string(j) + ".1.1")), + CNetAddr("250." + boost::to_string(j) + ".1.1")); + int bucket = infoj.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 29: IP addresses in the different groups should map to more than + // 8 buckets. + BOOST_CHECK(buckets.size() == 160); +} + +BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + BOOST_CHECK(info1.GetNewBucket(nKey1) == 786); + + // Test 30: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2)); + + // Test 31: Ports should not effect bucket placement in the addr + CAddrInfo info2 = CAddrInfo(addr2, source1); + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetNewBucket(nKey1) == info2.GetNewBucket(nKey1)); + + std::set buckets; + for (int i = 0; i < 255; i++) { + CAddrInfo infoi = CAddrInfo( + CAddress(CService("250.1.1." + boost::to_string(i))), + CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 32: IP addresses in the same group (\16 prefix for IPv4) should + // always map to the same bucket. + BOOST_CHECK(buckets.size() == 1); + + buckets.clear(); + for (int j = 0; j < 4 * 255; j++) { + CAddrInfo infoj = CAddrInfo(CAddress( + CService( + boost::to_string(250 + (j / 255)) + "." + boost::to_string(j % 256) + ".1.1")), + CNetAddr("251.4.1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 33: IP addresses in the same source groups should map to no more + // than 64 buckets. + BOOST_CHECK(buckets.size() <= 64); + + buckets.clear(); + for (int p = 0; p < 255; p++) { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250.1.1.1")), + CNetAddr("250." + boost::to_string(p) + ".1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 34: IP addresses in the different source groups should map to more + // than 64 buckets. + BOOST_CHECK(buckets.size() > 64); +} +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 4869ba52acce..5ca519f0c855 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -15,10 +15,12 @@ #include "util.h" #include "utilstrencodings.h" +#include "test/test_phore.h" + #include #include -#include + #include #if 0 @@ -78,7 +80,7 @@ } #endif -struct ReadAlerts +struct ReadAlerts : public TestingSetup { ReadAlerts() { @@ -118,7 +120,7 @@ BOOST_AUTO_TEST_CASE(AlertApplies) { SetMockTime(11); - BOOST_FOREACH(const CAlert& alert, alerts) + for (const CAlert& alert : alerts) { BOOST_CHECK(alert.CheckSignature()); } @@ -163,7 +165,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify) mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); - BOOST_FOREACH(CAlert alert, alerts) + for (CAlert alert : alerts) alert.ProcessAlert(false); std::vector r = read_lines(temp); diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 69888da3dfa0..93202fa599a4 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -5,10 +5,11 @@ #include "util.h" #include "allocators.h" +#include "test/test_phore.h" #include -BOOST_AUTO_TEST_SUITE(allocator_tests) +BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup) // Dummy memory page locker for platform independent tests static const void *last_lock_addr, *last_unlock_addr; diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index 203ef75ca1e4..da6e228cef9f 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -12,9 +12,9 @@ #include "arith_uint256.h" #include #include "version.h" +#include "test/test_phore.h" -BOOST_AUTO_TEST_SUITE(arith_uint256_tests) -///BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) /// Convert vector to arith_uint256, via uint256 blob inline arith_uint256 arith_uint256V(const std::vector& vch) @@ -67,7 +67,7 @@ std::string ArrayToString(const unsigned char A[], unsigned int width) BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality { BOOST_CHECK(1 == 0+1); - // constructor arith_uint256(vector): + // constructor arith_uint256(std::vector): BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32)); BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32)); BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray,32)); diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 68617abbdd5f..768e4b46e6f3 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -3,10 +3,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilstrencodings.h" +#include "test/test_phore.h" #include -BOOST_AUTO_TEST_SUITE(base32_tests) +BOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(base32_testvectors) { diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 2bd8018649be..ae0573dda1cf 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -11,15 +11,16 @@ #include "uint256.h" #include "util.h" #include "utilstrencodings.h" +#include "test/test_phore.h" + -#include #include #include extern UniValue read_json(const std::string& jsondata); -BOOST_AUTO_TEST_SUITE(base58_tests) +BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup) // Goal: test low-level base58 encoding functionality BOOST_AUTO_TEST_CASE(base58_EncodeBase58) @@ -36,7 +37,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) std::vector sourcedata = ParseHex(test[0].get_str()); std::string base58string = test[1].get_str(); BOOST_CHECK_MESSAGE( - EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string, + EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()) == base58string, strTest); } } diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index f2bf3326ad8d..bbd059c1fff1 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -3,10 +3,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilstrencodings.h" +#include "test/test_phore.h" #include -BOOST_AUTO_TEST_SUITE(base64_tests) +BOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(base64_testvectors) { diff --git a/src/test/benchmark_zerocoin.cpp b/src/test/benchmark_zerocoin.cpp index 154e282c7ada..fce0061c760f 100644 --- a/src/test/benchmark_zerocoin.cpp +++ b/src/test/benchmark_zerocoin.cpp @@ -25,9 +25,8 @@ #include "libzerocoin/Coin.h" #include "libzerocoin/CoinSpend.h" #include "libzerocoin/Accumulator.h" +#include "test_phore.h" -using namespace std; -using namespace libzerocoin; #define COLOR_STR_GREEN "\033[32m" #define COLOR_STR_NORMAL "\033[0m" @@ -51,75 +50,75 @@ ZerocoinParams *gg_Params; class Timer { - timeval timer[2]; + timeval timer[2]; public: - timeval start() - { - gettimeofday(&this->timer[0], NULL); - return this->timer[0]; - } - - timeval stop() - { - gettimeofday(&this->timer[1], NULL); - return this->timer[1]; - } - - int duration() const - { - int secs(this->timer[1].tv_sec - this->timer[0].tv_sec); - int usecs(this->timer[1].tv_usec - this->timer[0].tv_usec); - - if(usecs < 0) - { - --secs; - usecs += 1000000; - } - - return static_cast(secs * 1000 + usecs / 1000.0 + 0.5); - } + timeval start() + { + gettimeofday(&this->timer[0], NULL); + return this->timer[0]; + } + + timeval stop() + { + gettimeofday(&this->timer[1], NULL); + return this->timer[1]; + } + + int duration() const + { + int secs(this->timer[1].tv_sec - this->timer[0].tv_sec); + int usecs(this->timer[1].tv_usec - this->timer[0].tv_usec); + + if(usecs < 0) + { + --secs; + usecs += 1000000; + } + + return static_cast(secs * 1000 + usecs / 1000.0 + 0.5); + } }; // Global timer Timer timer; void -gLogTestResult(string testName, bool (*testPtr)()) +gLogTestResult(std::string testName, bool (*testPtr)()) { - string colorGreen(COLOR_STR_GREEN); - string colorNormal(COLOR_STR_NORMAL); - string colorRed(COLOR_STR_RED); + std::string colorGreen(COLOR_STR_GREEN); + std::string colorNormal(COLOR_STR_NORMAL); + std::string colorRed(COLOR_STR_RED); - cout << "Testing if " << testName << "..." << endl; + cout << "Testing if " << testName << "..." << endl; - bool testResult = testPtr(); + bool testResult = testPtr(); - if (testResult == true) { - cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; - ggSuccessfulTests++; - } else { - cout << colorRed << "\t[FAIL]" << colorNormal << endl; - } + if (testResult == true) { + cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + ggSuccessfulTests++; + } else { + cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } - ggNumTests++; + ggNumTests++; } CBigNum gGetTestModulus() { - static CBigNum testModulus(0); + static CBigNum testModulus(0); - // TODO: should use a hard-coded RSA modulus for testing - if (!testModulus) { - CBigNum p, q; - p = CBigNum::generatePrime(1024, false); - q = CBigNum::generatePrime(1024, false); - testModulus = p * q; - } + // TODO: should use a hard-coded RSA modulus for testing + if (!testModulus) { + CBigNum p, q; + p = CBigNum::generatePrime(1024, false); + q = CBigNum::generatePrime(1024, false); + testModulus = p * q; + } - return testModulus; + return testModulus; } ////////// @@ -130,285 +129,286 @@ gGetTestModulus() bool Testb_GenRSAModulus() { - CBigNum result = gGetTestModulus(); - - if (!result) { - return false; - } - else { - return true; - } + CBigNum result = gGetTestModulus(); + + if (!result) { + return false; + } + else { + return true; + } } bool Testb_CalcParamSizes() { - bool result = true; + bool result = true; #if 0 - uint32_t pLen, qLen; - - try { - calculateGroupParamLengths(4000, 80, &pLen, &qLen); - if (pLen < 1024 || qLen < 256) { - result = false; - } - calculateGroupParamLengths(4000, 96, &pLen, &qLen); - if (pLen < 2048 || qLen < 256) { - result = false; - } - calculateGroupParamLengths(4000, 112, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - calculateGroupParamLengths(4000, 120, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - calculateGroupParamLengths(4000, 128, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - } catch (exception &e) { - result = false; - } + uint32_t pLen, qLen; + + try { + calculateGroupParamLengths(4000, 80, &pLen, &qLen); + if (pLen < 1024 || qLen < 256) { + result = false; + } + calculateGroupParamLengths(4000, 96, &pLen, &qLen); + if (pLen < 2048 || qLen < 256) { + result = false; + } + calculateGroupParamLengths(4000, 112, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + calculateGroupParamLengths(4000, 120, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + calculateGroupParamLengths(4000, 128, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + } catch (exception &e) { + result = false; + } #endif - return result; + return result; } bool Testb_GenerateGroupParams() { - uint32_t pLen = 1024, qLen = 256, count; - IntegerGroupParams group; + uint32_t pLen = 1024, qLen = 256, count; + IntegerGroupParams group; - for (count = 0; count < 1; count++) { + for (count = 0; count < 1; count++) { - try { - group = deriveIntegerGroupParams(calculateSeed(gGetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen); - } catch (std::runtime_error e) { - cout << "Caught exception " << e.what() << endl; - return false; - } + try { + group = deriveIntegerGroupParams(calculateSeed(gGetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen); + } catch (std::runtime_error e) { + cout << "Caught exception " << e.what() << endl; + return false; + } - // Now perform some simple tests on the resulting parameters - if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) { - return false; - } + // Now perform some simple tests on the resulting parameters + if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) { + return false; + } - CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus); - //cout << "g^q mod p = " << c << endl; - if (!(c.isOne())) return false; + CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus); + //cout << "g^q mod p = " << c << endl; + if (!(c.isOne())) return false; - // Try at multiple parameter sizes - pLen = pLen * 1.5; - qLen = qLen * 1.5; - } + // Try at multiple parameter sizes + pLen = pLen * 1.5; + qLen = qLen * 1.5; + } - return true; + return true; } bool Testb_ParamGen() { - bool result = true; + bool result = true; - try { - timer.start(); - // Instantiating testParams runs the parameter generation code - ZerocoinParams testParams(gGetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); - timer.stop(); + try { + timer.start(); + // Instantiating testParams runs the parameter generation code + ZerocoinParams testParams(gGetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); + timer.stop(); - cout << "\tPARAMGEN ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; - } catch (runtime_error e) { - cout << e.what() << endl; - result = false; - } + cout << "\tPARAMGEN ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + } catch (runtime_error e) { + cout << e.what() << endl; + result = false; + } - return result; + return result; } bool Testb_Accumulator() { - // This test assumes a list of coins were generated during - // the Testb_MintCoin() test. - if (ggCoins[0] == NULL) { - return false; - } - try { - // Accumulate the coin list from first to last into one accumulator + // This test assumes a list of coins were generated during + // the Testb_MintCoin() test. + if (ggCoins[0] == NULL) { + return false; + } + try { + // Accumulate the coin list from first to last into one accumulator Accumulator accOne(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); Accumulator accTwo(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); Accumulator accThree(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); Accumulator accFour(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); - AccumulatorWitness wThree(gg_Params, accThree, ggCoins[0]->getPublicCoin()); - - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - accOne += ggCoins[i]->getPublicCoin(); - accTwo += ggCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); - accThree += ggCoins[i]->getPublicCoin(); - wThree += ggCoins[i]->getPublicCoin(); - if(i != 0) { - accFour += ggCoins[i]->getPublicCoin(); - } - } - - // Compare the accumulated results - if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) { - cout << "Accumulators don't match" << endl; - return false; - } - - if(accFour.getValue() != wThree.getValue()) { - cout << "Witness math not working," << endl; - return false; - } - - // Verify that the witness is correct - if (!wThree.VerifyWitness(accThree, ggCoins[0]->getPublicCoin()) ) { - cout << "Witness not valid" << endl; - return false; - } - - } catch (runtime_error e) { - cout << e.what() << endl; + AccumulatorWitness wThree(gg_Params, accThree, ggCoins[0]->getPublicCoin()); + + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + accOne += ggCoins[i]->getPublicCoin(); + accTwo += ggCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); + accThree += ggCoins[i]->getPublicCoin(); + wThree += ggCoins[i]->getPublicCoin(); + if(i != 0) { + accFour += ggCoins[i]->getPublicCoin(); + } + } + + // Compare the accumulated results + if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) { + cout << "Accumulators don't match" << endl; + return false; + } + + if(accFour.getValue() != wThree.getValue()) { + cout << "Witness math not working," << endl; + return false; + } + + // Verify that the witness is correct + if (!wThree.VerifyWitness(accThree, ggCoins[0]->getPublicCoin()) ) { + cout << "Witness not valid" << endl; + return false; + } + + } catch (runtime_error e) { + cout << e.what() << endl; return false; - } + } - return true; + return true; } bool Testb_MintCoin() { - try { - // Generate a list of coins - timer.start(); - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + try { + // Generate a list of coins + timer.start(); + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { ggCoins[i] = new PrivateCoin(gg_Params,CoinDenomination::ZQ_ONE); - } - timer.stop(); - } catch (exception &e) { - return false; - } + } + timer.stop(); + } catch (exception &e) { + return false; + } - cout << "\tMINT ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Coin: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; + cout << "\tMINT ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Coin: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; - return true; + return true; } bool Testb_MintAndSpend() { - try { - // This test assumes a list of coins were generated in Testb_MintCoin() - if (ggCoins[0] == NULL) - { - // No coins: mint some. - Testb_MintCoin(); - if (ggCoins[0] == NULL) { - return false; - } - } - - // Accumulate the list of generated coins into a fresh accumulator. - // The first one gets marked as accumulated for a witness, the - // others just get accumulated normally. + try { + // This test assumes a list of coins were generated in Testb_MintCoin() + if (ggCoins[0] == NULL) + { + // No coins: mint some. + Testb_MintCoin(); + if (ggCoins[0] == NULL) { + return false; + } + } + + // Accumulate the list of generated coins into a fresh accumulator. + // The first one gets marked as accumulated for a witness, the + // others just get accumulated normally. Accumulator acc(&gg_Params->accumulatorParams,CoinDenomination::ZQ_ONE); - AccumulatorWitness wAcc(gg_Params, acc, ggCoins[0]->getPublicCoin()); + AccumulatorWitness wAcc(gg_Params, acc, ggCoins[0]->getPublicCoin()); - timer.start(); - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - acc += ggCoins[i]->getPublicCoin(); - } - timer.stop(); + timer.start(); + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + acc += ggCoins[i]->getPublicCoin(); + } + timer.stop(); - cout << "\tACCUMULATOR ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; + cout << "\tACCUMULATOR ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; - timer.start(); - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - wAcc +=ggCoins[i]->getPublicCoin(); - } - timer.stop(); + timer.start(); + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + wAcc +=ggCoins[i]->getPublicCoin(); + } + timer.stop(); - cout << "\tWITNESS ELAPSED TIME: \n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; + cout << "\tWITNESS ELAPSED TIME: \n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; - // Now spend the coin - timer.start(); - CoinSpend spend(gg_Params, gg_Params, *(ggCoins[0]), acc, 0, wAcc, 0, SpendType::SPEND); //(0) presstab - timer.stop(); + // Now spend the coin + timer.start(); + CoinSpend spend(gg_Params, gg_Params, *(ggCoins[0]), acc, 0, wAcc, 0, SpendType::SPEND); //(0) presstab + timer.stop(); - cout << "\tSPEND ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + cout << "\tSPEND ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; - // Serialize the proof and deserialize into newSpend - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + // Serialize the proof and deserialize into newSpend + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - timer.start(); - ss << spend; - timer.stop(); + timer.start(); + ss << spend; + timer.stop(); - CoinSpend newSpend(gg_Params, gg_Params, ss); + CoinSpend newSpend(gg_Params, gg_Params, ss); - cout << "\tSERIALIZE ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + cout << "\tSERIALIZE ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; - // Finally, see if we can verify the deserialized proof (return our result) - timer.start(); - bool ret = newSpend.Verify(acc); - timer.stop(); + // Finally, see if we can verify the deserialized proof (return our result) + timer.start(); + bool ret = newSpend.Verify(acc); + timer.stop(); - cout << "\tSPEND VERIFY ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + cout << "\tSPEND VERIFY ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; - return ret; - } catch (runtime_error &e) { - cout << e.what() << endl; - return false; - } + return ret; + } catch (runtime_error &e) { + cout << e.what() << endl; + return false; + } - return false; + return false; } void Testb_RunAllTests() { - // Make a new set of parameters from a random RSA modulus - gg_Params = new ZerocoinParams(gGetTestModulus()); - - ggNumTests = ggSuccessfulTests = 0; - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - ggCoins[i] = NULL; - } - - // Run through all of the Zerocoin tests - gLogTestResult("an RSA modulus can be generated", Testb_GenRSAModulus); - gLogTestResult("parameter sizes are correct", Testb_CalcParamSizes); - gLogTestResult("group/field parameters can be generated", Testb_GenerateGroupParams); - gLogTestResult("parameter generation is correct", Testb_ParamGen); - gLogTestResult("coins can be minted", Testb_MintCoin); - gLogTestResult("the accumulator works", Testb_Accumulator); - gLogTestResult("a minted coin can be spent", Testb_MintAndSpend); - - // Summarize test results - if (ggSuccessfulTests < ggNumTests) { - cout << endl << "ERROR: SOME TESTS FAILED" << endl; - } - - // Clear any generated coins - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - delete ggCoins[i]; - } - - cout << ggSuccessfulTests << " out of " << ggNumTests << " tests passed." << endl << endl; - delete gg_Params; + // Make a new set of parameters from a random RSA modulus + gg_Params = new ZerocoinParams(gGetTestModulus()); + + ggNumTests = ggSuccessfulTests = 0; + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + ggCoins[i] = NULL; + } + + // Run through all of the Zerocoin tests + gLogTestResult("an RSA modulus can be generated", Testb_GenRSAModulus); + gLogTestResult("parameter sizes are correct", Testb_CalcParamSizes); + gLogTestResult("group/field parameters can be generated", Testb_GenerateGroupParams); + gLogTestResult("parameter generation is correct", Testb_ParamGen); + gLogTestResult("coins can be minted", Testb_MintCoin); + gLogTestResult("the accumulator works", Testb_Accumulator); + gLogTestResult("a minted coin can be spent", Testb_MintAndSpend); + + // Summarize test results + if (ggSuccessfulTests < ggNumTests) { + cout << endl << "ERROR: SOME TESTS FAILED" << endl; + } + + // Clear any generated coins + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + delete ggCoins[i]; + } + + cout << ggSuccessfulTests << " out of " << ggNumTests << " tests passed." << endl << endl; + delete gg_Params; } -BOOST_AUTO_TEST_SUITE(benchmark_zerocoin) + +BOOST_FIXTURE_TEST_SUITE(benchmark_zerocoin, TestingSetup) BOOST_AUTO_TEST_CASE(benchmark_test) { - cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " benchmark utility." << endl << endl; + cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " benchmark utility." << endl << endl; - Testb_RunAllTests(); + Testb_RunAllTests(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bignum.h b/src/test/bignum.h index f64c9872025f..3455d9617bd0 100644 --- a/src/test/bignum.h +++ b/src/test/bignum.h @@ -138,7 +138,7 @@ class CBigNum : public BIGNUM std::vector vch(nSize); BN_bn2mpi(this, &vch[0]); vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); + std::reverse(vch.begin(), vch.end()); return vch; } diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 93abe379fc77..83f00d190ac1 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -8,6 +8,7 @@ #include "key.h" #include "uint256.h" #include "util.h" +#include "test/test_phore.h" #include #include @@ -82,7 +83,7 @@ void RunTest(const TestVector &test) { CExtPubKey pubkey; key.SetMaster(&seed[0], seed.size()); pubkey = key.Neuter(); - BOOST_FOREACH(const TestDerivation &derive, test.vDerive) { + for (const TestDerivation &derive : test.vDerive) { unsigned char data[74]; key.Encode(data); pubkey.Encode(data); @@ -122,7 +123,7 @@ void RunTest(const TestVector &test) { } } -BOOST_AUTO_TEST_SUITE(bip32_tests) +BOOST_FIXTURE_TEST_SUITE(bip32_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bip32_test1) { RunTest(test1); diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py deleted file mode 100755 index 0eece14cfe3a..000000000000 --- a/src/test/bitcoin-util-test.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/python -# Copyright 2014 BitPay, Inc. -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import os -import bctest -import buildenv - -if __name__ == '__main__': - bctest.bctester(os.environ["srcdir"] + "/test/data", - "bitcoin-util-test.json",buildenv) - diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 5c15cc9c6980..f5546504e196 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -13,16 +13,15 @@ #include "uint256.h" #include "util.h" #include "utilstrencodings.h" +#include "test/test_phore.h" #include #include #include -using namespace std; -using namespace boost::tuples; -BOOST_AUTO_TEST_SUITE(bloom_tests) +BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) { @@ -42,8 +41,8 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); - vector vch = ParseHex("03614e9b050000000000000001"); - vector expected(vch.size()); + std::vector vch = ParseHex("03614e9b050000000000000001"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -74,8 +73,8 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); - vector vch = ParseHex("03ce4299050000000100008001"); - vector expected(vch.size()); + std::vector vch = ParseHex("03ce4299050000000100008001"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -85,24 +84,24 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) BOOST_AUTO_TEST_CASE(bloom_create_insert_key) { - string strSecret = string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); + std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); CBitcoinSecret vchSecret; BOOST_CHECK(vchSecret.SetString(strSecret)); CKey key = vchSecret.GetKey(); CPubKey pubkey = key.GetPubKey(); - vector vchPubKey(pubkey.begin(), pubkey.end()); + std::vector vchPubKey(pubkey.begin(), pubkey.end()); CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); filter.insert(vchPubKey); uint160 hash = pubkey.GetID(); - filter.insert(vector(hash.begin(), hash.end())); + filter.insert(std::vector(hash.begin(), hash.end())); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); - vector vch = ParseHex("038fc16b080000000000000001"); - vector expected(vch.size()); + std::vector vch = ParseHex("038fc16b080000000000000001"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -119,7 +118,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) // and one which spends it (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; - vector vch(ch, ch + sizeof(ch) -1); + std::vector vch(ch, ch + sizeof(ch) -1); CDataStream spendStream(vch, SER_DISK, CLIENT_VERSION); CTransaction spendingTx; spendStream >> spendingTx; @@ -157,7 +156,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); { - vector data(32 + sizeof(unsigned int)); + std::vector data(32 + sizeof(unsigned int)); memcpy(&data[0], prevOutPoint.hash.begin(), 32); memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); filter.insert(data); @@ -197,12 +196,12 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); - vector vMatched; + std::vector vMatched; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -242,12 +241,12 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); - vector vMatched; + std::vector vMatched; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -296,12 +295,12 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); - vector vMatched; + std::vector vMatched; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -351,7 +350,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); - vector vMatched; + std::vector vMatched; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -360,8 +359,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION); merkleStream << merkleBlock; - vector vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); - vector expected(vch.size()); + std::vector vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -385,12 +384,12 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); - vector vMatched; + std::vector vMatched; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) diff --git a/src/test/budget_tests.cpp b/src/test/budget_tests.cpp index c156644e2cb7..dc4aeca22778 100644 --- a/src/test/budget_tests.cpp +++ b/src/test/budget_tests.cpp @@ -2,12 +2,14 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test_phore.h" #include #include #include #include "masternode-budget.h" -BOOST_AUTO_TEST_SUITE(budget_tests) +BOOST_FIXTURE_TEST_SUITE(budget_tests, TestingSetup) void CheckBudgetValue(int nHeight, std::string strNetwork, CAmount nExpectedValue) { diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in deleted file mode 100644 index 1618bdeb764b..000000000000 --- a/src/test/buildenv.py.in +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/python -exeext="@EXEEXT@" diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 0703414e620e..da66a999dfa6 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -12,6 +12,7 @@ #include "consensus/validation.h" #include "main.h" #include "utiltime.h" +#include "test/test_phore.h" #include @@ -20,7 +21,7 @@ #include -BOOST_AUTO_TEST_SUITE(CheckBlock_tests) +BOOST_FIXTURE_TEST_SUITE(CheckBlock_tests, BasicTestingSetup) bool read_block(const std::string& filename, CBlock& block) { diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 3ecd301bc749..e78c80c436a8 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -5,6 +5,7 @@ #include "coins.h" #include "random.h" #include "uint256.h" +#include "test/test_phore.h" #include #include @@ -60,7 +61,7 @@ class CCoinsViewTest : public CCoinsView }; } -BOOST_AUTO_TEST_SUITE(coins_tests) +BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index bf404cf0cfa8..c166f2c8dc14 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -4,6 +4,7 @@ #include "compressor.h" #include "util.h" +#include "test/test_phore.h" #include @@ -21,7 +22,7 @@ // amounts 50 .. 21000000 #define NUM_MULTIPLES_50BTC 420000 -BOOST_AUTO_TEST_SUITE(compress_tests) +BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup) bool static TestEncode(uint64_t in) { return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in)); diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index f13a651a20f8..9f49ee89db31 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -11,6 +11,7 @@ #include "crypto/hmac_sha512.h" #include "random.h" #include "utilstrencodings.h" +#include "test/test_phore.h" #include @@ -18,7 +19,7 @@ #include #include -BOOST_AUTO_TEST_SUITE(crypto_tests) +BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup) template void TestVector(const Hasher &h, const In &in, const Out &out) { diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 1cf7ff62df13..1540c9fa233c 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -984,5 +984,50 @@ "P2SH,WITNESS", "Basic P2SH(P2WPKH) with wrong value" ], + +["0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","P2PK, bad sig"], +["0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640","DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG","","P2PKH, bad pubkey"], +["0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","P2PK anyonecanpay marked with normal hashtype"], +["0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac","HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL","P2SH","P2SH(P2PK), bad redeemscript"], +["0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac","HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL","P2SH","P2SH(P2PKH), bad sig"], +["0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","3-of-3, 2 sigs"], +["0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae","HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL","P2SH","P2SH(2-of-3), 1 sig"], +["0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","P2PK with too much R padding"], +["0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","P2PK with too much S padding"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","P2PK with too little R padding"], +["0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","DERSIG","P2PK NOT with bad sig with too much R padding"], +["0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","","P2PK NOT with too much R padding but no DERSIG"], +["0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","DERSIG","P2PK NOT with too much R padding"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","BIP66 example 1, with DERSIG"], +["0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","BIP66 example 2, without DERSIG"], +["0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","BIP66 example 2, with DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","BIP66 example 3, without DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","BIP66 example 3, with DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","BIP66 example 5, without DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","BIP66 example 5, with DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","BIP66 example 6, with DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","BIP66 example 7, with DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","BIP66 example 8, without DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","BIP66 example 8, with DERSIG"], +["0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","BIP66 example 9, without DERSIG"], +["0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","BIP66 example 9, with DERSIG"], +["0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","BIP66 example 10, with DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","BIP66 example 11, without DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","BIP66 example 11, with DERSIG"], +["0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","LOW_S","P2PK with high S"], +["0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","STRICTENC","P2PK with hybrid pubkey"], +["0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","","P2PK NOT with hybrid pubkey but no STRICTENC"], +["0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","STRICTENC","P2PK NOT with hybrid pubkey"], +["0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","STRICTENC","P2PK NOT with invalid hybrid pubkey"], +["0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201","1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG","STRICTENC","1-of-2 with the first 1 hybrid pubkey"], +["0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","STRICTENC","P2PK with undefined hashtype"], +["0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT","STRICTENC","P2PK NOT with invalid sig and undefined hashtype"], +["1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","NULLDUMMY","3-of-3 with nonzero dummy"], +["1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT","NULLDUMMY","3-of-3 NOT with invalid sig with nonzero dummy"], +["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","SIGPUSHONLY","2-of-2 with two identical keys and sigs pushed using OP_DUP"], +["0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"], +["0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","SIGPUSHONLY","P2SH(P2PK) with non-push scriptSig"], + + ["The End"] ] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index 3246799907cc..1d256512f55a 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -1239,5 +1239,38 @@ "P2SH", "Basic P2SH(P2WPKH) with the wrong key but no WITNESS" ], +["0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","P2PK"], +["0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508","DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG","","P2PKH"], +["0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","P2PK anyonecanpay"], +["0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac","HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL","P2SH","P2SH(P2PK)"], +["0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac","HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL","","P2SH(P2PKH), bad sig but no VERIFY_P2SH"], +["0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","3-of-3"], +["0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae","HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL","P2SH","P2SH(2-of-3)"], +["0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","P2PK with too much R padding but no DERSIG"], +["0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","P2PK with too much S padding but no DERSIG"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","P2PK with too little R padding but no DERSIG"], +["0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","","P2PK NOT with bad sig with too much R padding but no DERSIG"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","BIP66 example 1, without DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","BIP66 example 4, without DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","BIP66 example 4, with DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","BIP66 example 6, without DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","BIP66 example 7, without DERSIG"], +["0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","BIP66 example 10, without DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","BIP66 example 12, without DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","BIP66 example 12, with DERSIG"], +["0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","P2PK with high S but no LOW_S"], +["0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","P2PK with hybrid pubkey but no STRICTENC"], +["0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","","P2PK NOT with invalid hybrid pubkey but no STRICTENC"], +["0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401","1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","","1-of-2 with the second 1 hybrid pubkey and no STRICTENC"], +["0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401","1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","STRICTENC","1-of-2 with the second 1 hybrid pubkey"], +["0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","P2PK with undefined hashtype but no STRICTENC"], +["0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT","","P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"], +["1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","3-of-3 with nonzero dummy but no NULLDUMMY"], +["1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT","","3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"], +["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","","2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"], +["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","SIGPUSHONLY","2-of-2 with two identical keys and sigs pushed"], + + + ["The End"] ] diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index b73623b7bb2f..3ea2a5025d60 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -3,15 +3,16 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "util.h" +#include "test/test_phore.h" #include #include #include -#include + #include -BOOST_AUTO_TEST_SUITE(getarg_tests) +BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup) static void ResetArgs(const std::string& strArg) { @@ -24,7 +25,7 @@ static void ResetArgs(const std::string& strArg) // Convert to char*: std::vector vecChar; - BOOST_FOREACH(std::string& s, vecArg) + for (std::string& s : vecArg) vecChar.push_back(s.c_str()); ParseParameters(vecChar.size(), &vecChar[0]); diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index b8e290f071fd..2458d7591998 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -4,14 +4,14 @@ #include "hash.h" #include "utilstrencodings.h" +#include "test/test_phore.h" #include #include -using namespace std; -BOOST_AUTO_TEST_SUITE(hash_tests) +BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(murmurhash3) { diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index e2e7124eb216..a007c52bcc9d 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -9,25 +9,25 @@ #include "uint256.h" #include "util.h" #include "utilstrencodings.h" +#include "test_phore.h" #include #include #include -using namespace std; -static const string strSecret1 ("88rZ37TerZ3hMw3Y4BDJmeZKdXMf9yz1TAi874VoYa5AgHcp5TX"); -static const string strSecret2 ("87X8C4vzdeui65KtGvzFzhJ4SaesVxq86RH9C1rA1hQV7jnykNp"); -static const string strSecret1C ("YVfiQKWe5iSu9PYC525KS4mfECzBQeWczVrWMkS8SLyPhz1MXKup"); -static const string strSecret2C ("YPmxjrMKNnKeMQ6MKKHjBerJBuY9tqRQJvAF9cjxn5Lf6TJfgSR3"); -static const string addr1 = "P8dKq5MfsTED7GDeiYkf1rdcAUc9KmL97C"; -static const string addr2 = "PEt8QagBLy3jAGnZ58cSDcu9SyZ7nhZf9F"; -static const string addr1C = "PXLdAeb1zt1MrocfVarDMtxPejD8vPSkUQ"; -static const string addr2C = "PRyhkCVSbV5JCaBncYDnZ43s4kD6LPbacA"; +static const std::string strSecret1 ("88rZ37TerZ3hMw3Y4BDJmeZKdXMf9yz1TAi874VoYa5AgHcp5TX"); +static const std::string strSecret2 ("87X8C4vzdeui65KtGvzFzhJ4SaesVxq86RH9C1rA1hQV7jnykNp"); +static const std::string strSecret1C ("YVfiQKWe5iSu9PYC525KS4mfECzBQeWczVrWMkS8SLyPhz1MXKup"); +static const std::string strSecret2C ("YPmxjrMKNnKeMQ6MKKHjBerJBuY9tqRQJvAF9cjxn5Lf6TJfgSR3"); +static const std::string addr1 = "P8dKq5MfsTED7GDeiYkf1rdcAUc9KmL97C"; +static const std::string addr2 = "PEt8QagBLy3jAGnZ58cSDcu9SyZ7nhZf9F"; +static const std::string addr1C = "PXLdAeb1zt1MrocfVarDMtxPejD8vPSkUQ"; +static const std::string addr2C = "PRyhkCVSbV5JCaBncYDnZ43s4kD6LPbacA"; -static const string strAddressBad("Xta1praZQjyELweyMByXyiREw1ZRsjXzVP"); +static const std::string strAddressBad("Xta1praZQjyELweyMByXyiREw1ZRsjXzVP"); #ifdef KEY_TESTS_DUMPINFO @@ -36,7 +36,7 @@ void dumpKeyInfo(uint256 privkey) CKey key; key.resize(32); memcpy(&secret[0], &privkey, 32); - vector sec; + std::vector sec; sec.resize(32); memcpy(&sec[0], &secret[0], 32); printf(" * secret (hex): %s\n", HexStr(sec).c_str()); @@ -50,15 +50,14 @@ void dumpKeyInfo(uint256 privkey) printf(" * secret (base58): %s\n", bsecret.ToString().c_str()); CKey key; key.SetSecret(secret, fCompressed); - vector vchPubKey = key.GetPubKey(); + std::vector vchPubKey = key.GetPubKey(); printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str()); printf(" * address (base58): %s\n", EncodeDestination(CTxDestination(vchPubKey)).c_str()); } } #endif - -BOOST_AUTO_TEST_SUITE(key_tests) +BOOST_FIXTURE_TEST_SUITE(key_tests, TestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { @@ -110,12 +109,12 @@ BOOST_AUTO_TEST_CASE(key_test1) for (int n=0; n<16; n++) { - string strMsg = strprintf("Very secret message %i: 11", n); + std::string strMsg = strprintf("Very secret message %i: 11", n); uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); // normal signatures - vector sign1, sign2, sign1C, sign2C; + std::vector sign1, sign2, sign1C, sign2C; BOOST_CHECK(key1.Sign (hashMsg, sign1)); BOOST_CHECK(key2.Sign (hashMsg, sign2)); @@ -144,7 +143,7 @@ BOOST_AUTO_TEST_CASE(key_test1) // compact signatures (with key recovery) - vector csign1, csign2, csign1C, csign2C; + std::vector csign1, csign2, csign1C, csign2C; BOOST_CHECK(key1.SignCompact (hashMsg, csign1)); BOOST_CHECK(key2.SignCompact (hashMsg, csign2)); @@ -167,7 +166,7 @@ BOOST_AUTO_TEST_CASE(key_test1) // test deterministic signing std::vector detsig, detsigc; - string strMsg = "Very deterministic message"; + std::string strMsg = "Very deterministic message"; uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); BOOST_CHECK(key1.Sign(hashMsg, detsig)); BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); diff --git a/src/test/libzerocoin_tests.cpp b/src/test/libzerocoin_tests.cpp index 509f726f7ee2..02e6484778f3 100644 --- a/src/test/libzerocoin_tests.cpp +++ b/src/test/libzerocoin_tests.cpp @@ -23,25 +23,24 @@ #include "libzerocoin/Coin.h" #include "libzerocoin/CoinSpend.h" #include "libzerocoin/Accumulator.h" +#include "test_phore.h" -using namespace std; -using namespace libzerocoin; #define COLOR_STR_GREEN "\033[32m" #define COLOR_STR_NORMAL "\033[0m" #define COLOR_STR_RED "\033[31m" #define TESTS_COINS_TO_ACCUMULATE 10 -#define NON_PRIME_TESTS 100 +#define NON_PRIME_TESTS 100 // Global test counters uint32_t gNumTests = 0; uint32_t gSuccessfulTests = 0; // Proof size -uint32_t gProofSize = 0; -uint32_t gCoinSize = 0; -uint32_t gSerialNumberSize = 0; +uint32_t gProofSize = 0; +uint32_t gCoinSize = 0; +uint32_t gSerialNumberSize = 0; // Global coin array PrivateCoin *gCoins[TESTS_COINS_TO_ACCUMULATE]; @@ -54,44 +53,44 @@ ZerocoinParams *g_Params; ////////// void -LogTestResult(string testName, bool (*testPtr)()) +LogTestResult(std::string testName, bool (*testPtr)()) { - string colorGreen(COLOR_STR_GREEN); - string colorNormal(COLOR_STR_NORMAL); - string colorRed(COLOR_STR_RED); + std::string colorGreen(COLOR_STR_GREEN); + std::string colorNormal(COLOR_STR_NORMAL); + std::string colorRed(COLOR_STR_RED); - cout << "Testing if " << testName << "..." << endl; + std::cout << "Testing if " << testName << "..." << endl; - bool testResult = testPtr(); + bool testResult = testPtr(); - if (testResult == true) { - cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; - gSuccessfulTests++; - } else { - cout << colorRed << "\t[FAIL]" << colorNormal << endl; - } + if (testResult == true) { + std::cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + gSuccessfulTests++; + } else { + std::cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } - gNumTests++; + gNumTests++; } CBigNum GetTestModulus() { - static CBigNum testModulus(0); + static CBigNum testModulus(0); - // TODO: should use a hard-coded RSA modulus for testing - if (!testModulus) { - CBigNum p, q; + // TODO: should use a hard-coded RSA modulus for testing + if (!testModulus) { + CBigNum p, q; - // Note: we are NOT using safe primes for testing because - // they take too long to generate. Don't do this in real - // usage. See the paramgen utility for better code. - p = CBigNum::generatePrime(1024, false); - q = CBigNum::generatePrime(1024, false); - testModulus = p * q; - } + // Note: we are NOT using safe primes for testing because + // they take too long to generate. Don't do this in real + // usage. See the paramgen utility for better code. + p = CBigNum::generatePrime(1024, false); + q = CBigNum::generatePrime(1024, false); + testModulus = p * q; + } - return testModulus; + return testModulus; } ////////// @@ -101,392 +100,392 @@ GetTestModulus() bool Test_GenRSAModulus() { - CBigNum result = GetTestModulus(); - - if (!result) { - return false; - } - else { - return true; - } + CBigNum result = GetTestModulus(); + + if (!result) { + return false; + } + else { + return true; + } } bool Test_CalcParamSizes() { - bool result = true; + bool result = true; #if 0 - uint32_t pLen, qLen; - - try { - calculateGroupParamLengths(4000, 80, &pLen, &qLen); - if (pLen < 1024 || qLen < 256) { - result = false; - } - calculateGroupParamLengths(4000, 96, &pLen, &qLen); - if (pLen < 2048 || qLen < 256) { - result = false; - } - calculateGroupParamLengths(4000, 112, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - calculateGroupParamLengths(4000, 120, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - calculateGroupParamLengths(4000, 128, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - } catch (exception &e) { - result = false; - } + uint32_t pLen, qLen; + + try { + calculateGroupParamLengths(4000, 80, &pLen, &qLen); + if (pLen < 1024 || qLen < 256) { + result = false; + } + calculateGroupParamLengths(4000, 96, &pLen, &qLen); + if (pLen < 2048 || qLen < 256) { + result = false; + } + calculateGroupParamLengths(4000, 112, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + calculateGroupParamLengths(4000, 120, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + calculateGroupParamLengths(4000, 128, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + } catch (exception &e) { + result = false; + } #endif - return result; + return result; } bool Test_GenerateGroupParams() { - uint32_t pLen = 1024, qLen = 256, count; - IntegerGroupParams group; + uint32_t pLen = 1024, qLen = 256, count; + IntegerGroupParams group; - for (count = 0; count < 1; count++) { + for (count = 0; count < 1; count++) { - try { - group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen); - } catch (std::runtime_error e) { - cout << "Caught exception " << e.what() << endl; - return false; - } + try { + group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen); + } catch (std::runtime_error e) { + std::cout << "Caught exception " << e.what() << endl; + return false; + } - // Now perform some simple tests on the resulting parameters - if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) { - return false; - } + // Now perform some simple tests on the resulting parameters + if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) { + return false; + } - CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus); - //cout << "g^q mod p = " << c << endl; - if (!(c.isOne())) return false; + CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus); + //cout << "g^q mod p = " << c << endl; + if (!(c.isOne())) return false; - // Try at multiple parameter sizes - pLen = pLen * 1.5; - qLen = qLen * 1.5; - } + // Try at multiple parameter sizes + pLen = pLen * 1.5; + qLen = qLen * 1.5; + } - return true; + return true; } bool Test_ParamGen() { - bool result = true; + bool result = true; - try { - // Instantiating testParams runs the parameter generation code - ZerocoinParams testParams(GetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); - } catch (runtime_error e) { - cout << e.what() << endl; - result = false; - } + try { + // Instantiating testParams runs the parameter generation code + ZerocoinParams testParams(GetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); + } catch (runtime_error e) { + std::cout << e.what() << endl; + result = false; + } - return result; + return result; } bool Test_Accumulator() { - // This test assumes a list of coins were generated during - // the Test_MintCoin() test. - if (gCoins[0] == NULL) { - return false; - } - try { - // Accumulate the coin list from first to last into one accumulator + // This test assumes a list of coins were generated during + // the Test_MintCoin() test. + if (gCoins[0] == NULL) { + return false; + } + try { + // Accumulate the coin list from first to last into one accumulator Accumulator accOne(&g_Params->accumulatorParams, CoinDenomination::ZQ_ONE); Accumulator accTwo(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); Accumulator accThree(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); Accumulator accFour(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); - AccumulatorWitness wThree(g_Params, accThree, gCoins[0]->getPublicCoin()); - - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - accOne += gCoins[i]->getPublicCoin(); - accTwo += gCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); - accThree += gCoins[i]->getPublicCoin(); - wThree += gCoins[i]->getPublicCoin(); - if(i != 0) { - accFour += gCoins[i]->getPublicCoin(); - } - } - - // Compare the accumulated results - if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) { - cout << "Accumulators don't match" << endl; - return false; - } - - if(accFour.getValue() != wThree.getValue()) { - cout << "Witness math not working," << endl; - return false; - } - - // Verify that the witness is correct - if (!wThree.VerifyWitness(accThree, gCoins[0]->getPublicCoin()) ) { - cout << "Witness not valid" << endl; - return false; - } - - // Serialization test: see if we can serialize the accumulator - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << accOne; - - // Deserialize it into a new object - Accumulator newAcc(g_Params, ss); - - // Compare the results - if (accOne.getValue() != newAcc.getValue()) { - return false; - } - - } catch (runtime_error e) { - return false; - } - - return true; + AccumulatorWitness wThree(g_Params, accThree, gCoins[0]->getPublicCoin()); + + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + accOne += gCoins[i]->getPublicCoin(); + accTwo += gCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); + accThree += gCoins[i]->getPublicCoin(); + wThree += gCoins[i]->getPublicCoin(); + if(i != 0) { + accFour += gCoins[i]->getPublicCoin(); + } + } + + // Compare the accumulated results + if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) { + std::cout << "Accumulators don't match" << endl; + return false; + } + + if(accFour.getValue() != wThree.getValue()) { + std::cout << "Witness math not working," << endl; + return false; + } + + // Verify that the witness is correct + if (!wThree.VerifyWitness(accThree, gCoins[0]->getPublicCoin()) ) { + std::cout << "Witness not valid" << endl; + return false; + } + + // Serialization test: see if we can serialize the accumulator + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << accOne; + + // Deserialize it into a new object + Accumulator newAcc(g_Params, ss); + + // Compare the results + if (accOne.getValue() != newAcc.getValue()) { + return false; + } + + } catch (runtime_error e) { + return false; + } + + return true; } bool Test_EqualityPoK() { - // Run this test 10 times - for (uint32_t i = 0; i < 10; i++) { - try { - // Generate a random integer "val" - CBigNum val = CBigNum::randBignum(g_Params->coinCommitmentGroup.groupOrder); - - // Manufacture two commitments to "val", both - // under different sets of parameters - Commitment one(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, val); - - Commitment two(&g_Params->serialNumberSoKCommitmentGroup, val); - - // Now generate a proof of knowledge that "one" and "two" are - // both commitments to the same value - CommitmentProofOfKnowledge pok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, - &g_Params->serialNumberSoKCommitmentGroup, - one, two); - - // Serialize the proof into a stream - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pok; - - // Deserialize back into a PoK object - CommitmentProofOfKnowledge newPok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, - &g_Params->serialNumberSoKCommitmentGroup, - ss); - - if (newPok.Verify(one.getCommitmentValue(), two.getCommitmentValue()) != true) { - return false; - } - - // Just for fun, deserialize the proof a second time - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << pok; - - // This time tamper with it, then deserialize it back into a PoK - ss2[15] = 0; - CommitmentProofOfKnowledge newPok2(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, - &g_Params->serialNumberSoKCommitmentGroup, - ss2); - - // If the tampered proof verifies, that's a failure! - if (newPok2.Verify(one.getCommitmentValue(), two.getCommitmentValue()) == true) { - return false; - } - - } catch (runtime_error &e) { - return false; - } - } - - return true; + // Run this test 10 times + for (uint32_t i = 0; i < 10; i++) { + try { + // Generate a random integer "val" + CBigNum val = CBigNum::randBignum(g_Params->coinCommitmentGroup.groupOrder); + + // Manufacture two commitments to "val", both + // under different sets of parameters + Commitment one(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, val); + + Commitment two(&g_Params->serialNumberSoKCommitmentGroup, val); + + // Now generate a proof of knowledge that "one" and "two" are + // both commitments to the same value + CommitmentProofOfKnowledge pok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, + &g_Params->serialNumberSoKCommitmentGroup, + one, two); + + // Serialize the proof into a stream + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pok; + + // Deserialize back into a PoK object + CommitmentProofOfKnowledge newPok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, + &g_Params->serialNumberSoKCommitmentGroup, + ss); + + if (newPok.Verify(one.getCommitmentValue(), two.getCommitmentValue()) != true) { + return false; + } + + // Just for fun, deserialize the proof a second time + CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); + ss2 << pok; + + // This time tamper with it, then deserialize it back into a PoK + ss2[15] = 0; + CommitmentProofOfKnowledge newPok2(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, + &g_Params->serialNumberSoKCommitmentGroup, + ss2); + + // If the tampered proof verifies, that's a failure! + if (newPok2.Verify(one.getCommitmentValue(), two.getCommitmentValue()) == true) { + return false; + } + + } catch (runtime_error &e) { + return false; + } + } + + return true; } bool Test_MintCoin() { - gCoinSize = 0; + gCoinSize = 0; - try { - // Generate a list of coins - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + try { + // Generate a list of coins + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { gCoins[i] = new PrivateCoin(g_Params,libzerocoin::CoinDenomination::ZQ_ONE); - PublicCoin pc = gCoins[i]->getPublicCoin(); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pc; - gCoinSize += ss.size(); - } + PublicCoin pc = gCoins[i]->getPublicCoin(); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pc; + gCoinSize += ss.size(); + } - gCoinSize /= TESTS_COINS_TO_ACCUMULATE; + gCoinSize /= TESTS_COINS_TO_ACCUMULATE; - } catch (exception &e) { - return false; - } + } catch (exception &e) { + return false; + } - return true; + return true; } bool Test_InvalidCoin() { - CBigNum coinValue; - - try { - // Pick a random non-prime CBigNum - for (uint32_t i = 0; i < NON_PRIME_TESTS; i++) { - coinValue = CBigNum::randBignum(g_Params->coinCommitmentGroup.modulus); - coinValue = coinValue * 2; - if (!coinValue.isPrime()) break; - } - - PublicCoin pubCoin(g_Params); - if (pubCoin.validate()) { - // A blank coin should not be valid! - return false; - } - - PublicCoin pubCoin2(g_Params, coinValue, ZQ_ONE); - if (pubCoin2.validate()) { - // A non-prime coin should not be valid! - return false; - } - - PublicCoin pubCoin3 = pubCoin2; - if (pubCoin2.validate()) { - // A copy of a non-prime coin should not be valid! - return false; - } - - // Serialize and deserialize the coin - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pubCoin; - PublicCoin pubCoin4(g_Params, ss); - if (pubCoin4.validate()) { - // A deserialized copy of a non-prime coin should not be valid! - return false; - } - - } catch (runtime_error &e) { - cout << "Caught exception: " << e.what() << endl; - return false; - } - - return true; + CBigNum coinValue; + + try { + // Pick a random non-prime CBigNum + for (uint32_t i = 0; i < NON_PRIME_TESTS; i++) { + coinValue = CBigNum::randBignum(g_Params->coinCommitmentGroup.modulus); + coinValue = coinValue * 2; + if (!coinValue.isPrime()) break; + } + + PublicCoin pubCoin(g_Params); + if (pubCoin.validate()) { + // A blank coin should not be valid! + return false; + } + + PublicCoin pubCoin2(g_Params, coinValue, ZQ_ONE); + if (pubCoin2.validate()) { + // A non-prime coin should not be valid! + return false; + } + + PublicCoin pubCoin3 = pubCoin2; + if (pubCoin2.validate()) { + // A copy of a non-prime coin should not be valid! + return false; + } + + // Serialize and deserialize the coin + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pubCoin; + PublicCoin pubCoin4(g_Params, ss); + if (pubCoin4.validate()) { + // A deserialized copy of a non-prime coin should not be valid! + return false; + } + + } catch (runtime_error &e) { + std::cout << "Caught exception: " << e.what() << endl; + return false; + } + + return true; } bool Test_MintAndSpend() { - try { - // This test assumes a list of coins were generated in Test_MintCoin() - if (gCoins[0] == NULL) - { - // No coins: mint some. - Test_MintCoin(); - if (gCoins[0] == NULL) { - return false; - } - } - - // Accumulate the list of generated coins into a fresh accumulator. - // The first one gets marked as accumulated for a witness, the - // others just get accumulated normally. + try { + // This test assumes a list of coins were generated in Test_MintCoin() + if (gCoins[0] == NULL) + { + // No coins: mint some. + Test_MintCoin(); + if (gCoins[0] == NULL) { + return false; + } + } + + // Accumulate the list of generated coins into a fresh accumulator. + // The first one gets marked as accumulated for a witness, the + // others just get accumulated normally. Accumulator acc(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); - AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin()); - - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - acc += gCoins[i]->getPublicCoin(); - wAcc +=gCoins[i]->getPublicCoin(); - } - - // Now spend the coin - //SpendMetaData m(1,1); - CDataStream cc(SER_NETWORK, PROTOCOL_VERSION); - cc << *gCoins[0]; - PrivateCoin myCoin(g_Params,cc); - - CoinSpend spend(g_Params, g_Params, myCoin, acc, 0, wAcc, 0, SpendType::SPEND); - - // Serialize the proof and deserialize into newSpend - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << spend; - gProofSize = ss.size(); - CoinSpend newSpend(g_Params, g_Params, ss); - - // See if we can verify the deserialized proof (return our result) - bool ret = newSpend.Verify(acc); - - // Extract the serial number - CBigNum serialNumber = newSpend.getCoinSerialNumber(); - gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0); - - return ret; - } catch (runtime_error &e) { - cout << e.what() << endl; - return false; - } - - return false; + AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin()); + + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + acc += gCoins[i]->getPublicCoin(); + wAcc +=gCoins[i]->getPublicCoin(); + } + + // Now spend the coin + //SpendMetaData m(1,1); + CDataStream cc(SER_NETWORK, PROTOCOL_VERSION); + cc << *gCoins[0]; + PrivateCoin myCoin(g_Params,cc); + + CoinSpend spend(g_Params, g_Params, myCoin, acc, 0, wAcc, 0, SpendType::SPEND); + + // Serialize the proof and deserialize into newSpend + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << spend; + gProofSize = ss.size(); + CoinSpend newSpend(g_Params, g_Params, ss); + + // See if we can verify the deserialized proof (return our result) + bool ret = newSpend.Verify(acc); + + // Extract the serial number + CBigNum serialNumber = newSpend.getCoinSerialNumber(); + gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0); + + return ret; + } catch (runtime_error &e) { + std::cout << e.what() << endl; + return false; + } + + return false; } void Test_RunAllTests() { - // Make a new set of parameters from a random RSA modulus - g_Params = new ZerocoinParams(GetTestModulus()); - - gNumTests = gSuccessfulTests = gProofSize = 0; - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - gCoins[i] = NULL; - } - - // Run through all of the Zerocoin tests - LogTestResult("an RSA modulus can be generated", Test_GenRSAModulus); - LogTestResult("parameter sizes are correct", Test_CalcParamSizes); - LogTestResult("group/field parameters can be generated", Test_GenerateGroupParams); - LogTestResult("parameter generation is correct", Test_ParamGen); - LogTestResult("coins can be minted", Test_MintCoin); - LogTestResult("invalid coins will be rejected", Test_InvalidCoin); - LogTestResult("the accumulator works", Test_Accumulator); - LogTestResult("the commitment equality PoK works", Test_EqualityPoK); - LogTestResult("a minted coin can be spent", Test_MintAndSpend); - - cout << endl << "Average coin size is " << gCoinSize << " bytes." << endl; - cout << "Serial number size is " << gSerialNumberSize << " bytes." << endl; - cout << "Spend proof size is " << gProofSize << " bytes." << endl; - - // Summarize test results - if (gSuccessfulTests < gNumTests) { - cout << endl << "ERROR: SOME TESTS FAILED" << endl; - } - - // Clear any generated coins - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - delete gCoins[i]; - } - - cout << endl << gSuccessfulTests << " out of " << gNumTests << " tests passed." << endl << endl; - delete g_Params; + // Make a new set of parameters from a random RSA modulus + g_Params = new ZerocoinParams(GetTestModulus()); + + gNumTests = gSuccessfulTests = gProofSize = 0; + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + gCoins[i] = NULL; + } + + // Run through all of the Zerocoin tests + LogTestResult("an RSA modulus can be generated", Test_GenRSAModulus); + LogTestResult("parameter sizes are correct", Test_CalcParamSizes); + LogTestResult("group/field parameters can be generated", Test_GenerateGroupParams); + LogTestResult("parameter generation is correct", Test_ParamGen); + LogTestResult("coins can be minted", Test_MintCoin); + LogTestResult("invalid coins will be rejected", Test_InvalidCoin); + LogTestResult("the accumulator works", Test_Accumulator); + LogTestResult("the commitment equality PoK works", Test_EqualityPoK); + LogTestResult("a minted coin can be spent", Test_MintAndSpend); + + std::cout << endl << "Average coin size is " << gCoinSize << " bytes." << endl; + std::cout << "Serial number size is " << gSerialNumberSize << " bytes." << endl; + std::cout << "Spend proof size is " << gProofSize << " bytes." << endl; + + // Summarize test results + if (gSuccessfulTests < gNumTests) { + std::cout << endl << "ERROR: SOME TESTS FAILED" << endl; + } + + // Clear any generated coins + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + delete gCoins[i]; + } + + std::cout << endl << gSuccessfulTests << " out of " << gNumTests << " tests passed." << endl << endl; + delete g_Params; } -BOOST_AUTO_TEST_SUITE(libzerocoin) +BOOST_FIXTURE_TEST_SUITE(libzerocoin, TestingSetup) BOOST_AUTO_TEST_CASE(libzerocoin_tests) { - cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " test utility." << endl << endl; - - Test_RunAllTests(); + std::cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " test utility." << endl << endl; + + Test_RunAllTests(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 4bcbb844f3ba..e8cd1f07fe97 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -6,10 +6,11 @@ #include "primitives/transaction.h" #include "main.h" +#include "test_phore.h" #include -BOOST_AUTO_TEST_SUITE(main_tests) +BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup) CAmount nMoneySupplyPoWEnd = 18000000 * COIN; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 8baa790e8eef..39b0cde8af8c 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -10,9 +10,11 @@ #include "uint256.h" #include "util.h" +#include "test/test_phore.h" + #include -BOOST_AUTO_TEST_SUITE(miner_tests) +BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) static struct { @@ -259,7 +261,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) SetMockTime(0); mempool.clear(); - BOOST_FOREACH(CTransaction *tx, txFirst) + for (CTransaction *tx : txFirst) delete tx; Checkpoints::fEnabled = true; diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp index 547cd1090c58..df6aabfde3ba 100644 --- a/src/test/mruset_tests.cpp +++ b/src/test/mruset_tests.cpp @@ -6,6 +6,7 @@ #include "random.h" #include "util.h" +#include "test/test_phore.h" #include @@ -14,7 +15,6 @@ #define NUM_TESTS 16 #define MAX_SIZE 100 -using namespace std; class mrutester { @@ -34,7 +34,7 @@ class mrutester } }; -BOOST_AUTO_TEST_SUITE(mruset_tests) +BOOST_FIXTURE_TEST_SUITE(mruset_tests, BasicTestingSetup) // Test that an mruset behaves like a set, as long as no more than MAX_SIZE elements are in it BOOST_AUTO_TEST_CASE(mruset_like_set) @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(mruset_window) { mru.insert(permute(n)); - set tester; + std::set tester; for (int m=max(0,n-MAX_SIZE+1); m<=n; m++) tester.insert(permute(m)); diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 7281b8506798..43b575bc2e75 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -10,32 +10,31 @@ #include "script/interpreter.h" #include "script/sign.h" #include "uint256.h" +#include "test_phore.h" #ifdef ENABLE_WALLET #include "wallet_ismine.h" #endif #include -#include + #include -using namespace std; -using namespace boost::assign; -typedef vector valtype; +typedef std::vector valtype; -BOOST_AUTO_TEST_SUITE(multisig_tests) +BOOST_FIXTURE_TEST_SUITE(multisig_tests, TestingSetup) CScript -sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) +sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, int whichIn) { uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE); CScript result; result << OP_0; // CHECKMULTISIG bug workaround - BOOST_FOREACH(const CKey &key, keys) + for (const CKey &key : keys) { - vector vchSig; + std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); result << vchSig; @@ -78,7 +77,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify) txTo[i].vout[0].nValue = 1; } - vector keys; + std::vector keys; CScript s; // Test a AND b: @@ -205,7 +204,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) partialkeystore.AddKey(key[0]); { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; @@ -220,7 +219,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) #endif } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; @@ -235,7 +234,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) #endif } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; @@ -250,13 +249,13 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) #endif } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4U); - vector addrs; + std::vector addrs; int nRequired; BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(addrs[0] == keyaddr[0]); @@ -269,7 +268,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) #endif } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index d706e9434b7d..50a67e92c5e5 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -5,14 +5,14 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "netbase.h" +#include "test/test_phore.h" #include #include -using namespace std; -BOOST_AUTO_TEST_SUITE(netbase_tests) +BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(netbase_networks) { @@ -47,9 +47,9 @@ BOOST_AUTO_TEST_CASE(netbase_properties) BOOST_CHECK(CNetAddr("127.0.0.1").IsValid()); } -bool static TestSplitHost(string test, string host, int port) +bool static TestSplitHost(std::string test, std::string host, int port) { - string hostOut; + std::string hostOut; int portOut = -1; SplitHostPort(test, portOut, hostOut); return hostOut == host && port == portOut; @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(netbase_splithost) BOOST_CHECK(TestSplitHost("", "", -1)); } -bool static TestParse(string src, string canon) +bool static TestParse(std::string src, std::string canon) { CService addr; if (!LookupNumeric(src.c_str(), addr, 65535)) diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 3b535a84fd80..8598af620fde 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -7,12 +7,13 @@ #include "streams.h" #include "uint256.h" #include "version.h" +#include "random.h" +#include "test/test_phore.h" #include #include -using namespace std; class CPartialMerkleTreeTester : public CPartialMerkleTree { @@ -26,7 +27,7 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree } }; -BOOST_AUTO_TEST_SUITE(pmt_tests) +BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(pmt_test1) { diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 4dd190694472..d033da6e382a 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -8,7 +8,7 @@ #include "uint256.h" #include "util.h" -#include "test/test_bitcoin.h" +#include "test/test_phore.h" #include diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 696a739b24b7..c79d3f22e0c2 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -2,19 +2,20 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" -#include "rpcclient.h" +#include "rpc/server.h" +#include "rpc/client.h" #include "base58.h" #include "netbase.h" #include "util.h" +#include "test/test_phore.h" + #include #include #include -using namespace std; UniValue createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) @@ -28,11 +29,11 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) return result; } -UniValue CallRPC(string args) +UniValue CallRPC(std::string args) { - vector vArgs; + std::vector vArgs; boost::split(vArgs, args, boost::is_any_of(" \t")); - string strMethod = vArgs[0]; + std::string strMethod = vArgs[0]; vArgs.erase(vArgs.begin()); UniValue params = RPCConvertValues(strMethod, vArgs); @@ -42,70 +43,70 @@ UniValue CallRPC(string args) return result; } catch (const UniValue& objError) { - throw runtime_error(find_value(objError, "message").get_str()); + throw std::runtime_error(find_value(objError, "message").get_str()); } } -BOOST_AUTO_TEST_SUITE(rpc_tests) +BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup) BOOST_AUTO_TEST_CASE(rpc_rawparams) { // Test raw transaction API argument handling UniValue r; - BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error); - BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), std::runtime_error); BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}")); - BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error); - string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; - BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx)); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error); + std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx)); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0); - BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error); + BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx)); - BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY")); - BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY")); - BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), std::runtime_error); + BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx)); + BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY")); + BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY")); + BOOST_CHECK_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" null null badenum"), std::runtime_error); // Only check failure cases for sendrawtransaction, there's no network to send to... - BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error); - BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC(std::string("sendrawtransaction ")+rawtx+" extra"), std::runtime_error); } BOOST_AUTO_TEST_CASE(rpc_rawsign) { UniValue r; // input is a 1-of-2 multisig (so is output): - string prevout = + std::string prevout = "[{\"txid\":\"dd2888870cdc3f6e92661f6b0829667ee4bb07ed086c44205e726bbf3338f726\"," "\"vout\":1,\"scriptPubKey\":\"a914f5404a39a4799d8710e15db4c4512c5e06f97fed87\"," "\"redeemScript\":\"5121021431a18c7039660cd9e3612a2a47dc53b69cb38ea4ad743b7df8245fd0438f8e21029bbeff390ce736bd396af43b52a1c14ed52c086b1e5585c15931f68725772bac52ae\"}]"; - r = CallRPC(string("createrawtransaction ")+prevout+" "+ + r = CallRPC(std::string("createrawtransaction ")+prevout+" "+ "{\"6ckcNMWRYgTnPcrTXCdwhDnMLwj3zwseej\":1}"); - string notsigned = r.get_str(); - string privkey1 = "\"YVobcS47fr6kceZy9LzLJR8WQ6YRpUwYKoJhrnEXepebMxaSpbnn\""; - string privkey2 = "\"YRyMjG8hbm8jHeDMAfrzSeHq5GgAj7kuHFvJtMudCUH3sCkq1WtA\""; - r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]"); + std::string notsigned = r.get_str(); + std::string privkey1 = "\"YVobcS47fr6kceZy9LzLJR8WQ6YRpUwYKoJhrnEXepebMxaSpbnn\""; + std::string privkey2 = "\"YRyMjG8hbm8jHeDMAfrzSeHq5GgAj7kuHFvJtMudCUH3sCkq1WtA\""; + r = CallRPC(std::string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]"); BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); - r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]"); + r = CallRPC(std::string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]"); BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); } @@ -183,23 +184,23 @@ BOOST_AUTO_TEST_CASE(json_parse_errors) BOOST_AUTO_TEST_CASE(rpc_ban) { - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); UniValue r; - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add"))); - BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.0:8334")), std::runtime_error); //portnumber for setban not allowed + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); UniValue ar = r.get_array(); UniValue o1 = ar[0].get_obj(); UniValue adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32"); - BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));; - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0 remove")));; + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 1607731200 true"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); @@ -207,10 +208,10 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 200"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); @@ -221,42 +222,42 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK(banned_until.get_int64()-now <= 200); // must throw an exception because 127.0.0.1 is in already banned suubnet range - BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error); + BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove")));; - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0/24 remove")));; + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add"))); - BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/255.255.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.1.1 add")), std::runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); - BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); //invalid IP + BOOST_CHECK_THROW(r = CallRPC(std::string("setban test add")), std::runtime_error); //invalid IP //IPv6 tests - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128"); - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30"); - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp new file mode 100644 index 000000000000..3931c4b2e5ce --- /dev/null +++ b/src/test/rpc_wallet_tests.cpp @@ -0,0 +1,185 @@ +// Copyright (c) 2013-2014 The Bitcoin Core developers +// Copyright (c) 2017 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "rpc/server.h" +#include "rpc/client.h" + +#include "base58.h" +#include "wallet/wallet.h" + +#include "test/test_phore.h" + +#include +#include + +#include + + +extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL); +extern UniValue CallRPC(std::string args); + +extern CWallet* pwalletMain; + +BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(rpc_addmultisig) +{ + LOCK(pwalletMain->cs_wallet); + + rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; + + // old, 65-byte-long: + const char address1Hex[] = "041431A18C7039660CD9E3612A2A47DC53B69CB38EA4AD743B7DF8245FD0438F8E7270415F1085B9DC4D7DA367C69F1245E27EE5552A481D6854184C80F0BB8456"; + // new, compressed: + const char address2Hex[] = "029BBEFF390CE736BD396AF43B52A1C14ED52C086B1E5585C15931F68725772BAC"; + + UniValue v; + CBitcoinAddress address; + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_THROW(addmultisig(createArgs(0), false), std::runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(1), false), std::runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), std::runtime_error); + + BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), std::runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), std::runtime_error); + + std::string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing + BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), std::runtime_error); + + std::string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing + BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(rpc_wallet) +{ + // Test RPC calls for various wallet statistics + UniValue r; + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CPubKey demoPubkey = pwalletMain->GenerateNewKey(); + CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID())); + UniValue retValue; + std::string strAccount = "walletDemoAccount"; + std::string strPurpose = "receive"; + BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */ + CWalletDB walletdb(pwalletMain->strWalletFile); + CAccount account; + account.vchPubKey = demoPubkey; + pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose); + walletdb.WriteAccount(strAccount, account); + }); + + CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey(); + CBitcoinAddress setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID())); + + /********************************* + * setaccount + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount")); + /* D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5R is not owned by the test wallet. */ + BOOST_CHECK_THROW(CallRPC("setaccount D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5R nullaccount"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("setaccount"), std::runtime_error); + /* D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5 (33 chars) is an illegal address (should be 34 chars) */ + BOOST_CHECK_THROW(CallRPC("setaccount D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5 nullaccount"), std::runtime_error); + + /********************************* + * listunspent + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listunspent")); + BOOST_CHECK_THROW(CallRPC("listunspent string"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), std::runtime_error); + BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []")); + BOOST_CHECK(r.get_array().empty()); + + /********************************* + * listreceivedbyaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), std::runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), std::runtime_error); + + /********************************* + * listreceivedbyaccount + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), std::runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), std::runtime_error); + + /********************************* + * getrawchangeaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress")); + + /********************************* + * getnewaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getnewaddress")); + BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount")); + + /********************************* + * getaccountaddress + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\"")); + BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account + BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount)); + BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get()); + + /********************************* + * getaccount + *********************************/ + BOOST_CHECK_THROW(CallRPC("getaccount"), std::runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString())); + + /********************************* + * signmessage + verifymessage + *********************************/ + BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage")); + BOOST_CHECK_THROW(CallRPC("signmessage"), std::runtime_error); + /* Should throw error because this address is not loaded in the wallet */ + BOOST_CHECK_THROW(CallRPC("signmessage D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5R mymessage"), std::runtime_error); + + /* missing arguments */ + BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), std::runtime_error); + /* Illegal address */ + BOOST_CHECK_THROW(CallRPC("verifymessage D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5 " + retValue.get_str() + " mymessage"), std::runtime_error); + /* wrong address */ + BOOST_CHECK(CallRPC("verifymessage D8w12Vu3WVhn543dgrUUf9uYu6HLwnPm5R " + retValue.get_str() + " mymessage").get_bool() == false); + /* Correct address and signature but wrong message */ + BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false); + /* Correct address, message and signature*/ + BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true); + + /********************************* + * getaddressesbyaccount + *********************************/ + BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), std::runtime_error); + BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount)); + UniValue arr = retValue.get_array(); + BOOST_CHECK(arr.size() > 0); + BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 464a8fbb8cfb..258032845991 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -4,9 +4,11 @@ #include "compat/sanity.h" #include "key.h" +#include "test_phore.h" #include -BOOST_AUTO_TEST_SUITE(sanity_tests) + +BOOST_FIXTURE_TEST_SUITE(sanity_tests, TestingSetup) BOOST_AUTO_TEST_CASE(basic_sanity) { diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index f088d1d27983..4ccc4ebc130c 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -9,6 +9,7 @@ #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" +#include "test_phore.h" #ifdef ENABLE_WALLET #include "wallet_ismine.h" @@ -18,7 +19,6 @@ #include -using namespace std; // Helpers: static std::vector @@ -47,8 +47,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri return VerifyScript(scriptSig, scriptPubKey, NULL, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); } - -BOOST_AUTO_TEST_SUITE(script_P2SH_tests) +BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, TestingSetup) BOOST_AUTO_TEST_CASE(sign) { @@ -81,7 +80,7 @@ BOOST_AUTO_TEST_CASE(sign) } CMutableTransaction txFrom; // Funding transaction: - string reason; + std::string reason; txFrom.vout.resize(8); for (int i = 0; i < 4; i++) { @@ -179,7 +178,7 @@ BOOST_AUTO_TEST_CASE(set) } CMutableTransaction txFrom; // Funding transaction: - string reason; + std::string reason; txFrom.vout.resize(4); for (int i = 0; i < 4; i++) { diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index b6fa23b7f91c..4d093dc8c5b6 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -14,7 +14,8 @@ #include "script/sign.h" #include "util.h" #include "utilstrencodings.h" -#include "rpcserver.h" +#include "rpc/server.h" +#include "test_phore.h" #if defined(HAVE_CONSENSUS_LIB) #include "script/bitcoinconsensus.h" @@ -31,21 +32,19 @@ #include #include #include -#include + #include #include -using namespace std; -using namespace boost::algorithm; // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; -unsigned int ParseScriptFlags(string strFlags); -string FormatScriptFlags(unsigned int flags); +unsigned int ParseScriptFlags(std::string strFlags); +std::string FormatScriptFlags(unsigned int flags); UniValue read_json(const std::string& jsondata) @@ -60,7 +59,7 @@ read_json(const std::string& jsondata) return v.get_array(); } -BOOST_AUTO_TEST_SUITE(script_tests) +BOOST_FIXTURE_TEST_SUITE(script_tests, TestingSetup) CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int nValue = 0) { @@ -809,7 +808,7 @@ BOOST_AUTO_TEST_CASE(script_build) std::string strGood; std::string strBad; - BOOST_FOREACH(TestBuilder& test, good) { + for (TestBuilder& test : good) { test.Test(true); std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS @@ -819,7 +818,7 @@ BOOST_AUTO_TEST_CASE(script_build) #endif strGood += str + ",\n"; } - BOOST_FOREACH(TestBuilder& test, bad) { + for (TestBuilder& test : bad) { test.Test(false); std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS @@ -851,7 +850,7 @@ BOOST_AUTO_TEST_CASE(script_valid) for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); CScriptWitness witness; CAmount nValue = 0; unsigned int pos = 0; @@ -870,9 +869,9 @@ BOOST_AUTO_TEST_CASE(script_valid) } continue; } - string scriptSigString = test[pos++].get_str(); + std::string scriptSigString = test[pos++].get_str(); CScript scriptSig = ParseScript(scriptSigString); - string scriptPubKeyString = test[pos++].get_str(); + std::string scriptPubKeyString = test[pos++].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); @@ -887,7 +886,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); CScriptWitness witness; CAmount nValue = 0; unsigned int pos = 0; @@ -906,9 +905,9 @@ BOOST_AUTO_TEST_CASE(script_invalid) } continue; } - string scriptSigString = test[pos++].get_str(); + std::string scriptSigString = test[pos++].get_str(); CScript scriptSig = ParseScript(scriptSigString); - string scriptPubKeyString = test[pos++].get_str(); + std::string scriptPubKeyString = test[pos++].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); @@ -926,21 +925,21 @@ BOOST_AUTO_TEST_CASE(script_PushData) static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; ScriptError err; - vector > directStack; + std::vector > directStack; BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - vector > pushdata1Stack; + std::vector > pushdata1Stack; BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - vector > pushdata2Stack; + std::vector > pushdata2Stack; BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - vector > pushdata4Stack; + std::vector > pushdata4Stack; BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); @@ -961,9 +960,9 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac // and vice-versa) // result << OP_0; - BOOST_FOREACH(const CKey &key, keys) + for (const CKey &key : keys) { - vector vchSig; + std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); result << vchSig; @@ -1075,15 +1074,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); -} +} BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function CAmount amount = 0; CBasicKeyStore keystore; - vector keys; - vector pubkeys; + std::vector keys; + std::vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; @@ -1144,15 +1143,15 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: - vector sig1; + std::vector sig1; uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); - vector sig2; + std::vector sig2; uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); - vector sig3; + std::vector sig3; uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp index 8d62d2de8979..c74ae5cd38d0 100644 --- a/src/test/scriptnum_tests.cpp +++ b/src/test/scriptnum_tests.cpp @@ -4,10 +4,13 @@ #include "libzerocoin/bignum.h" #include "script/script.h" +#include "test/test_phore.h" + #include #include #include -BOOST_AUTO_TEST_SUITE(scriptnum_tests) + +BOOST_FIXTURE_TEST_SUITE(scriptnum_tests, BasicTestingSetup) static const long values[] = \ { 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, static_castUINT_MAX, LONG_MIN, LONG_MAX }; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 59e95f2fd123..1025b952e722 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -4,14 +4,15 @@ #include "serialize.h" #include "streams.h" +#include "hash.h" +#include "test/test_phore.h" #include #include -using namespace std; -BOOST_AUTO_TEST_SUITE(serialize_tests) +BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(varints) { @@ -48,7 +49,7 @@ BOOST_AUTO_TEST_CASE(varints) BOOST_AUTO_TEST_CASE(compactsize) { CDataStream ss(SER_DISK, 0); - vector::size_type i, j; + std::vector::size_type i, j; for (i = 1; i <= MAX_SIZE; i *= 2) { @@ -70,8 +71,8 @@ static bool isCanonicalException(const std::ios_base::failure& ex) // The string returned by what() can be different for different platforms. // Instead of directly comparing the ex.what() with an expected string, - // create an instance of exception to see if ex.what() matches - // the expected explanatory string returned by the exception instance. + // create an instance of exception to see if ex.what() matches + // the expected explanatory string returned by the exception instance. return strcmp(expectedException.what(), ex.what()) == 0; } @@ -81,7 +82,7 @@ BOOST_AUTO_TEST_CASE(noncanonical) // Write some non-canonical CompactSize encodings, and // make sure an exception is thrown when read back. CDataStream ss(SER_DISK, 0); - vector::size_type n; + std::vector::size_type n; // zero encoded with three bytes: ss.write("\xfd\x00\x00", 3); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index fe0737d63a0f..2834dd3c9f50 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -11,6 +11,7 @@ #include "script/interpreter.h" #include "util.h" #include "version.h" +#include "test_phore.h" #include @@ -113,7 +114,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { } } -BOOST_AUTO_TEST_SUITE(sighash_tests) +BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sighash_test) { diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 87f987cfb69e..680dfbfbe04c 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -8,13 +8,13 @@ #include "script/script.h" #include "script/standard.h" #include "uint256.h" +#include "test_phore.h" #include -#include + #include -using namespace std; // Helpers: static std::vector @@ -24,7 +24,7 @@ Serialize(const CScript& s) return sSerialized; } -BOOST_AUTO_TEST_SUITE(sigopcount_tests) +BOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(GetSigOpCount) { @@ -163,8 +163,8 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript scriptSig = CScript(); CTxinWitness witness; CScriptWitness scriptWitness; - scriptWitness.stack.push_back(vector(0)); - scriptWitness.stack.push_back(vector(0)); + scriptWitness.stack.push_back(std::vector(0)); + scriptWitness.stack.push_back(std::vector(0)); witness.scriptWitness = scriptWitness; @@ -195,8 +195,8 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) scriptSig = CScript() << ToByteVector(scriptSig); CTxinWitness witness; CScriptWitness scriptWitness; - scriptWitness.stack.push_back(vector(0)); - scriptWitness.stack.push_back(vector(0)); + scriptWitness.stack.push_back(std::vector(0)); + scriptWitness.stack.push_back(std::vector(0)); witness.scriptWitness = scriptWitness; BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness); @@ -211,9 +211,9 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript scriptSig = CScript(); CTxinWitness witness; CScriptWitness scriptWitness; - scriptWitness.stack.push_back(vector(0)); - scriptWitness.stack.push_back(vector(0)); - scriptWitness.stack.push_back(vector(witnessScript.begin(), witnessScript.end())); + scriptWitness.stack.push_back(std::vector(0)); + scriptWitness.stack.push_back(std::vector(0)); + scriptWitness.stack.push_back(std::vector(witnessScript.begin(), witnessScript.end())); witness.scriptWitness = scriptWitness; BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness); @@ -230,9 +230,9 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript scriptSig = CScript() << ToByteVector(redeemScript); CTxinWitness witness; CScriptWitness scriptWitness; - scriptWitness.stack.push_back(vector(0)); - scriptWitness.stack.push_back(vector(0)); - scriptWitness.stack.push_back(vector(witnessScript.begin(), witnessScript.end())); + scriptWitness.stack.push_back(std::vector(0)); + scriptWitness.stack.push_back(std::vector(0)); + scriptWitness.stack.push_back(std::vector(witnessScript.begin(), witnessScript.end())); witness.scriptWitness = scriptWitness; BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness); diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index a123f1d197fd..a6a5ced4a745 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -5,6 +5,7 @@ #include "main.h" #include "random.h" #include "util.h" +#include "test/test_phore.h" #include @@ -12,7 +13,7 @@ #define SKIPLIST_LENGTH 300000 -BOOST_AUTO_TEST_SUITE(skiplist_tests) +BOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(skiplist_test) { diff --git a/src/test/test_phore.cpp b/src/test/test_phore.cpp index 50a8bcf8e6e9..209c8efadd18 100644 --- a/src/test/test_phore.cpp +++ b/src/test/test_phore.cpp @@ -4,6 +4,8 @@ #define BOOST_TEST_MODULE Phore Test Suite +#include "test_phore.h" + #include "main.h" #include "random.h" #include "txdb.h" @@ -14,9 +16,7 @@ #include "wallet/wallet.h" #endif -#include #include -#include CClientUIInterface uiInterface; CWallet* pwalletMain; @@ -24,20 +24,25 @@ CWallet* pwalletMain; extern bool fPrintToConsole; extern void noui_connect(); -struct TestingSetup { - CCoinsViewDB *pcoinsdbview; - boost::filesystem::path pathTemp; - boost::thread_group threadGroup; - - TestingSetup() { +BasicTestingSetup::BasicTestingSetup() +{ + ECC_Start(); SetupEnvironment(); fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; SelectParams(CBaseChainParams::UNITTEST); - noui_connect(); +} +BasicTestingSetup::~BasicTestingSetup() +{ + ECC_Stop(); +} + +TestingSetup::TestingSetup() +{ #ifdef ENABLE_WALLET bitdb.MakeMock(); #endif + ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_phore_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); boost::filesystem::create_directories(pathTemp); mapArgs["-datadir"] = pathTemp.string(); @@ -55,27 +60,28 @@ struct TestingSetup { for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); RegisterNodeSignals(GetNodeSignals()); - } - ~TestingSetup() - { +} + +TestingSetup::~TestingSetup() +{ + UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); - UnregisterNodeSignals(GetNodeSignals()); #ifdef ENABLE_WALLET + UnregisterValidationInterface(pwalletMain); delete pwalletMain; pwalletMain = NULL; #endif + UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; delete pblocktree; #ifdef ENABLE_WALLET bitdb.Flush(true); + bitdb.Reset(); #endif boost::filesystem::remove_all(pathTemp); - } -}; - -BOOST_GLOBAL_FIXTURE(TestingSetup); +} void Shutdown(void* parg) { diff --git a/src/test/test_phore.h b/src/test/test_phore.h new file mode 100644 index 000000000000..6d1fe37aca2e --- /dev/null +++ b/src/test/test_phore.h @@ -0,0 +1,31 @@ +#ifndef PHORE_TEST_TEST_PHORE_H +#define PHORE_TEST_TEST_PHORE_H + +#include "txdb.h" + +#include +#include + +/** Basic testing setup. + * This just configures logging and chain parameters. + */ +struct BasicTestingSetup { + BasicTestingSetup(); + ~BasicTestingSetup(); +}; + +/** Testing setup that configures a complete environment. + * Included are data directory, coins database, script check threads + * and wallet (if enabled) setup. + */ +struct TestingSetup: public BasicTestingSetup { + CCoinsViewDB *pcoinsdbview; + boost::filesystem::path pathTemp; + boost::thread_group threadGroup; + ECCVerifyHandle globalVerifyHandle; + + TestingSetup(); + ~TestingSetup(); +}; + +#endif diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp index aa4fa0d500e8..5b895bc9b9a9 100644 --- a/src/test/timedata_tests.cpp +++ b/src/test/timedata_tests.cpp @@ -3,12 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. // #include "timedata.h" +#include "test/test_phore.h" #include -using namespace std; -BOOST_AUTO_TEST_SUITE(timedata_tests) +BOOST_FIXTURE_TEST_SUITE(timedata_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_MedianFilter) { diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 2d1236ab13bc..4c5138b67005 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -5,6 +5,7 @@ #include "data/tx_invalid.json.h" #include "data/tx_valid.json.h" +#include "test/test_phore.h" #include "checkqueue.h" #include "clientversion.h" @@ -18,6 +19,7 @@ #include "core_io.h" #include "script/standard.h" #include "utilstrencodings.h" +#include "test_phore.h" #include #include @@ -27,46 +29,44 @@ #include #include #include -#include + #include -using namespace std; -using namespace boost::algorithm; -typedef vector valtype; +typedef std::vector valtype; // In script_tests.cpp extern UniValue read_json(const std::string& jsondata); -static std::map mapFlagNames = boost::assign::map_list_of - (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) - (string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH) - (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC) - (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG) - (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S) - (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY) - (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA) - (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) - (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) - (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK) - (string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS) - (string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) - (string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) - (string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) - (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) +static std::map mapFlagNames = boost::assign::map_list_of + (std::string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) + (std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH) + (std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC) + (std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG) + (std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S) + (std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY) + (std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA) + (std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) + (std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) + (std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK) + (std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS) + (std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) + (std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) + (std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) + (std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) ; -unsigned int ParseScriptFlags(string strFlags) +unsigned int ParseScriptFlags(std::string strFlags) { if (strFlags.empty()) { return 0; } unsigned int flags = 0; - vector words; + std::vector words; split(words, strFlags, is_any_of(",")); - BOOST_FOREACH(string word, words) + for (std::string word : words) { if (!mapFlagNames.count(word)) BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); @@ -76,13 +76,13 @@ unsigned int ParseScriptFlags(string strFlags) return flags; } -string FormatScriptFlags(unsigned int flags) +std::string FormatScriptFlags(unsigned int flags) { if (flags == 0) { return ""; } - string ret; - std::map::const_iterator it = mapFlagNames.begin(); + std::string ret; + std::map::const_iterator it = mapFlagNames.begin(); while (it != mapFlagNames.end()) { if (flags & it->second) { ret += it->first + ","; @@ -92,7 +92,7 @@ string FormatScriptFlags(unsigned int flags) return ret.substr(0, ret.size() - 1); } -BOOST_AUTO_TEST_SUITE(transaction_tests) +BOOST_FIXTURE_TEST_SUITE(transaction_tests, TestingSetup) BOOST_AUTO_TEST_CASE(tx_valid) { @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) ScriptError err; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); if (test[0].isArray()) { if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) @@ -117,12 +117,12 @@ BOOST_AUTO_TEST_CASE(tx_valid) continue; } - map mapprevOutScriptPubKeys; - map mapprevOutValues; + std::map mapprevOutScriptPubKeys; + std::map mapprevOutValues; UniValue inputs = test[0].get_array(); bool fValid = true; - for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { - const UniValue& input = inputs[inpIdx]; + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { + const UniValue& input = inputs[inpIdx]; if (!input.isArray()) { fValid = false; @@ -147,7 +147,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) continue; } - string transaction = test[1].get_str(); + std::string transaction = test[1].get_str(); CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; stream >> tx; @@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) ScriptError err; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); if (test[0].isArray()) { if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) @@ -202,12 +202,12 @@ BOOST_AUTO_TEST_CASE(tx_invalid) continue; } - map mapprevOutScriptPubKeys; - map mapprevOutValues; + std::map mapprevOutScriptPubKeys; + std::map mapprevOutValues; UniValue inputs = test[0].get_array(); bool fValid = true; - for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { - const UniValue& input = inputs[inpIdx]; + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { + const UniValue& input = inputs[inpIdx]; if (!input.isArray()) { fValid = false; @@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) continue; } - string transaction = test[1].get_str(); + std::string transaction = test[1].get_str(); CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; stream >> tx; @@ -267,7 +267,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) { // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; - vector vch(ch, ch + sizeof(ch) -1); + std::vector vch(ch, ch + sizeof(ch) -1); CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CMutableTransaction tx; stream >> tx; @@ -398,10 +398,10 @@ void CheckWithFlag(const CTransaction& output, const CMutableTransaction& input, assert(ret == success); } -static CScript PushAll(const vector& values) +static CScript PushAll(const std::vector& values) { CScript result; - BOOST_FOREACH(const valtype& v, values) { + for (const valtype& v : values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { @@ -415,7 +415,7 @@ static CScript PushAll(const vector& values) void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) { - vector stack; + std::vector stack; EvalScript(stack, script, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); assert(stack.size() > 0); stack.back() = std::vector(redeemScript.begin(), redeemScript.end()); @@ -434,7 +434,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { CKeyID hash = key.GetPubKey().GetID(); CScript scriptPubKey = CScript() << OP_0 << std::vector(hash.begin(), hash.end()); - vector sigHashes; + std::vector sigHashes; sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY); sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY); sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY); @@ -696,7 +696,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) key.MakeNewKey(true); t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - string reason; + std::string reason; BOOST_CHECK(IsStandardTx(t, reason)); t.vout[0].nValue = 5011; // dust diff --git a/src/test/tutorial_zerocoin.cpp b/src/test/tutorial_zerocoin.cpp index ab711f02d906..8917f1df9623 100644 --- a/src/test/tutorial_zerocoin.cpp +++ b/src/test/tutorial_zerocoin.cpp @@ -24,8 +24,8 @@ #include "libzerocoin/Coin.h" #include "libzerocoin/CoinSpend.h" #include "libzerocoin/Accumulator.h" +#include "test_phore.h" -using namespace std; #define COINS_TO_ACCUMULATE 5 #define DUMMY_TRANSACTION_HASH 0 // in real life these would be uint256 hashes @@ -48,236 +48,236 @@ using namespace std; bool ZerocoinTutorial() { - // The following simple code illustrates the call flow for Zerocoin - // applications. In a real currency network these operations would - // be split between individual payers/payees, network nodes and miners. - // - // For each call we specify the participant who would use it. - - // Zerocoin uses exceptions (based on the runtime_error class) - // to indicate all sorts of problems. Always remember to catch them! - - try { - - /********************************************************************/ - // What is it: Parameter loading - // Who does it: ALL ZEROCOIN PARTICIPANTS - // What it does: Loads a trusted Zerocoin modulus "N" and - // generates all associated parameters from it. - // We use a hardcoded "N" that we generated using - // the included 'paramgen' utility. - /********************************************************************/ - - // Load a test modulus from our hardcoded string (above) - CBigNum testModulus; - testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS)); - - // Set up the Zerocoin Params object - libzerocoin::ZerocoinParams* params = new libzerocoin::ZerocoinParams(testModulus); - - cout << "Successfully loaded parameters." << endl; - - /********************************************************************/ - // What is it: Coin generation - // Who does it: ZEROCOIN CLIENTS - // What it does: Generates a new 'zerocoin' coin using the - // public parameters. Once generated, the client - // will transmit the public portion of this coin - // in a ZEROCOIN_MINT transaction. The inputs - // to this transaction must add up to the zerocoin - // denomination plus any transaction fees. - /********************************************************************/ - - // The following constructor does all the work of minting a brand - // new zerocoin. It stores all the private values inside the - // PrivateCoin object. This includes the coin secrets, which must be - // stored in a secure location (wallet) at the client. + // The following simple code illustrates the call flow for Zerocoin + // applications. In a real currency network these operations would + // be split between individual payers/payees, network nodes and miners. + // + // For each call we specify the participant who would use it. + + // Zerocoin uses exceptions (based on the std::runtime_error class) + // to indicate all sorts of problems. Always remember to catch them! + + try { + + /********************************************************************/ + // What is it: Parameter loading + // Who does it: ALL ZEROCOIN PARTICIPANTS + // What it does: Loads a trusted Zerocoin modulus "N" and + // generates all associated parameters from it. + // We use a hardcoded "N" that we generated using + // the included 'paramgen' utility. + /********************************************************************/ + + // Load a test modulus from our hardcoded string (above) + CBigNum testModulus; + testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS)); + + // Set up the Zerocoin Params object + libzerocoin::ZerocoinParams* params = new libzerocoin::ZerocoinParams(testModulus); + + cout << "Successfully loaded parameters." << endl; + + /********************************************************************/ + // What is it: Coin generation + // Who does it: ZEROCOIN CLIENTS + // What it does: Generates a new 'zerocoin' coin using the + // public parameters. Once generated, the client + // will transmit the public portion of this coin + // in a ZEROCOIN_MINT transaction. The inputs + // to this transaction must add up to the zerocoin + // denomination plus any transaction fees. + /********************************************************************/ + + // The following constructor does all the work of minting a brand + // new zerocoin. It stores all the private values inside the + // PrivateCoin object. This includes the coin secrets, which must be + // stored in a secure location (wallet) at the client. libzerocoin::PrivateCoin newCoin(params, libzerocoin::CoinDenomination::ZQ_ONE); - // Get a copy of the 'public' portion of the coin. You should - // embed this into a Zerocoin 'MINT' transaction along with a series - // of currency inputs totaling the assigned value of one zerocoin. - libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin(); - - cout << "Successfully minted a zerocoin." << endl; - - // Serialize the public coin to a CDataStream object. - CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION); - serializedCoin << pubCoin; - - /********************************************************************/ - // What is it: Coin verification - // Who does it: TRANSACTION VERIFIERS - // What it does: Verifies the structure of a zerocoin obtained from - // a ZEROCOIN_MINT transaction. All coins must be - // verified before you operate on them. - // Note that this is only part of the transaction - // verification process! The client must also check - // that (1) the inputs to the transaction are valid - // and add up to the value of one zerocoin, (2) that - // this particular zerocoin has not been minted before. - /********************************************************************/ - - // Deserialize the public coin into a fresh object. - libzerocoin::PublicCoin pubCoinNew(params, serializedCoin); - - // Now make sure the coin is valid. - if (!pubCoinNew.validate()) { - // If this returns false, don't accept the coin for any purpose! - // Any ZEROCOIN_MINT with an invalid coin should NOT be - // accepted as a valid transaction in the block chain. - cout << "Error: coin is not valid!"; - } - - cout << "Deserialized and verified the coin." << endl; - - /********************************************************************/ - // What is it: Accumulator computation - // Who does it: ZEROCOIN CLIENTS & TRANSACTION VERIFIERS - // What it does: Collects a number of PublicCoin values drawn from - // the block chain and calculates an accumulator. - // This accumulator is incrementally computable; - // you can stop and serialize it at any point - // then continue accumulating new transactions. - // The accumulator is also order-independent, so - // the same coins can be accumulated in any order - // to give the same result. - // WARNING: do not accumulate the same coin twice! - /********************************************************************/ - - // Create an empty accumulator object + // Get a copy of the 'public' portion of the coin. You should + // embed this into a Zerocoin 'MINT' transaction along with a series + // of currency inputs totaling the assigned value of one zerocoin. + libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin(); + + cout << "Successfully minted a zerocoin." << endl; + + // Serialize the public coin to a CDataStream object. + CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION); + serializedCoin << pubCoin; + + /********************************************************************/ + // What is it: Coin verification + // Who does it: TRANSACTION VERIFIERS + // What it does: Verifies the structure of a zerocoin obtained from + // a ZEROCOIN_MINT transaction. All coins must be + // verified before you operate on them. + // Note that this is only part of the transaction + // verification process! The client must also check + // that (1) the inputs to the transaction are valid + // and add up to the value of one zerocoin, (2) that + // this particular zerocoin has not been minted before. + /********************************************************************/ + + // Deserialize the public coin into a fresh object. + libzerocoin::PublicCoin pubCoinNew(params, serializedCoin); + + // Now make sure the coin is valid. + if (!pubCoinNew.validate()) { + // If this returns false, don't accept the coin for any purpose! + // Any ZEROCOIN_MINT with an invalid coin should NOT be + // accepted as a valid transaction in the block chain. + cout << "Error: coin is not valid!"; + } + + cout << "Deserialized and verified the coin." << endl; + + /********************************************************************/ + // What is it: Accumulator computation + // Who does it: ZEROCOIN CLIENTS & TRANSACTION VERIFIERS + // What it does: Collects a number of PublicCoin values drawn from + // the block chain and calculates an accumulator. + // This accumulator is incrementally computable; + // you can stop and serialize it at any point + // then continue accumulating new transactions. + // The accumulator is also order-independent, so + // the same coins can be accumulated in any order + // to give the same result. + // WARNING: do not accumulate the same coin twice! + /********************************************************************/ + + // Create an empty accumulator object libzerocoin::Accumulator accumulator(params,libzerocoin::CoinDenomination::ZQ_ONE); - // Add several coins to it (we'll generate them here on the fly). - for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) { + // Add several coins to it (we'll generate them here on the fly). + for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) { libzerocoin::PrivateCoin testCoin(params, libzerocoin::CoinDenomination::ZQ_ONE); - accumulator += testCoin.getPublicCoin(); - } - - // Serialize the accumulator object. - // - // If you're using Accumulator Checkpoints, each miner would - // start by deserializing the accumulator checkpoint from the - // previous block (or creating a new Accumulator if no previous - // block exists). It will then add all the coins in the new block, - // then serialize the resulting Accumulator object to obtain the - // new checkpoint. All block verifiers should do the same thing - // to check their work. - CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION); - serializedAccumulator << accumulator; - - // Deserialize the accumulator object - libzerocoin::Accumulator newAccumulator(params, serializedAccumulator); - - // We can now continue accumulating things into the accumulator - // we just deserialized. For example, let's put in the coin - // we generated up above. - newAccumulator += pubCoinNew; - - cout << "Successfully accumulated coins." << endl; - - /********************************************************************/ - // What is it: Coin spend - // Who does it: ZEROCOIN CLIENTS - // What it does: Create a new transaction that spends a Zerocoin. - // The user first authors a transaction specifying - // a set of destination addresses (outputs). They - // next compute an Accumulator over all coins in the - // block chain (see above) and a Witness based on the - // coin to be spent. Finally they instantiate a CoinSpend - // object that 'signs' the transaction with a special - // zero knowledge signature of knowledge over the coin - // data, Witness and Accumulator. - /********************************************************************/ - - // We are going to spend the coin "newCoin" that we generated at the - // top of this function. - // - // We'll use the accumulator we constructed above. This contains - // a set of coins, but does NOT include the coin "newCoin". - // - // To generate the witness, we start with this accumulator and - // add the public half of the coin we want to spend. - libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin()); - - // Add the public half of "newCoin" to the Accumulator itself. - accumulator += newCoin.getPublicCoin(); - - // At this point we should generate a ZEROCOIN_SPEND transaction to - // send to the network. This network should include a set of outputs - // totalling to the value of one zerocoin (minus transaction fees). - - // Construct the CoinSpend object. This acts like a signature on the - // transaction. + accumulator += testCoin.getPublicCoin(); + } + + // Serialize the accumulator object. + // + // If you're using Accumulator Checkpoints, each miner would + // start by deserializing the accumulator checkpoint from the + // previous block (or creating a new Accumulator if no previous + // block exists). It will then add all the coins in the new block, + // then serialize the resulting Accumulator object to obtain the + // new checkpoint. All block verifiers should do the same thing + // to check their work. + CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION); + serializedAccumulator << accumulator; + + // Deserialize the accumulator object + libzerocoin::Accumulator newAccumulator(params, serializedAccumulator); + + // We can now continue accumulating things into the accumulator + // we just deserialized. For example, let's put in the coin + // we generated up above. + newAccumulator += pubCoinNew; + + cout << "Successfully accumulated coins." << endl; + + /********************************************************************/ + // What is it: Coin spend + // Who does it: ZEROCOIN CLIENTS + // What it does: Create a new transaction that spends a Zerocoin. + // The user first authors a transaction specifying + // a set of destination addresses (outputs). They + // next compute an Accumulator over all coins in the + // block chain (see above) and a Witness based on the + // coin to be spent. Finally they instantiate a CoinSpend + // object that 'signs' the transaction with a special + // zero knowledge signature of knowledge over the coin + // data, Witness and Accumulator. + /********************************************************************/ + + // We are going to spend the coin "newCoin" that we generated at the + // top of this function. + // + // We'll use the accumulator we constructed above. This contains + // a set of coins, but does NOT include the coin "newCoin". + // + // To generate the witness, we start with this accumulator and + // add the public half of the coin we want to spend. + libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin()); + + // Add the public half of "newCoin" to the Accumulator itself. + accumulator += newCoin.getPublicCoin(); + + // At this point we should generate a ZEROCOIN_SPEND transaction to + // send to the network. This network should include a set of outputs + // totalling to the value of one zerocoin (minus transaction fees). + + // Construct the CoinSpend object. This acts like a signature on the + // transaction. libzerocoin::CoinSpend spend(params, params, newCoin, accumulator, 0, witness, 0, libzerocoin::SpendType::SPEND);//(0) - Presstab - // This is a sanity check. The CoinSpend object should always verify, - // but why not check before we put it onto the wire? - if (!spend.Verify(accumulator)) { - cout << "ERROR: Our new CoinSpend transaction did not verify!" << endl; - return false; - } - - // Serialize the CoinSpend object into a buffer. - CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION); - serializedCoinSpend << spend; - - cout << "Successfully generated a coin spend transaction." << endl; - - /********************************************************************/ - // What is it: Coin spend verification - // Who does it: ALL PARTIES - // What it does: Verifies that a CoinSpend signature is correct - // with respect to a ZEROCOIN_SPEND transaction hash. - // The client must also extract the serial number from - // the CoinSpend and verify that this serial number has - // not previously appeared in another ZEROCOIN_SPEND - // transaction. - /********************************************************************/ - - // Deserialize the CoinSpend intro a fresh object - libzerocoin::CoinSpend newSpend(params, params, serializedCoinSpend); - - // Create a new metadata object to contain the hash of the received - // ZEROCOIN_SPEND transaction. If we were a real client we'd actually - // compute the hash of the received transaction here. - - // If we were a real client we would now re-compute the Accumulator - // from the information given in the ZEROCOIN_SPEND transaction. - // For our purposes we'll just use the one we calculated above. - // - // Verify that the spend is valid with respect to the Accumulator - // and the Metadata - if (!newSpend.Verify(accumulator)) { - cout << "ERROR: The CoinSpend transaction did not verify!" << endl; - return false; - } - - // Pull the serial number out of the CoinSpend object. If we - // were a real Zerocoin client we would now check that the serial number - // has not been spent before (in another ZEROCOIN_SPEND) transaction. - // The serial number is stored as a CBigNum. - CBigNum serialNumber = newSpend.getCoinSerialNumber(); - - cout << "Successfully verified a coin spend transaction." << endl; - cout << endl << "Coin serial number is:" << endl << serialNumber << endl; - - // We're done - return true; - - } catch (runtime_error &e) { - cout << e.what() << endl; - return false; - } - - return false; + // This is a sanity check. The CoinSpend object should always verify, + // but why not check before we put it onto the wire? + if (!spend.Verify(accumulator)) { + cout << "ERROR: Our new CoinSpend transaction did not verify!" << endl; + return false; + } + + // Serialize the CoinSpend object into a buffer. + CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION); + serializedCoinSpend << spend; + + cout << "Successfully generated a coin spend transaction." << endl; + + /********************************************************************/ + // What is it: Coin spend verification + // Who does it: ALL PARTIES + // What it does: Verifies that a CoinSpend signature is correct + // with respect to a ZEROCOIN_SPEND transaction hash. + // The client must also extract the serial number from + // the CoinSpend and verify that this serial number has + // not previously appeared in another ZEROCOIN_SPEND + // transaction. + /********************************************************************/ + + // Deserialize the CoinSpend intro a fresh object + libzerocoin::CoinSpend newSpend(params, params, serializedCoinSpend); + + // Create a new metadata object to contain the hash of the received + // ZEROCOIN_SPEND transaction. If we were a real client we'd actually + // compute the hash of the received transaction here. + + // If we were a real client we would now re-compute the Accumulator + // from the information given in the ZEROCOIN_SPEND transaction. + // For our purposes we'll just use the one we calculated above. + // + // Verify that the spend is valid with respect to the Accumulator + // and the Metadata + if (!newSpend.Verify(accumulator)) { + cout << "ERROR: The CoinSpend transaction did not verify!" << endl; + return false; + } + + // Pull the serial number out of the CoinSpend object. If we + // were a real Zerocoin client we would now check that the serial number + // has not been spent before (in another ZEROCOIN_SPEND) transaction. + // The serial number is stored as a CBigNum. + CBigNum serialNumber = newSpend.getCoinSerialNumber(); + + cout << "Successfully verified a coin spend transaction." << endl; + cout << endl << "Coin serial number is:" << endl << serialNumber << endl; + + // We're done + return true; + + } catch (runtime_error &e) { + cout << e.what() << endl; + return false; + } + + return false; } -BOOST_AUTO_TEST_SUITE(tutorial_libzerocoin) +BOOST_FIXTURE_TEST_SUITE(tutorial_libzerocoin, TestingSetup) BOOST_AUTO_TEST_CASE(tutorial_libzerocoin_tests) { - cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl; + cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl; - ZerocoinTutorial(); + ZerocoinTutorial(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 000eca1821e0..68bb7114b769 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -10,7 +10,7 @@ #include "txmempool.h" #include "random.h" #include "script/standard.h" -#include "test/test_bitcoin.h" +#include "test/test_phore.h" #include "utiltime.h" #include diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 4b1a2ae58f4b..f52b2b8e5b4b 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -1,7 +1,6 @@ // Copyright (c) 2011-2013 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #include #include #include @@ -11,20 +10,21 @@ #include "uint256.h" #include #include "version.h" +#include "test/test_phore.h" + +BOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup) -BOOST_AUTO_TEST_SUITE(uint256_tests) - -const unsigned char R1Array[] = +const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c"; const double R1Ldouble = 0.4887374590559308955; // R1L equals roughly R1Ldouble * 2^256 -const double R1Sdouble = 0.7096329412477836074; +const double R1Sdouble = 0.7096329412477836074; const uint256 R1L = uint256(std::vector(R1Array,R1Array+32)); const uint160 R1S = uint160(std::vector(R1Array,R1Array+20)); const uint64_t R1LLow64 = 0x121156cfdb4a529cULL; -const unsigned char R2Array[] = +const unsigned char R2Array[] = "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf" "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; const uint256 R2L = uint256(std::vector(R2Array,R2Array+32)); @@ -32,19 +32,19 @@ const uint160 R2S = uint160(std::vector(R2Array,R2Array+20)); const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C"; -const unsigned char ZeroArray[] = +const unsigned char ZeroArray[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const uint256 ZeroL = uint256(std::vector(ZeroArray,ZeroArray+32)); const uint160 ZeroS = uint160(std::vector(ZeroArray,ZeroArray+20)); - -const unsigned char OneArray[] = + +const unsigned char OneArray[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const uint256 OneL = uint256(std::vector(OneArray,OneArray+32)); const uint160 OneS = uint160(std::vector(OneArray,OneArray+20)); -const unsigned char MaxArray[] = +const unsigned char MaxArray[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; const uint256 MaxL = uint256(std::vector(MaxArray,MaxArray+32)); @@ -56,17 +56,17 @@ std::string ArrayToString(const unsigned char A[], unsigned int width) { std::stringstream Stream; Stream << std::hex; - for (unsigned int i = 0; i < width; ++i) + for (unsigned int i = 0; i < width; ++i) { Stream<): + // constructor uint256(std::vector): BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32)); BOOST_CHECK(R1S.ToString() == ArrayToString(R1Array,20)); BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32)); @@ -88,25 +88,25 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality BOOST_CHECK(~MaxL == ZeroL && ~MaxS == ZeroS); BOOST_CHECK( ((R1L ^ R2L) ^ R1L) == R2L); BOOST_CHECK( ((R1S ^ R2S) ^ R1S) == R2S); - + uint64_t Tmp64 = 0xc4dab720d9c7acaaULL; - for (unsigned int i = 0; i < 256; ++i) + for (unsigned int i = 0; i < 256; ++i) { - BOOST_CHECK(ZeroL != (OneL << i)); - BOOST_CHECK((OneL << i) != ZeroL); + BOOST_CHECK(ZeroL != (OneL << i)); + BOOST_CHECK((OneL << i) != ZeroL); BOOST_CHECK(R1L != (R1L ^ (OneL << i))); BOOST_CHECK(((uint256(Tmp64) ^ (OneL << i) ) != Tmp64 )); } - BOOST_CHECK(ZeroL == (OneL << 256)); + BOOST_CHECK(ZeroL == (OneL << 256)); - for (unsigned int i = 0; i < 160; ++i) + for (unsigned int i = 0; i < 160; ++i) { - BOOST_CHECK(ZeroS != (OneS << i)); - BOOST_CHECK((OneS << i) != ZeroS); + BOOST_CHECK(ZeroS != (OneS << i)); + BOOST_CHECK((OneS << i) != ZeroS); BOOST_CHECK(R1S != (R1S ^ (OneS << i))); BOOST_CHECK(((uint160(Tmp64) ^ (OneS << i) ) != Tmp64 )); } - BOOST_CHECK(ZeroS == (OneS << 256)); + BOOST_CHECK(ZeroS == (OneS << 256)); // String Constructor and Copy Constructor BOOST_CHECK(uint256("0x"+R1L.ToString()) == R1L); @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality BOOST_CHECK(uint160("0x"+OneS.ToString()) == OneS); BOOST_CHECK(uint160("0x"+MaxS.ToString()) == MaxS); BOOST_CHECK(uint160(R1S.ToString()) == R1S); - BOOST_CHECK(uint160(" 0x"+R1S.ToString()+" ") == R1S); + BOOST_CHECK(uint160(" 0x"+R1S.ToString()+" ") == R1S); BOOST_CHECK(uint160("") == ZeroS); BOOST_CHECK(R1S == uint160(R1ArrayHex)); @@ -167,25 +167,25 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality BOOST_CHECK_THROW(uint160(std::vector(OneArray,OneArray+19)), uint_error); } -void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) +void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) { - for (unsigned int T=0; T < arrayLength; ++T) + for (unsigned int T=0; T < arrayLength; ++T) { unsigned int F = (T+bitsToShift/8); - if (F < arrayLength) + if (F < arrayLength) to[T] = from[F] >> (bitsToShift%8); else to[T] = 0; - if (F + 1 < arrayLength) + if (F + 1 < arrayLength) to[T] |= from[(F+1)] << (8-bitsToShift%8); } } -void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) +void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) { - for (unsigned int T=0; T < arrayLength; ++T) + for (unsigned int T=0; T < arrayLength; ++T) { - if (T >= bitsToShift/8) + if (T >= bitsToShift/8) { unsigned int F = T-bitsToShift/8; to[T] = from[F] << (bitsToShift%8); @@ -210,14 +210,14 @@ BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>=" BOOST_CHECK((HalfL >> (255-i)) == (OneL << i)); TmpL = HalfL; TmpL >>= (255-i); BOOST_CHECK(TmpL == (OneL << i)); - + shiftArrayLeft(TmpArray, R1Array, 32, i); BOOST_CHECK(uint256(std::vector(TmpArray,TmpArray+32)) == (R1L << i)); TmpL = R1L; TmpL <<= i; BOOST_CHECK(TmpL == (R1L << i)); shiftArrayRight(TmpArray, R1Array, 32, i); - BOOST_CHECK(uint256(std::vector(TmpArray,TmpArray+32)) == (R1L >> i)); + BOOST_CHECK(uint256(std::vector(TmpArray,TmpArray+32)) == (R1L >> i)); TmpL = R1L; TmpL >>= i; BOOST_CHECK(TmpL == (R1L >> i)); @@ -250,14 +250,14 @@ BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>=" BOOST_CHECK((HalfS >> (159-i)) == (OneS << i)); TmpS = HalfS; TmpS >>= (159-i); BOOST_CHECK(TmpS == (OneS << i)); - + shiftArrayLeft(TmpArray, R1Array, 20, i); BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (R1S << i)); TmpS = R1S; TmpS <<= i; BOOST_CHECK(TmpS == (R1S << i)); shiftArrayRight(TmpArray, R1Array, 20, i); - BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (R1S >> i)); + BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (R1S >> i)); TmpS = R1S; TmpS >>= i; BOOST_CHECK(TmpS == (R1S >> i)); @@ -285,27 +285,27 @@ BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ - { BOOST_CHECK(!ZeroL); BOOST_CHECK(!ZeroS); BOOST_CHECK(!(!OneL));BOOST_CHECK(!(!OneS)); - for (unsigned int i = 0; i < 256; ++i) + for (unsigned int i = 0; i < 256; ++i) BOOST_CHECK(!(!(OneL<(TmpArray,TmpArray+32)) == (~R1L)); BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (~R1S)); BOOST_CHECK(-ZeroL == ZeroL); BOOST_CHECK(-ZeroS == ZeroS); BOOST_CHECK(-R1L == (~R1L)+1); BOOST_CHECK(-R1S == (~R1S)+1); - for (unsigned int i = 0; i < 256; ++i) + for (unsigned int i = 0; i < 256; ++i) BOOST_CHECK(-(OneL<= < > } } -BOOST_AUTO_TEST_CASE( plusMinus ) +BOOST_AUTO_TEST_CASE( plusMinus ) { uint256 TmpL = 0; BOOST_CHECK(R1L+R2L == uint256(R1LplusR2L)); @@ -412,7 +412,7 @@ BOOST_AUTO_TEST_CASE( plusMinus ) BOOST_CHECK( TmpL == (HalfL >> (i-1)) ); TmpL = (MaxL>>i); TmpL += 1; BOOST_CHECK( TmpL == (HalfL >> (i-1)) ); - TmpL = (MaxL>>i); + TmpL = (MaxL>>i); BOOST_CHECK( TmpL++ == (MaxL>>i) ); BOOST_CHECK( TmpL == (HalfL >> (i-1))); } @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE( plusMinus ) BOOST_CHECK( TmpS == (HalfS >> (i-1)) ); TmpS = (MaxS>>i); TmpS += 1; BOOST_CHECK( TmpS == (HalfS >> (i-1)) ); - TmpS = (MaxS>>i); + TmpS = (MaxS>>i); BOOST_CHECK( TmpS++ == (MaxS>>i) ); BOOST_CHECK( TmpS == (HalfS >> (i-1))); } @@ -553,7 +553,7 @@ BOOST_AUTO_TEST_CASE( divide ) } -bool almostEqual(double d1, double d2) +bool almostEqual(double d1, double d2) { return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits::epsilon(); } @@ -634,7 +634,7 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(MaxS.begin() + 20 == MaxS.end()); BOOST_CHECK(TmpS.begin() + 20 == TmpS.end()); BOOST_CHECK(R1S.GetLow64() == R1LLow64); - BOOST_CHECK(HalfS.GetLow64() ==0x0000000000000000ULL); + BOOST_CHECK(HalfS.GetLow64() ==0x0000000000000000ULL); BOOST_CHECK(OneS.GetLow64() ==0x0000000000000001ULL); BOOST_CHECK(R1S.GetSerializeSize(0,PROTOCOL_VERSION) == 20); BOOST_CHECK(ZeroS.GetSerializeSize(0,PROTOCOL_VERSION) == 20); @@ -654,17 +654,17 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G TmpS.Unserialize(ss,0,PROTOCOL_VERSION); BOOST_CHECK(MaxS == TmpS); ss.str(""); - - for (unsigned int i = 0; i < 255; ++i) + + for (unsigned int i = 0; i < 255; ++i) { BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0,i)); if (i < 160) BOOST_CHECK((OneS << i).getdouble() == ldexp(1.0,i)); } BOOST_CHECK(ZeroL.getdouble() == 0.0); BOOST_CHECK(ZeroS.getdouble() == 0.0); - for (int i = 256; i > 53; --i) + for (int i = 256; i > 53; --i) BOOST_CHECK(almostEqual((R1L>>(256-i)).getdouble(), ldexp(R1Ldouble,i))); - for (int i = 160; i > 53; --i) + for (int i = 160; i > 53; --i) BOOST_CHECK(almostEqual((R1S>>(160-i)).getdouble(), ldexp(R1Sdouble,i))); uint64_t R1L64part = (R1L>>192).GetLow64(); uint64_t R1S64part = (R1S>>96).GetLow64(); @@ -809,21 +809,21 @@ BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% cover // ~R1L give a base_uint<256> BOOST_CHECK((~~R1L >> 10) == (R1L >> 10)); BOOST_CHECK((~~R1S >> 10) == (R1S >> 10)); BOOST_CHECK((~~R1L << 10) == (R1L << 10)); BOOST_CHECK((~~R1S << 10) == (R1S << 10)); - BOOST_CHECK(!(~~R1L < R1L)); BOOST_CHECK(!(~~R1S < R1S)); - BOOST_CHECK(~~R1L <= R1L); BOOST_CHECK(~~R1S <= R1S); - BOOST_CHECK(!(~~R1L > R1L)); BOOST_CHECK(!(~~R1S > R1S)); - BOOST_CHECK(~~R1L >= R1L); BOOST_CHECK(~~R1S >= R1S); - BOOST_CHECK(!(R1L < ~~R1L)); BOOST_CHECK(!(R1S < ~~R1S)); - BOOST_CHECK(R1L <= ~~R1L); BOOST_CHECK(R1S <= ~~R1S); - BOOST_CHECK(!(R1L > ~~R1L)); BOOST_CHECK(!(R1S > ~~R1S)); - BOOST_CHECK(R1L >= ~~R1L); BOOST_CHECK(R1S >= ~~R1S); - + BOOST_CHECK(!(~~R1L < R1L)); BOOST_CHECK(!(~~R1S < R1S)); + BOOST_CHECK(~~R1L <= R1L); BOOST_CHECK(~~R1S <= R1S); + BOOST_CHECK(!(~~R1L > R1L)); BOOST_CHECK(!(~~R1S > R1S)); + BOOST_CHECK(~~R1L >= R1L); BOOST_CHECK(~~R1S >= R1S); + BOOST_CHECK(!(R1L < ~~R1L)); BOOST_CHECK(!(R1S < ~~R1S)); + BOOST_CHECK(R1L <= ~~R1L); BOOST_CHECK(R1S <= ~~R1S); + BOOST_CHECK(!(R1L > ~~R1L)); BOOST_CHECK(!(R1S > ~~R1S)); + BOOST_CHECK(R1L >= ~~R1L); BOOST_CHECK(R1S >= ~~R1S); + BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L); BOOST_CHECK(~~R1S + R2S == R1S + ~~R2S); BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L); BOOST_CHECK(~~R1S - R2S == R1S - ~~R2S); - BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L); - BOOST_CHECK(~R1S != R1S); BOOST_CHECK(R1S != ~R1S); + BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L); + BOOST_CHECK(~R1S != R1S); BOOST_CHECK(R1S != ~R1S); unsigned char TmpArray[32]; CHECKBITWISEOPERATOR(~R1,R2,|) CHECKBITWISEOPERATOR(~R1,R2,^) diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index dc215cf6668d..0c09d24507c9 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -7,12 +7,11 @@ #include #include #include +#include "test/test_phore.h" #include -using namespace std; - -BOOST_AUTO_TEST_SUITE(univalue_tests) +BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(univalue_constructor) { @@ -51,7 +50,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor) BOOST_CHECK(v7.isNum()); BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); - string vs("yawn"); + std::string vs("yawn"); UniValue v8(vs); BOOST_CHECK(v8.isStr()); BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); @@ -67,41 +66,41 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck) UniValue v1; BOOST_CHECK(v1.setNumStr("1")); BOOST_CHECK(v1.isNum()); - BOOST_CHECK_THROW(v1.get_bool(), runtime_error); + BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); UniValue v2; BOOST_CHECK(v2.setBool(true)); BOOST_CHECK_EQUAL(v2.get_bool(), true); - BOOST_CHECK_THROW(v2.get_int(), runtime_error); + BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); UniValue v3; BOOST_CHECK(v3.setNumStr("32482348723847471234")); - BOOST_CHECK_THROW(v3.get_int64(), runtime_error); + BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); BOOST_CHECK(v3.setNumStr("1000")); BOOST_CHECK_EQUAL(v3.get_int64(), 1000); UniValue v4; BOOST_CHECK(v4.setNumStr("2147483648")); BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); - BOOST_CHECK_THROW(v4.get_int(), runtime_error); + BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); BOOST_CHECK(v4.setNumStr("1000")); BOOST_CHECK_EQUAL(v4.get_int(), 1000); - BOOST_CHECK_THROW(v4.get_str(), runtime_error); + BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); BOOST_CHECK_EQUAL(v4.get_real(), 1000); - BOOST_CHECK_THROW(v4.get_array(), runtime_error); - BOOST_CHECK_THROW(v4.getKeys(), runtime_error); - BOOST_CHECK_THROW(v4.getValues(), runtime_error); - BOOST_CHECK_THROW(v4.get_obj(), runtime_error); + BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); + BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); UniValue v5; BOOST_CHECK(v5.read("[true, 10]")); BOOST_CHECK_NO_THROW(v5.get_array()); std::vector vals = v5.getValues(); - BOOST_CHECK_THROW(vals[0].get_int(), runtime_error); + BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); BOOST_CHECK_EQUAL(vals[0].get_bool(), true); BOOST_CHECK_EQUAL(vals[1].get_int(), 10); - BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error); + BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); } BOOST_AUTO_TEST_CASE(univalue_set) @@ -170,13 +169,13 @@ BOOST_AUTO_TEST_CASE(univalue_array) UniValue v((int64_t)1023LL); BOOST_CHECK(arr.push_back(v)); - string vStr("zippy"); + std::string vStr("zippy"); BOOST_CHECK(arr.push_back(vStr)); const char *s = "pippy"; BOOST_CHECK(arr.push_back(s)); - vector vec; + std::vector vec; v.setStr("boing"); vec.push_back(v); @@ -204,7 +203,7 @@ BOOST_AUTO_TEST_CASE(univalue_array) BOOST_AUTO_TEST_CASE(univalue_object) { UniValue obj(UniValue::VOBJ); - string strKey, strVal; + std::string strKey, strVal; UniValue v; strKey = "age"; @@ -264,7 +263,7 @@ BOOST_AUTO_TEST_CASE(univalue_object) BOOST_CHECK(!obj.exists("nyuknyuknyuk")); - map objTypes; + std::map objTypes; objTypes["age"] = UniValue::VNUM; objTypes["first"] = UniValue::VSTR; objTypes["last"] = UniValue::VSTR; @@ -292,7 +291,7 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite) UniValue v; BOOST_CHECK(v.read(json1)); - string strJson1(json1); + std::string strJson1(json1); BOOST_CHECK(v.read(strJson1)); BOOST_CHECK(v.isArray()); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 8038a9aba03d..4354a31d48c7 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -10,15 +10,15 @@ #include "sync.h" #include "utilstrencodings.h" #include "utilmoneystr.h" +#include "test/test_phore.h" #include #include #include -using namespace std; -BOOST_AUTO_TEST_SUITE(util_tests) +BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_criticalsection) { diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index d82070c22f3d..6ea3ab5913f7 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -9,8 +9,9 @@ #include #include -#include + #include +#include "test_phore.h" // how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles #define RUN_TESTS 100 @@ -19,14 +20,12 @@ // we repeat those tests this many times and only complain if all iterations of the test fail #define RANDOM_REPEATS 5 -using namespace std; - -typedef set > CoinSet; +typedef std::set > CoinSet; -BOOST_AUTO_TEST_SUITE(wallet_tests) +BOOST_FIXTURE_TEST_SUITE(wallet_tests, TestingSetup) static CWallet wallet; -static vector vCoins; +static std::vector vCoins; static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { @@ -52,14 +51,14 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa static void empty_wallet(void) { - BOOST_FOREACH(COutput output, vCoins) + for (COutput output : vCoins) delete output.tx; vCoins.clear(); } static bool equal_sets(CoinSet a, CoinSet b) { - pair ret = mismatch(a.begin(), a.end(), b.begin()); + std::pair ret = mismatch(a.begin(), a.end(), b.begin()); return ret.first == a.end() && ret.second == b.end(); } diff --git a/src/test/zerocoin_denomination_tests.cpp b/src/test/zerocoin_denomination_tests.cpp index 8cf852d705ad..6dc103a63b2a 100644 --- a/src/test/zerocoin_denomination_tests.cpp +++ b/src/test/zerocoin_denomination_tests.cpp @@ -10,18 +10,16 @@ #include "txdb.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" +#include "test/test_phore.h" #include #include -using namespace libzerocoin; - -BOOST_AUTO_TEST_SUITE(zerocoin_denom_tests) - +BOOST_FIXTURE_TEST_SUITE(zerocoin_denom_tests, BasicTestingSetup) //translation from phore quantity to zerocoin denomination BOOST_AUTO_TEST_CASE(amount_to_denomination_test) { - cout << "Running amount_to_denomination_test...\n"; + std::cout << "Running amount_to_denomination_test...\n"; //valid amount (min edge) CAmount amount = 1 * COIN; @@ -42,7 +40,7 @@ BOOST_AUTO_TEST_CASE(amount_to_denomination_test) BOOST_AUTO_TEST_CASE(denomination_to_value_test) { - cout << "Running ZerocoinDenominationToValue_test...\n"; + std::cout << "Running ZerocoinDenominationToValue_test...\n"; int64_t Value = 1 * COIN; CoinDenomination denomination = ZQ_ONE; @@ -85,7 +83,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test241) // Create a set of Minted coins that fits profile given by DenomAmounts // Also setup Map array corresponding to DenomAmount which is the current set of coins available - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { for (int i = 0; i < DenomAmounts[j]; i++) { CAmount currentAmount = ZerocoinDenominationToAmount(denom); nTotalAmount += currentAmount; @@ -109,7 +107,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test241) // Show what we have j = 0; - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; std::cout << "\n"; @@ -169,7 +167,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test115) // Create a set of Minted coins that fits profile given by DenomAmounts // Also setup Map array corresponding to DenomAmount which is the current set of coins available - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { for (int i = 0; i < DenomAmounts[j]; i++) { CAmount currentAmount = ZerocoinDenominationToAmount(denom); nTotalAmount += currentAmount; @@ -193,7 +191,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test115) // Show what we have j = 0; - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; std::cout << "\n"; @@ -253,7 +251,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_245) // Create a set of Minted coins that fits profile given by DenomAmounts // Also setup Map array corresponding to DenomAmount which is the current set of coins available - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { for (int i = 0; i < DenomAmounts[j]; i++) { CAmount currentAmount = ZerocoinDenominationToAmount(denom); nTotalAmount += currentAmount; @@ -277,7 +275,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_245) // Show what we have j = 0; - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; std::cout << "\n"; @@ -355,7 +353,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_145) // Create a set of Minted coins that fits profile given by DenomAmounts // Also setup Map array corresponding to DenomAmount which is the current set of coins available - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { for (int i = 0; i < DenomAmounts[j]; i++) { CAmount currentAmount = ZerocoinDenominationToAmount(denom); nTotalAmount += currentAmount; @@ -382,7 +380,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_145) // Show what we have j = 0; - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; std::cout << "\n"; @@ -461,7 +459,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test99) // Create a set of Minted coins that fits profile given by DenomAmounts // Also setup Map array corresponding to DenomAmount which is the current set of coins available - for (const auto& denom : zerocoinDenomList) { + for (const auto& denom : libzerocoin::zerocoinDenomList) { for (int i = 0; i < DenomAmounts[j]; i++) { CAmount currentAmount = ZerocoinDenominationToAmount(denom); nTotalAmount += currentAmount; @@ -485,7 +483,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test99) // Show what we have j = 0; - for (const auto& denom : zerocoinDenomList) + for (const auto& denom : libzerocoin::zerocoinDenomList) std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; std::cout << "\n"; diff --git a/src/test/zerocoin_implementation_tests.cpp b/src/test/zerocoin_implementation_tests.cpp index 51153771e0c2..378e85f79320 100644 --- a/src/test/zerocoin_implementation_tests.cpp +++ b/src/test/zerocoin_implementation_tests.cpp @@ -16,16 +16,15 @@ #include #include "wallet/wallet.h" #include "zphrwallet.h" - -using namespace libzerocoin; +#include "test_phore.h" extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false); -BOOST_AUTO_TEST_SUITE(zerocoin_implementation_tests) +BOOST_FIXTURE_TEST_SUITE(zerocoin_implementation_tests, TestingSetup) BOOST_AUTO_TEST_CASE(zcparams_test) { - cout << "Running zcparams_test...\n"; + std::cout << "Running zcparams_test...\n"; bool fPassed = true; try{ @@ -67,7 +66,7 @@ std::vector > vecRawMints = {std::make_pair( //create a zerocoin mint from vecsend BOOST_AUTO_TEST_CASE(checkzerocoinmint_test) { - cout << "generating privkeys\n"; + std::cout << "generating privkeys\n"; //generate a privkey CKey key; @@ -88,7 +87,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinmint_test) BOOST_CHECK_MESSAGE(bnSerial == bnSerial2, "Serials do not match!"); - cout << "Running check_zerocoinmint_test...\n"; + std::cout << "Running check_zerocoinmint_test...\n"; CTransaction tx; BOOST_CHECK(DecodeHexTx(tx, rawTx1, true)); @@ -104,7 +103,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinmint_test) BOOST_CHECK(fFoundMint); } -bool CheckZerocoinSpendNoDB(const CTransaction tx, string& strError) +bool CheckZerocoinSpendNoDB(const CTransaction tx, std::string& strError) { //max needed non-mint outputs should be 2 - one for redemption address and a possible 2nd for change if (tx.vout.size() > 2){ @@ -129,10 +128,10 @@ bool CheckZerocoinSpendNoDB(const CTransaction tx, string& strError) // uint256 hashTxOut = txTemp.GetHash(); bool fValidated = false; - set serials; - list vSpends; + std::set serials; + std::list vSpends; CAmount nTotalRedeemed = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { //only check txin that is a zcspend if (!txin.scriptSig.IsZerocoinSpend()) @@ -221,7 +220,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) bnTrustedModulus.SetDec(zerocoinModulus); libzerocoin::ZerocoinParams zerocoinParams = libzerocoin::ZerocoinParams(bnTrustedModulus); - cout << "Running check_zerocoinspend_test...\n"; + std::cout << "Running check_zerocoinspend_test...\n"; //load our serialized pubcoin CBigNum bnpubcoin; @@ -235,7 +234,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) //populate the witness and accumulators CValidationState state; - for(pair raw : vecRawMints) { + for(std::pair raw : vecRawMints) { CTransaction tx; BOOST_CHECK_MESSAGE(DecodeHexTx(tx, raw.first, true), "Failed to deserialize hex transaction"); @@ -265,7 +264,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) uint32_t nChecksum = GetChecksum(accumulator.getValue()); //AddAccumulatorChecksum(nChecksum, accumulator.getValue(), true); CoinSpend coinSpend(Params().OldZerocoin_Params(), Params().Zerocoin_Params(), privateCoin, accumulator, nChecksum, witness, 0, SpendType::SPEND); - cout << coinSpend.ToString() << endl; + std::cout << coinSpend.ToString() << endl; BOOST_CHECK_MESSAGE(coinSpend.Verify(accumulator), "Coinspend construction failed to create valid proof"); CBigNum serial = coinSpend.getCoinSerialNumber(); @@ -313,9 +312,9 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) CTransaction txMintFrom; BOOST_CHECK_MESSAGE(DecodeHexTx(txMintFrom, rawTx1, true), "Failed to deserialize hex transaction"); - string strError = ""; + std::string strError = ""; if (!CheckZerocoinSpendNoDB(txNew, strError)) { - cout << state.GetRejectCode() << endl; + std::cout << state.GetRejectCode() << endl; BOOST_CHECK_MESSAGE(false, strError); } @@ -326,11 +325,11 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) txOverSpend.vout.push_back(txOutOverSpend); strError = ""; CheckZerocoinSpendNoDB(txOverSpend, strError); - string str = "Failed to detect overspend. Error Message: " + strError; + std::string str = "Failed to detect overspend. Error Message: " + strError; BOOST_CHECK_MESSAGE(strError == "Transaction spend more than was redeemed in zerocoins", str); - cout << "checking v2 spend\n"; + std::cout << "checking v2 spend\n"; CMutableTransaction tx; uint256 txHash = 0; @@ -358,7 +357,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) accumulator_v2 += pubTemp; witness_v2 += pubTemp; } - cout << (GetTimeMillis() - nTimeStart)/5 << "ms per mint\n"; + std::cout << (GetTimeMillis() - nTimeStart)/5 << "ms per mint\n"; accumulator_v2 += pubcoin_v2; @@ -382,7 +381,7 @@ BOOST_AUTO_TEST_CASE(setup_exceptions_test) bnTrustedModulus.SetDec(zerocoinModulus); libzerocoin::ZerocoinParams zerocoinParams = libzerocoin::ZerocoinParams(bnTrustedModulus); - cout << "Running check_unitialized parameters,etc for setup exceptions...\n"; + std::cout << "Running check_unitialized parameters,etc for setup exceptions...\n"; CBigNum bnpubcoin; BOOST_CHECK(bnpubcoin.SetHexBool(rawTxpub1)); @@ -439,7 +438,7 @@ BOOST_AUTO_TEST_CASE(setup_exceptions_test) BOOST_AUTO_TEST_CASE(checksum_tests) { - cout << "Running checksum_tests\n"; + std::cout << "Running checksum_tests\n"; uint256 checksum; uint32_t c1 = 0xa3219ef1; @@ -450,21 +449,21 @@ BOOST_AUTO_TEST_CASE(checksum_tests) uint32_t c6 = 0xbbbbbbbb; uint32_t c7 = 0x11111111; uint32_t c8 = 0xeeeeeeee; - vector vChecksums {c1,c2,c3,c4,c5,c6,c7,c8}; + std::vector vChecksums {c1,c2,c3,c4,c5,c6,c7,c8}; for(uint32_t c : vChecksums) checksum = checksum << 32 | c; BOOST_CHECK_MESSAGE(checksum == uint256("a3219ef1abcdef00101029f3aaaaaeeeffffffffbbbbbbbb11111111eeeeeeee"), "checksum not properly concatenated"); int i = 0; - for (auto& denom : zerocoinDenomList){ + for (auto& denom : libzerocoin::zerocoinDenomList){ uint32_t checksumParsed = ParseChecksum(checksum, denom); BOOST_CHECK_MESSAGE(checksumParsed == vChecksums[i], "checksum parse failed"); i++; } } -string strHexModulus = "0xc7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5"; +std::string strHexModulus = "0xc7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5"; BOOST_AUTO_TEST_CASE(bignum_setdecimal) { @@ -486,10 +485,10 @@ BOOST_AUTO_TEST_CASE(test_checkpoints) BOOST_AUTO_TEST_CASE(deterministic_tests) { SelectParams(CBaseChainParams::UNITTEST); - cout << "Testing deterministic minting\n"; + std::cout << "Testing deterministic minting\n"; uint256 seedMaster("3a1947364362e2e7c073b386869c89c905c0cf462448ffd6c2021bd03ce689f6"); - string strWalletFile = "unittestwallet.dat"; + std::string strWalletFile = "unittestwallet.dat"; CWalletDB walletdb(strWalletFile, "cr+"); CWallet wallet(strWalletFile); @@ -510,18 +509,18 @@ BOOST_AUTO_TEST_CASE(deterministic_tests) } int64_t nTotalTime = GetTimeMillis() - nTimeStart; - cout << "Total time:" << nTotalTime << "ms. Per Deterministic Mint:" << (nTotalTime/nTests) << "ms" << endl; + std::cout << "Total time:" << nTotalTime << "ms. Per Deterministic Mint:" << (nTotalTime/nTests) << "ms" << endl; - cout << "Checking that mints are valid" << endl; + std::cout << "Checking that mints are valid" << endl; CDataStream ss(SER_GETHASH, 0); for (PrivateCoin& coin : vCoins) { BOOST_CHECK_MESSAGE(coin.IsValid(), "Generated Mint is not valid"); ss << coin.getPublicCoin().getValue(); } - cout << "Checking that mints are deterministic: sha256 checksum="; + std::cout << "Checking that mints are deterministic: sha256 checksum="; uint256 hash = Hash(ss.begin(), ss.end()); - cout << hash.GetHex() << endl; + std::cout << hash.GetHex() << endl; BOOST_CHECK_MESSAGE(hash == uint256("c90c225f2cbdee5ef053b1f9f70053dd83724c58126d0e1b8425b88091d1f73f"), "minting determinism isn't as expected"); } diff --git a/src/test/zerocoin_transactions_tests.cpp b/src/test/zerocoin_transactions_tests.cpp index c5afaa4a63a9..724ac642769e 100644 --- a/src/test/zerocoin_transactions_tests.cpp +++ b/src/test/zerocoin_transactions_tests.cpp @@ -13,7 +13,6 @@ #include #include -using namespace libzerocoin; BOOST_AUTO_TEST_SUITE(zerocoin_transactions_tests) @@ -28,7 +27,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test) bool fFirstRun; cWallet.LoadWallet(fFirstRun); - cWallet.zphrTracker = unique_ptr(new CzPHRTracker(cWallet.strWalletFile)); + cWallet.zphrTracker = std::unique_ptr(new CzPHRTracker(cWallet.strWalletFile)); CMutableTransaction tx; CWalletTx* wtx = new CWalletTx(&cWallet, tx); bool fMintChange=true; diff --git a/src/timedata.cpp b/src/timedata.cpp index e8ba3b26b388..ddd30a78447f 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -10,9 +10,8 @@ #include "util.h" #include "utilstrencodings.h" -#include -using namespace std; + static CCriticalSection cs_nTimeOffset; static int64_t nTimeOffset = 0; @@ -44,7 +43,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) { LOCK(cs_nTimeOffset); // Ignore duplicates - static set setKnown; + static std::set setKnown; if (!setKnown.insert(ip).second) return; @@ -83,13 +82,13 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) if (!fDone) { // If nobody has a time different than ours but within 5 minutes of ours, give a warning bool fMatch = false; - BOOST_FOREACH (int64_t nOffset, vSorted) + for (int64_t nOffset : vSorted) if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true; if (!fMatch) { fDone = true; - string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Phore Core will not work properly."); + std::string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Phore Core will not work properly."); strMiscWarning = strMessage; LogPrintf("*** %s\n", strMessage); uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); @@ -97,7 +96,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) } } if (fDebug) { - BOOST_FOREACH (int64_t n, vSorted) + for (int64_t n : vSorted) LogPrintf("%+d ", n); LogPrintf("| "); } diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 36e5c5727121..eb180d3eca2e 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -18,7 +18,7 @@ #include #include #include -#include + #include #include #include @@ -264,7 +264,7 @@ static std::pair SplitTorReplyLine(const std::string &s } if (ptr < s.size()) ++ptr; // skip ' ' - return make_pair(type, s.substr(ptr)); + return std::make_pair(type, s.substr(ptr)); } /** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=".../control_auth_cookie"'. @@ -488,7 +488,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe { if (reply.code == 250) { LogPrint("tor", "tor: ADD_ONION successful\n"); - BOOST_FOREACH(const std::string &s, reply.lines) { + for (const std::string &s : reply.lines) { std::map m = ParseTorReplyMapping(s); std::map::iterator i; if ((i = m.find("ServiceID")) != m.end()) @@ -619,7 +619,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro * 250-AUTH METHODS=NULL * 250-AUTH METHODS=HASHEDPASSWORD */ - BOOST_FOREACH(const std::string &s, reply.lines) { + for (const std::string &s : reply.lines) { std::pair l = SplitTorReplyLine(s); if (l.first == "AUTH") { std::map m = ParseTorReplyMapping(l.second); @@ -636,7 +636,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro } } } - BOOST_FOREACH(const std::string &s, methods) { + for (const std::string &s : methods) { LogPrint("tor", "tor: Supported authentication method: %s\n", s); } // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD diff --git a/src/txdb.cpp b/src/txdb.cpp index 698a9d419787..a7cf2e96419f 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -17,15 +17,13 @@ #include -using namespace std; -using namespace libzerocoin; void static BatchWriteCoins(CLevelDBBatch& batch, const uint256& hash, const CCoins& coins) { if (coins.IsPruned()) - batch.Erase(make_pair('c', hash)); + batch.Erase(std::make_pair('c', hash)); else - batch.Write(make_pair('c', hash), coins); + batch.Write(std::make_pair('c', hash), coins); } void static BatchWriteHashBestChain(CLevelDBBatch& batch, const uint256& hash) @@ -39,12 +37,12 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get bool CCoinsViewDB::GetCoins(const uint256& txid, CCoins& coins) const { - return db.Read(make_pair('c', txid), coins); + return db.Read(std::make_pair('c', txid), coins); } bool CCoinsViewDB::HaveCoins(const uint256& txid) const { - return db.Exists(make_pair('c', txid)); + return db.Exists(std::make_pair('c', txid)); } uint256 CCoinsViewDB::GetBestBlock() const @@ -86,17 +84,17 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevel bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) { - return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); + return Write(std::make_pair('b', blockindex.GetBlockHash()), blockindex); } bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo& info) { - return Write(make_pair('f', nFile), info); + return Write(std::make_pair('f', nFile), info); } bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo& info) { - return Read(make_pair('f', nFile), info); + return Read(std::make_pair('f', nFile), info); } bool CBlockTreeDB::WriteLastBlockFile(int nFile) @@ -179,14 +177,14 @@ bool CCoinsViewDB::GetStats(CCoinsStats& stats) const bool CBlockTreeDB::ReadTxIndex(const uint256& txid, CDiskTxPos& pos) { - return Read(make_pair('t', txid), pos); + return Read(std::make_pair('t', txid), pos); } bool CBlockTreeDB::WriteTxIndex(const std::vector >& vect) { CLevelDBBatch batch; for (std::vector >::const_iterator it = vect.begin(); it != vect.end(); it++) - batch.Write(make_pair('t', it->first), it->second); + batch.Write(std::make_pair('t', it->first), it->second); return WriteBatch(batch); } @@ -202,7 +200,7 @@ bool CBlockTreeDB::ReadAddrIndex(uint160 addrid, std::vector &lis } CDataStream firstKey(SER_DISK, CLIENT_VERSION); - firstKey << make_pair('a', lookupid); + firstKey << std::make_pair('a', lookupid); pcursor->Seek(firstKey.str()); for(pcursor->Seek(firstKey.str()); pcursor->Valid(); pcursor->Next()) { @@ -234,7 +232,7 @@ bool CBlockTreeDB::AddAddrIndex(const std::vectorfirst; - batch.Write(make_pair(make_pair('a', (ss.GetHash()).GetLow64()), it->second), FLATDATA(foo)); + batch.Write(std::make_pair(std::make_pair('a', (ss.GetHash()).GetLow64()), it->second), FLATDATA(foo)); } return WriteBatch(batch, true); } @@ -268,7 +266,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() boost::scoped_ptr pcursor(NewIterator()); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); - ssKeySet << make_pair('b', uint256(0)); + ssKeySet << std::make_pair('b', uint256(0)); pcursor->Seek(ssKeySet.str()); // Load mapBlockIndex @@ -320,9 +318,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); } - // ppcoin: build setStakeSeen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); //populate accumulator checksum map in memory if(pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { @@ -349,10 +344,10 @@ CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB { } -bool CZerocoinDB::WriteCoinMint(const PublicCoin& pubCoin, const uint256& hashTx) +bool CZerocoinDB::WriteCoinMint(const libzerocoin::PublicCoin& pubCoin, const uint256& hashTx) { uint256 hash = GetPubCoinHash(pubCoin.getValue()); - return Write(make_pair('m', hash), hashTx, true); + return Write(std::make_pair('m', hash), hashTx, true); } bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx) @@ -362,13 +357,13 @@ bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx) bool CZerocoinDB::ReadCoinMint(const uint256& hashPubcoin, uint256& hashTx) { - return Read(make_pair('m', hashPubcoin), hashTx); + return Read(std::make_pair('m', hashPubcoin), hashTx); } bool CZerocoinDB::EraseCoinMint(const CBigNum& bnPubcoin) { uint256 hash = GetPubCoinHash(bnPubcoin); - return Erase(make_pair('m', hash)); + return Erase(std::make_pair('m', hash)); } bool CZerocoinDB::WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash) @@ -377,7 +372,7 @@ bool CZerocoinDB::WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash) ss << bnSerial; uint256 hash = Hash(ss.begin(), ss.end()); - return Write(make_pair('s', hash), txHash, true); + return Write(std::make_pair('s', hash), txHash, true); } bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash) @@ -386,12 +381,12 @@ bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash) ss << bnSerial; uint256 hash = Hash(ss.begin(), ss.end()); - return Read(make_pair('s', hash), txHash); + return Read(std::make_pair('s', hash), txHash); } bool CZerocoinDB::ReadCoinSpend(const uint256& hashSerial, uint256 &txHash) { - return Read(make_pair('s', hashSerial), txHash); + return Read(std::make_pair('s', hashSerial), txHash); } bool CZerocoinDB::EraseCoinSpend(const CBigNum& bnSerial) @@ -400,7 +395,7 @@ bool CZerocoinDB::EraseCoinSpend(const CBigNum& bnSerial) ss << bnSerial; uint256 hash = Hash(ss.begin(), ss.end()); - return Erase(make_pair('s', hash)); + return Erase(std::make_pair('s', hash)); } bool CZerocoinDB::WipeCoins(std::string strType) @@ -412,7 +407,7 @@ bool CZerocoinDB::WipeCoins(std::string strType) char type = (strType == "spends" ? 's' : 'm'); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); - ssKeySet << make_pair(type, uint256(0)); + ssKeySet << std::make_pair(type, uint256(0)); pcursor->Seek(ssKeySet.str()); // Load mapBlockIndex std::set setDelete; @@ -439,7 +434,7 @@ bool CZerocoinDB::WipeCoins(std::string strType) } for (auto& hash : setDelete) { - if (!Erase(make_pair(type, hash))) + if (!Erase(std::make_pair(type, hash))) LogPrintf("%s: error failed to delete %s\n", __func__, hash.GetHex()); } @@ -449,16 +444,16 @@ bool CZerocoinDB::WipeCoins(std::string strType) bool CZerocoinDB::WriteAccumulatorValue(const uint32_t& nChecksum, const CBigNum& bnValue) { LogPrint("zero","%s : checksum:%d val:%s\n", __func__, nChecksum, bnValue.GetHex()); - return Write(make_pair('2', nChecksum), bnValue); + return Write(std::make_pair('2', nChecksum), bnValue); } bool CZerocoinDB::ReadAccumulatorValue(const uint32_t& nChecksum, CBigNum& bnValue) { - return Read(make_pair('2', nChecksum), bnValue); + return Read(std::make_pair('2', nChecksum), bnValue); } bool CZerocoinDB::EraseAccumulatorValue(const uint32_t& nChecksum) { LogPrint("zero", "%s : checksum:%d\n", __func__, nChecksum); - return Erase(make_pair('2', nChecksum)); + return Erase(std::make_pair('2', nChecksum)); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 3b7e3c529beb..98fcb67e56ed 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -17,7 +17,6 @@ #include -using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _dPriority, unsigned int _nHeight, @@ -87,14 +86,14 @@ class CBlockAverage size_t FeeSamples() const { return feeSamples.size(); } size_t GetFeeSamples(std::vector& insertInto) const { - BOOST_FOREACH (const CFeeRate& f, feeSamples) + for (const CFeeRate& f : feeSamples) insertInto.push_back(f); return feeSamples.size(); } size_t PrioritySamples() const { return prioritySamples.size(); } size_t GetPrioritySamples(std::vector& insertInto) const { - BOOST_FOREACH (double d, prioritySamples) + for (double d : prioritySamples) insertInto.push_back(d); return prioritySamples.size(); } @@ -113,7 +112,7 @@ class CBlockAverage } static bool AreSane(const std::vector& vecFee, const CFeeRate& minRelayFee) { - BOOST_FOREACH (CFeeRate fee, vecFee) { + for (CFeeRate fee : vecFee) { if (!AreSane(fee, minRelayFee)) return false; } @@ -125,7 +124,7 @@ class CBlockAverage } static bool AreSane(const std::vector vecPriority) { - BOOST_FOREACH (double priority, vecPriority) { + for (double priority : vecPriority) { if (!AreSane(priority)) return false; } @@ -147,13 +146,13 @@ class CBlockAverage if (AreSane(vecFee, minRelayFee)) feeSamples.insert(feeSamples.end(), vecFee.begin(), vecFee.end()); else - throw runtime_error("Corrupt fee value in estimates file."); + throw std::runtime_error("Corrupt fee value in estimates file."); std::vector vecPriority; filein >> vecPriority; if (AreSane(vecPriority)) prioritySamples.insert(prioritySamples.end(), vecPriority.begin(), vecPriority.end()); else - throw runtime_error("Corrupt priority value in estimates file."); + throw std::runtime_error("Corrupt priority value in estimates file."); if (feeSamples.size() + prioritySamples.size() > 0) LogPrint("estimatefee", "Read %d fee samples and %d priority samples\n", feeSamples.size(), prioritySamples.size()); @@ -180,7 +179,7 @@ class CMinerPolicyEstimator void seenTxConfirm(const CFeeRate& feeRate, const CFeeRate& minRelayFee, double dPriority, int nBlocksAgo) { // Last entry records "everything else". - int nBlocksTruncated = min(nBlocksAgo, (int)history.size() - 1); + int nBlocksTruncated = std::min(nBlocksAgo, (int)history.size() - 1); assert(nBlocksTruncated >= 0); // We need to guess why the transaction was included in a block-- either @@ -224,7 +223,7 @@ class CMinerPolicyEstimator // to confirm. std::vector > entriesByConfirmations; entriesByConfirmations.resize(history.size()); - BOOST_FOREACH (const CTxMemPoolEntry& entry, entries) { + for (const CTxMemPoolEntry& entry : entries) { // How many blocks did it take for miners to include this transaction? int delta = nBlockHeight - entry.GetHeight(); if (delta <= 0) { @@ -244,7 +243,7 @@ class CMinerPolicyEstimator std::random_shuffle(e.begin(), e.end()); e.resize(10); } - BOOST_FOREACH (const CTxMemPoolEntry* entry, e) { + for (const CTxMemPoolEntry* entry : e) { // Fees are stored and reported as BTC-per-kb: CFeeRate feeRate(entry->GetFee(), entry->GetTxSize()); double dPriority = entry->GetPriority(entry->GetHeight()); // Want priority when it went IN @@ -299,7 +298,7 @@ class CMinerPolicyEstimator size_t nPrevSize = 0; for (int i = 0; i < nBlocksToConfirm; i++) nPrevSize += history.at(i).FeeSamples(); - size_t index = min(nPrevSize + nBucketSize / 2, sortedFeeSamples.size() - 1); + size_t index = std::min(nPrevSize + nBucketSize / 2, sortedFeeSamples.size() - 1); return sortedFeeSamples[index]; } double estimatePriority(int nBlocksToConfirm) @@ -328,7 +327,7 @@ class CMinerPolicyEstimator size_t nPrevSize = 0; for (int i = 0; i < nBlocksToConfirm; i++) nPrevSize += history.at(i).PrioritySamples(); - size_t index = min(nPrevSize + nBucketSize / 2, sortedPrioritySamples.size() - 1); + size_t index = std::min(nPrevSize + nBucketSize / 2, sortedPrioritySamples.size() - 1); return sortedPrioritySamples[index]; } @@ -336,7 +335,7 @@ class CMinerPolicyEstimator { fileout << nBestSeenHeight; fileout << history.size(); - BOOST_FOREACH (const CBlockAverage& entry, history) { + for (const CBlockAverage& entry : history) { entry.Write(fileout); } } @@ -348,7 +347,7 @@ class CMinerPolicyEstimator size_t numEntries; filein >> numEntries; if (numEntries <= 0 || numEntries > 10000) - throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entries."); + throw std::runtime_error("Corrupt estimates file. Must have between 1 and 10k entries."); std::vector fileHistory; @@ -467,7 +466,7 @@ void CTxMemPool::remove(const CTransaction& origTx, std::list& rem txToRemove.push_back(it->second.ptx->GetHash()); } } - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) mapNextTx.erase(txin.prevout); removed.push_back(tx); @@ -482,10 +481,10 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache* pcoins, unsigned in { // Remove transactions spending a coinbase which are now immature LOCK(cs); - list transactionsToRemove; + std::list transactionsToRemove; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->second.GetTx(); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) continue; @@ -497,8 +496,8 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache* pcoins, unsigned in } } } - BOOST_FOREACH (const CTransaction& tx, transactionsToRemove) { - list removed; + for (const CTransaction& tx : transactionsToRemove) { + std::list removed; remove(tx, removed, true); } } @@ -506,9 +505,9 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache* pcoins, unsigned in void CTxMemPool::removeConflicts(const CTransaction& tx, std::list& removed) { // Remove transactions which depend on inputs of tx, recursively - list result; + std::list result; LOCK(cs); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { std::map::iterator it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { const CTransaction& txConflict = *it->second.ptx; @@ -526,13 +525,13 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i { LOCK(cs); std::vector entries; - BOOST_FOREACH (const CTransaction& tx, vtx) { + for (const CTransaction& tx : vtx) { uint256 hash = tx.GetHash(); if (mapTx.count(hash)) entries.push_back(mapTx[hash]); } minerPolicyEstimator->seenBlock(entries, nBlockHeight, minRelayFee); - BOOST_FOREACH (const CTransaction& tx, vtx) { + for (const CTransaction& tx : vtx) { std::list dummy; remove(tx, dummy, false); removeConflicts(tx, conflicts); @@ -562,13 +561,13 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); LOCK(cs); - list waitingOnDependants; + std::list waitingOnDependants; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; checkTotal += it->second.GetTxSize(); const CTransaction& tx = it->second.GetTx(); bool fDependsWait = false; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { if (tx.IsZerocoinSpend()) continue; // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. @@ -615,7 +614,7 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const } for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { uint256 hash = it->second.ptx->GetHash(); - map::const_iterator it2 = mapTx.find(hash); + std::map::const_iterator it2 = mapTx.find(hash); const CTransaction& tx = it2->second.GetTx(); assert(it2 != mapTx.end()); assert(&tx == it->second.ptx); @@ -626,13 +625,13 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const assert(totalTxSize == checkTotal); } -void CTxMemPool::queryHashes(vector& vtxid) +void CTxMemPool::queryHashes(std::vector& vtxid) { vtxid.clear(); LOCK(cs); vtxid.reserve(mapTx.size()); - for (map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) + for (std::map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) vtxid.push_back((*mi).first); } @@ -641,14 +640,14 @@ void CTxMemPool::getTransactions(std::set& setTxid) setTxid.clear(); LOCK(cs); - for (map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) + for (std::map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) setTxid.insert((*mi).first); } bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const { LOCK(cs); - map::const_iterator i = mapTx.find(hash); + std::map::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) return false; result = i->second.GetTx(); return true; @@ -696,7 +695,7 @@ bool CTxMemPool::ReadFeeEstimates(CAutoFile& filein) return true; } -void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta) +void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta) { { LOCK(cs); diff --git a/src/uint256.h b/src/uint256.h index 80f316a1cb49..85799102cb7f 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -6,8 +6,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_UINT256_H -#define BITCOIN_UINT256_H +#ifndef PHORE_UINT256_H +#define PHORE_UINT256_H #include #include @@ -411,4 +411,4 @@ inline uint512 uint512S(const std::string& str) return rv; } -#endif // BITCOIN_UINT256_H +#endif // PHORE_UINT256_H diff --git a/src/uint512.h b/src/uint512.h index 58bf8c26f4b3..54d6f6c6fa23 100644 --- a/src/uint512.h +++ b/src/uint512.h @@ -3,7 +3,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#pragma once +#ifndef PHORE_UINT512_H +#define PHORE_UINT512_H + #include "arith_uint256.h" #include "uint256.h" @@ -40,3 +42,5 @@ inline uint512 uint512S(const char* str) rv.SetHex(str); return rv; } + +#endif // PHORE_UINT512_H diff --git a/src/univalue/gen/gen.cpp b/src/univalue/gen/gen.cpp index 17f361941d9e..d96d1a076db7 100644 --- a/src/univalue/gen/gen.cpp +++ b/src/univalue/gen/gen.cpp @@ -40,45 +40,45 @@ static void initJsonEscape() static void outputEscape() { - printf( "// Automatically generated file. Do not modify.\n" - "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" - "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" - "static const char *escapes[256] = {\n"); + printf( "// Automatically generated file. Do not modify.\n" + "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "static const char *escapes[256] = {\n"); - for (unsigned int i = 0; i < 256; i++) { - if (escapes[i].empty()) { - printf("\tNULL,\n"); - } else { - printf("\t\""); + for (unsigned int i = 0; i < 256; i++) { + if (escapes[i].empty()) { + printf("\tNULL,\n"); + } else { + printf("\t\""); - unsigned int si; - for (si = 0; si < escapes[i].size(); si++) { - char ch = escapes[i][si]; - switch (ch) { - case '"': - printf("\\\""); - break; - case '\\': - printf("\\\\"); - break; - default: - printf("%c", escapes[i][si]); - break; - } - } + unsigned int si; + for (si = 0; si < escapes[i].size(); si++) { + char ch = escapes[i][si]; + switch (ch) { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", escapes[i][si]); + break; + } + } - printf("\",\n"); - } - } + printf("\",\n"); + } + } - printf( "};\n" - "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); + printf( "};\n" + "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); } int main (int argc, char *argv[]) { - initJsonEscape(); - outputEscape(); - return 0; + initJsonEscape(); + outputEscape(); + return 0; } diff --git a/src/univalue/lib/univalue_escapes.h b/src/univalue/lib/univalue_escapes.h index 74596aab6d2c..9219979d302d 100644 --- a/src/univalue/lib/univalue_escapes.h +++ b/src/univalue/lib/univalue_escapes.h @@ -2,261 +2,261 @@ #ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H #define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H static const char *escapes[256] = { - "\\u0000", - "\\u0001", - "\\u0002", - "\\u0003", - "\\u0004", - "\\u0005", - "\\u0006", - "\\u0007", - "\\b", - "\\t", - "\\n", - "\\u000b", - "\\f", - "\\r", - "\\u000e", - "\\u000f", - "\\u0010", - "\\u0011", - "\\u0012", - "\\u0013", - "\\u0014", - "\\u0015", - "\\u0016", - "\\u0017", - "\\u0018", - "\\u0019", - "\\u001a", - "\\u001b", - "\\u001c", - "\\u001d", - "\\u001e", - "\\u001f", - NULL, - NULL, - "\\\"", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\\\", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\u007f", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "\\u0000", + "\\u0001", + "\\u0002", + "\\u0003", + "\\u0004", + "\\u0005", + "\\u0006", + "\\u0007", + "\\b", + "\\t", + "\\n", + "\\u000b", + "\\f", + "\\r", + "\\u000e", + "\\u000f", + "\\u0010", + "\\u0011", + "\\u0012", + "\\u0013", + "\\u0014", + "\\u0015", + "\\u0016", + "\\u0017", + "\\u0018", + "\\u0019", + "\\u001a", + "\\u001b", + "\\u001c", + "\\u001d", + "\\u001e", + "\\u001f", + NULL, + NULL, + "\\\"", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\\", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\u007f", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, }; #endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp index 2bd83238b486..a585cde23086 100644 --- a/src/univalue/lib/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -42,7 +42,7 @@ static const char *hatoui(const char *first, const char *last, return first; } -enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, +enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, const char *raw, const char *end) { tokenVal.clear(); @@ -255,7 +255,7 @@ bool UniValue::read(const char *raw, size_t size) clear(); uint32_t expectMask = 0; - vector stack; + std::vector stack; string tokenVal; unsigned int consumed; diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index f1f2e63b3d6f..24f1f605b9b9 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -20,16 +20,16 @@ try { \ (stmt); \ } catch (excMatch & e) { \ - } catch (...) { \ - assert(0); \ - } \ + } catch (...) { \ + assert(0); \ + } \ } #define BOOST_CHECK_NO_THROW(stmt) { \ try { \ (stmt); \ - } catch (...) { \ - assert(0); \ - } \ + } catch (...) { \ + assert(0); \ + } \ } BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) diff --git a/src/univalue/test/test_json.cpp b/src/univalue/test/test_json.cpp index 2943bae2b15e..92cfa34fd84c 100644 --- a/src/univalue/test/test_json.cpp +++ b/src/univalue/test/test_json.cpp @@ -13,7 +13,7 @@ using namespace std; int main (int argc, char *argv[]) { UniValue val; - if (val.read(string(istreambuf_iterator(cin), + if (val.read(std::string(istreambuf_iterator(cin), istreambuf_iterator()))) { cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; return 0; diff --git a/src/util.cpp b/src/util.cpp index 266d3038e0dc..df90f4249cab 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -14,7 +14,6 @@ #include "allocators.h" #include "chainparamsbase.h" #include "random.h" -#include "serialize.h" #include "sync.h" #include "utilstrencodings.h" #include "utiltime.h" @@ -83,7 +82,7 @@ #include // for startswith() and endswith() #include #include -#include + #include #include #include @@ -91,26 +90,12 @@ #include #include -// Work around clang compilation problem in Boost 1.46: -// /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup -// See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options -// http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION -namespace boost -{ -namespace program_options -{ -std::string to_internal(const std::string&); -} - -} // namespace boost - -using namespace std; // Phore only features // Masternode bool fMasterNode = false; -string strMasterNodePrivKey = ""; -string strMasterNodeAddr = ""; +std::string strMasterNodePrivKey = ""; +std::string strMasterNodeAddr = ""; bool fLiteMode = false; // SwiftX bool fEnableSwiftTX = true; @@ -121,23 +106,21 @@ int nZeromintPercentage = 10; int nPreferredDenom = 0; const int64_t AUTOMINT_DELAY = (60 * 5); // Wait at least 5 minutes until Automint starts -int nAnonymizePhoreAmount = 1000; -int nLiquidityProvider = 0; /** Spork enforcement enabled time */ int64_t enforceMasternodePaymentsTime = 4085657524; bool fSucessfullyLoaded = false; /** All denominations used by obfuscation */ std::vector obfuScationDenominations; -string strBudgetMode = ""; +std::string strBudgetMode = ""; -map mapArgs; -map > mapMultiArgs; +std::map mapArgs; +std::map > mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugLog = true; bool fDaemon = false; bool fServer = false; -string strMiscWarning; +std::string strMiscWarning; bool fLogTimestamps = false; bool fLogIPs = false; volatile bool fReopenDebugLog = false; @@ -236,28 +219,28 @@ bool LogAcceptCategory(const char* category) // This helps prevent issues debugging global destructors, // where mapMultiArgs might be deleted before another // global destructor calls LogPrint() - static boost::thread_specific_ptr > ptrCategory; + static boost::thread_specific_ptr > ptrCategory; if (ptrCategory.get() == NULL) { - const vector& categories = mapMultiArgs["-debug"]; - ptrCategory.reset(new set(categories.begin(), categories.end())); + const std::vector& categories = mapMultiArgs["-debug"]; + ptrCategory.reset(new std::set(categories.begin(), categories.end())); // thread_specific_ptr automatically deletes the set when the thread ends. // "phore" is a composite category enabling all Phore-related debug output - if (ptrCategory->count(string("phore"))) { - ptrCategory->insert(string("obfuscation")); - ptrCategory->insert(string("swiftx")); - ptrCategory->insert(string("masternode")); - ptrCategory->insert(string("mnpayments")); - ptrCategory->insert(string("zero")); - ptrCategory->insert(string("mnbudget")); - ptrCategory->insert(string("precompute")); - ptrCategory->insert(string("staking")); + if (ptrCategory->count(std::string("phore"))) { + ptrCategory->insert(std::string("obfuscation")); + ptrCategory->insert(std::string("swiftx")); + ptrCategory->insert(std::string("masternode")); + ptrCategory->insert(std::string("mnpayments")); + ptrCategory->insert(std::string("zero")); + ptrCategory->insert(std::string("mnbudget")); + ptrCategory->insert(std::string("precompute")); + ptrCategory->insert(std::string("staking")); } } - const set& setCategories = *ptrCategory.get(); + const std::set& setCategories = *ptrCategory.get(); // if not debugging everything and not debugging specific category, LogPrint does nothing. - if (setCategories.count(string("")) == 0 && - setCategories.count(string(category)) == 0) + if (setCategories.count(std::string("")) == 0 && + setCategories.count(std::string(category)) == 0) return false; } return true; @@ -643,8 +626,8 @@ boost::filesystem::path GetMasternodeConfigFile() return pathConfigFile; } -void ReadConfigFile(map& mapSettingsRet, - map >& mapMultiSettingsRet) +void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet) { boost::filesystem::ifstream streamConfig(GetConfigFile()); if (!streamConfig.good()) { @@ -655,13 +638,13 @@ void ReadConfigFile(map& mapSettingsRet, return; // Nothing to read, so just return } - set setOptions; + std::set setOptions; setOptions.insert("*"); for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { // Don't overwrite existing settings so command line settings override phore.conf - string strKey = string("-") + it->string_key; - string strValue = it->value[0]; + std::string strKey = std::string("-") + it->string_key; + std::string strValue = it->value[0]; InterpretNegativeSetting(strKey, strValue); if (mapSettingsRet.count(strKey) == 0) mapSettingsRet[strKey] = strValue; @@ -824,12 +807,12 @@ void ShrinkDebugFile() // Restart the file with some of the end std::vector vch(200000, 0); fseek(file, -((long)vch.size()), SEEK_END); - int nBytes = fread(begin_ptr(vch), 1, vch.size(), file); + int nBytes = fread(vch.data(), 1, vch.size(), file); fclose(file); file = fopen(pathLog.string().c_str(), "w"); if (file) { - fwrite(begin_ptr(vch), 1, nBytes, file); + fwrite(vch.data(), 1, nBytes, file); fclose(file); } } else if (file != NULL) diff --git a/src/util.h b/src/util.h index e12d9fb975f7..d45091469ebb 100644 --- a/src/util.h +++ b/src/util.h @@ -29,6 +29,7 @@ #include #include +#include // for boost::thread_interrupted // Debugging macros // Uncomment the following line to enable debugging messages @@ -49,8 +50,6 @@ extern int nSwiftTXDepth; extern int nZeromintPercentage; extern const int64_t AUTOMINT_DELAY; extern int nPreferredDenom; -extern int nAnonymizePhoreAmount; -extern int nLiquidityProvider; extern bool fEnableZeromint; extern int64_t enforceMasternodePaymentsTime; extern std::string strMasterNodeAddr; @@ -80,6 +79,9 @@ int LogPrintStr(const std::string& str); #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) +/** Get format string from VA_ARGS for error reporting */ +template std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } + /** * When we switch to C++11, this can be switched to variadic templates instead * of this macro-based construction (see tinyformat.h). @@ -90,13 +92,25 @@ int LogPrintStr(const std::string& str); static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \ { \ if (!LogAcceptCategory(category)) return 0; \ - return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ + } catch (std::runtime_error &e) { \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ + } \ + return LogPrintStr(_log_msg_); \ } \ /** Log error and return false */ \ template \ static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ { \ - LogPrintStr(std::string("ERROR: ") + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ + } catch (std::runtime_error &e) { \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ + } \ + LogPrintStr(std::string("ERROR: ") + _log_msg_ + "\n"); \ return false; \ } @@ -130,6 +144,7 @@ bool TryCreateDirectory(const boost::filesystem::path& p); boost::filesystem::path GetDefaultDataDir(); bool CheckIfWalletDatExists(bool fNetSpecific = true); const boost::filesystem::path& GetDataDir(bool fNetSpecific = true); +void ClearDatadirCache(); boost::filesystem::path GetConfigFile(); boost::filesystem::path GetMasternodeConfigFile(); #ifndef WIN32 diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index e241b0fb6250..7276a9018f86 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -9,16 +9,14 @@ #include "tinyformat.h" #include "utilstrencodings.h" -using namespace std; - -string FormatMoney(const CAmount& n, bool fPlus) +std::string FormatMoney(const CAmount& n, bool fPlus) { // Note: not using straight sprintf here because we do NOT want // localized number formatting. int64_t n_abs = (n > 0 ? n : -n); int64_t quotient = n_abs / COIN; int64_t remainder = n_abs % COIN; - string str = strprintf("%d.%08d", quotient, remainder); + std::string str = strprintf("%d.%08d", quotient, remainder); // Right-trim excess zeros before the decimal point: int nTrim = 0; @@ -35,14 +33,14 @@ string FormatMoney(const CAmount& n, bool fPlus) } -bool ParseMoney(const string& str, CAmount& nRet) +bool ParseMoney(const std::string& str, CAmount& nRet) { return ParseMoney(str.c_str(), nRet); } bool ParseMoney(const char* pszIn, CAmount& nRet) { - string strWhole; + std::string strWhole; int64_t nUnits = 0; const char* p = pszIn; while (isspace(*p)) diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 8df7c46b0d3d..cf0b9c3e2f1d 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -19,23 +19,53 @@ #include -using namespace std; +static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -string SanitizeString(const string& str) +static const std::string SAFE_CHARS[] = { - /** - * safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything - * even possibly remotely dangerous like & or > - */ - static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_-/:?@()"); - string strResult; - for (std::string::size_type i = 0; i < str.size(); i++) { - if (safeChars.find(str[i]) != std::string::npos) + CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT + CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT + CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME +}; + +std::string SanitizeString(const std::string& str, int rule) +{ + std::string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (SAFE_CHARS[rule].find(str[i]) != std::string::npos) strResult.push_back(str[i]); } return strResult; } +bool validateURL(std::string strURL, std::string& strErr, unsigned int maxSize) { + + // Check URL size + if (strURL.size() > maxSize) { + strErr = strprintf("Invalid URL: %d exceeds limit of %d characters.", strURL.size(), maxSize); + return false; + } + + std::vector reqPre; + + // Required initial strings; URL must contain one + reqPre.push_back("http://"); + reqPre.push_back("https://"); + + // check fronts + bool found = false; + for (int i=0; i < reqPre.size() && !found; i++) { + if (strURL.find(reqPre[i]) == 0) found = true; + } + if ((!found) && (reqPre.size() > 0)) { + strErr = "Invalid URL, check scheme (e.g. https://)"; + return false; + } + + return true; +} + const signed char p_util_hexdigit[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -61,7 +91,7 @@ signed char HexDigit(char c) return p_util_hexdigit[(unsigned char)c]; } -bool IsHex(const string& str) +bool IsHex(const std::string& str) { for (std::string::const_iterator it(str.begin()); it != str.end(); ++it) { if (HexDigit(*it) < 0) @@ -70,10 +100,10 @@ bool IsHex(const string& str) return (str.size() > 0) && (str.size() % 2 == 0); } -vector ParseHex(const char* psz) +std::vector ParseHex(const char* psz) { // convert hex dump to vector - vector vch; + std::vector vch; while (true) { while (isspace(*psz)) psz++; @@ -90,16 +120,16 @@ vector ParseHex(const char* psz) return vch; } -vector ParseHex(const string& str) +std::vector ParseHex(const std::string& str) { return ParseHex(str.c_str()); } -string EncodeBase64(const unsigned char* pch, size_t len) +std::string EncodeBase64(const unsigned char* pch, size_t len) { static const char* pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - string strRet = ""; + std::string strRet = ""; strRet.reserve((len + 2) / 3 * 4); int mode = 0, left = 0; @@ -138,12 +168,12 @@ string EncodeBase64(const unsigned char* pch, size_t len) return strRet; } -string EncodeBase64(const string& str) +std::string EncodeBase64(const std::string& str) { return EncodeBase64((const unsigned char*)str.c_str(), str.size()); } -vector DecodeBase64(const char* p, bool* pfInvalid) +std::vector DecodeBase64(const char* p, bool* pfInvalid) { static const int decode64_table[256] = { @@ -164,7 +194,7 @@ vector DecodeBase64(const char* p, bool* pfInvalid) if (pfInvalid) *pfInvalid = false; - vector vchRet; + std::vector vchRet; vchRet.reserve(strlen(p) * 3 / 4); int mode = 0; @@ -222,10 +252,10 @@ vector DecodeBase64(const char* p, bool* pfInvalid) return vchRet; } -string DecodeBase64(const string& str) +std::string DecodeBase64(const std::string& str) { - vector vchRet = DecodeBase64(str.c_str()); - return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); + std::vector vchRet = DecodeBase64(str.c_str()); + return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size()); } // Base64 decoding with secure memory allocation @@ -242,7 +272,7 @@ SecureString DecodeBase64Secure(const SecureString& input) // Prepare buffer to receive decoded data if (input.size() % 4 != 0) { - throw runtime_error("Input length should be a multiple of 4"); + throw std::runtime_error("Input length should be a multiple of 4"); } size_t nMaxLen = input.size() / 4 * 3; // upper bound, guaranteed divisible by 4 output.resize(nMaxLen); @@ -284,11 +314,11 @@ SecureString EncodeBase64Secure(const SecureString& input) return output; } -string EncodeBase32(const unsigned char* pch, size_t len) +std::string EncodeBase32(const unsigned char* pch, size_t len) { static const char* pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - string strRet = ""; + std::string strRet = ""; strRet.reserve((len + 4) / 5 * 8); int mode = 0, left = 0; @@ -340,12 +370,12 @@ string EncodeBase32(const unsigned char* pch, size_t len) return strRet; } -string EncodeBase32(const string& str) +std::string EncodeBase32(const std::string& str) { return EncodeBase32((const unsigned char*)str.c_str(), str.size()); } -vector DecodeBase32(const char* p, bool* pfInvalid) +std::vector DecodeBase32(const char* p, bool* pfInvalid) { static const int decode32_table[256] = { @@ -366,7 +396,7 @@ vector DecodeBase32(const char* p, bool* pfInvalid) if (pfInvalid) *pfInvalid = false; - vector vchRet; + std::vector vchRet; vchRet.reserve((strlen(p)) * 5 / 8); int mode = 0; @@ -458,10 +488,10 @@ vector DecodeBase32(const char* p, bool* pfInvalid) return vchRet; } -string DecodeBase32(const string& str) +std::string DecodeBase32(const std::string& str) { - vector vchRet = DecodeBase32(str.c_str()); - return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); + std::vector vchRet = DecodeBase32(str.c_str()); + return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size()); } static bool ParsePrechecks(const std::string& str) diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 7a36096c0879..d7f1a599fdeb 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -23,7 +23,32 @@ /** This is needed because the foreach macro can't get over the comma in pair */ #define PAIRTYPE(t1, t2) std::pair -std::string SanitizeString(const std::string& str); +/** Used by SanitizeString() */ +enum SafeChars +{ + SAFE_CHARS_DEFAULT, //!< The full set of allowed chars + SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset + SAFE_CHARS_FILENAME, //!< Chars allowed in filenames +}; + +/** +* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email +* addresses, but avoid anything even possibly remotely dangerous like & or > +* @param[in] str The string to sanitize +* @param[in] rule The set of safe chars to choose (default: least restrictive) +* @return A new string without unsafe chars +*/ +std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT); + +/** +* Check URL format for conformance for validity to a defined pattern +* @param[in] strURL The string to be processed for validity +* @param[in] stdErr A string that will be loaded with any validation error message +* @param[in] maxSize An unsigned int, defaulted to 64, to restrict the length +* @return A bool, true if valid, false if not (reason in stdErr) +*/ +bool validateURL(std::string strURL, std::string& strErr, unsigned int maxSize = 64); + std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); signed char HexDigit(char c); @@ -123,13 +148,6 @@ bool TimingResistantEqual(const T& a, const T& b) return accumulator == 0; } -/** Parse number as fixed point according to JSON number syntax. - * See http://json.org/number.gif - * @returns true on success, false on error. - * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger. - */ -bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); - /** Convert from one power-of-2 number base to another. */ template bool ConvertBits(O& out, I it, I end) { diff --git a/src/utiltime.cpp b/src/utiltime.cpp index ebdf00c328aa..494ac2a27282 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -13,7 +13,6 @@ #include #include -using namespace std; static int64_t nMockTime = 0; //! For unit testing diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 4290c9a5637e..feff14300372 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -10,7 +10,7 @@ #include "init.h" #include "uint256.h" -#include + #include #include #include "wallet.h" @@ -240,10 +240,10 @@ bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, con if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (unsigned char*)(&sPlaintext[0]) + nPLen, &nFLen); EVP_CIPHER_CTX_cleanup(ctx); #else - if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, (const unsigned char*)&sKey[0], (const unsigned char*)&sIV[0]); if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, (const unsigned char*)&sKey[0], (const unsigned char*)&sIV[0]); - if (fOk) fOk = EVP_DecryptUpdate(&ctx, (unsigned char*)&sPlaintext[0], &nPLen, (const unsigned char*)&sCiphertext[0], nLen); if (fOk) fOk = EVP_DecryptUpdate(&ctx, (unsigned char*)&sPlaintext[0], &nPLen, (const unsigned char*)&sCiphertext[0], nLen); - if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (unsigned char*)(&sPlaintext[0]) + nPLen, &nFLen); if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (unsigned char*)(&sPlaintext[0]) + nPLen, &nFLen); - EVP_CIPHER_CTX_cleanup(&ctx); EVP_CIPHER_CTX_cleanup(&ctx); + if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, (const unsigned char*)&sKey[0], (const unsigned char*)&sIV[0]); if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, (const unsigned char*)&sKey[0], (const unsigned char*)&sIV[0]); + if (fOk) fOk = EVP_DecryptUpdate(&ctx, (unsigned char*)&sPlaintext[0], &nPLen, (const unsigned char*)&sCiphertext[0], nLen); if (fOk) fOk = EVP_DecryptUpdate(&ctx, (unsigned char*)&sPlaintext[0], &nPLen, (const unsigned char*)&sCiphertext[0], nLen); + if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (unsigned char*)(&sPlaintext[0]) + nPLen, &nFLen); if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (unsigned char*)(&sPlaintext[0]) + nPLen, &nFLen); + EVP_CIPHER_CTX_cleanup(&ctx); EVP_CIPHER_CTX_cleanup(&ctx); #endif if (!fOk) return false; @@ -524,7 +524,7 @@ bool CCryptoKeyStore::AddCryptedKey(const CPubKey& vchPubKey, const std::vector< if (!SetCrypted()) return false; - mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); + mapCryptedKeys[vchPubKey.GetID()] = std::make_pair(vchPubKey, vchCryptedSecret); ImplicitlyLearnRelatedKeyScripts(vchPubKey); } return true; @@ -577,7 +577,7 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) return false; fUseCrypto = true; - BOOST_FOREACH (KeyMap::value_type& mKey, mapKeys) { + for (KeyMap::value_type& mKey : mapKeys) { const CKey& key = mKey.second; CPubKey vchPubKey = key.GetPubKey(); CKeyingMaterial vchSecret(key.begin(), key.end()); @@ -595,14 +595,14 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) bool CCryptoKeyStore::AddDeterministicSeed(const uint256& seed) { CWalletDB db(pwalletMain->strWalletFile); - string strErr; + std::string strErr; uint256 hashSeed = Hash(seed.begin(), seed.end()); if(IsCrypted()) { if (!IsLocked()) { //if we have password CKeyingMaterial kmSeed(seed.begin(), seed.end()); - vector vchSeedSecret; + std::vector vchSeedSecret; //attempt encrypt if (EncryptSecret(vMasterKey, kmSeed, hashSeed, vchSeedSecret)) { @@ -629,11 +629,11 @@ bool CCryptoKeyStore::GetDeterministicSeed(const uint256& hashSeed, uint256& see { CWalletDB db(pwalletMain->strWalletFile); - string strErr; + std::string strErr; if (IsCrypted()) { if(!IsLocked()) { //if we have password - vector vchCryptedSeed; + std::vector vchCryptedSeed; //read encrypted seed if (db.ReadZPHRSeed(hashSeed, vchCryptedSeed)) { uint256 seedRetrieved = uint256(ReverseEndianString(HexStr(vchCryptedSeed))); @@ -654,7 +654,7 @@ bool CCryptoKeyStore::GetDeterministicSeed(const uint256& hashSeed, uint256& see } else { strErr = "read seed from wallet"; } } else { strErr = "read seed; wallet is locked"; } } else { - vector vchSeed; + std::vector vchSeed; // wallet not crypted if (db.ReadZPHRSeed(hashSeed, vchSeed)) { seedOut = uint256(ReverseEndianString(HexStr(vchSeed))); diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 960dc454200e..640be8e554b7 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -21,9 +21,6 @@ #include #include -using namespace std; -using namespace boost; - unsigned int nWalletDBUpdated; @@ -40,22 +37,31 @@ void CDBEnv::EnvShutdown() return; fDbEnvInit = false; - int ret = dbenv.close(0); + int ret = dbenv->close(0); if (ret != 0) LogPrintf("CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) DbEnv(0).remove(strPath.c_str(), 0); } -CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) +void CDBEnv::Reset() { + delete dbenv; + dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS); fDbEnvInit = false; fMockDb = false; } +CDBEnv::CDBEnv() : dbenv(NULL) +{ + Reset(); +} + CDBEnv::~CDBEnv() { EnvShutdown(); + delete dbenv; + dbenv = NULL; } void CDBEnv::Close() @@ -80,17 +86,17 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) if (GetBoolArg("-privdb", true)) nEnvFlags |= DB_PRIVATE; - dbenv.set_lg_dir(pathLogDir.string().c_str()); - dbenv.set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet - dbenv.set_lg_bsize(0x10000); - dbenv.set_lg_max(1048576); - dbenv.set_lk_max_locks(40000); - dbenv.set_lk_max_objects(40000); - dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); - dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv.open(strPath.c_str(), + dbenv->set_lg_dir(pathLogDir.string().c_str()); + dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet + dbenv->set_lg_bsize(0x10000); + dbenv->set_lg_max(1048576); + dbenv->set_lk_max_locks(40000); + dbenv->set_lk_max_objects(40000); + dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv->set_flags(DB_AUTO_COMMIT, 1); + dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1); + dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1); + int ret = dbenv->open(strPath.c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -111,20 +117,20 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) void CDBEnv::MakeMock() { if (fDbEnvInit) - throw runtime_error("CDBEnv::MakeMock : Already initialized"); + throw std::runtime_error("CDBEnv::MakeMock : Already initialized"); boost::this_thread::interruption_point(); LogPrint("db", "CDBEnv::MakeMock\n"); - dbenv.set_cachesize(1, 0, 1); - dbenv.set_lg_bsize(10485760 * 4); - dbenv.set_lg_max(10485760); - dbenv.set_lk_max_locks(10000); - dbenv.set_lk_max_objects(10000); - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); - int ret = dbenv.open(NULL, + dbenv->set_cachesize(1, 0, 1); + dbenv->set_lg_bsize(10485760 * 4); + dbenv->set_lg_max(10485760); + dbenv->set_lk_max_locks(10000); + dbenv->set_lk_max_objects(10000); + dbenv->set_flags(DB_AUTO_COMMIT, 1); + dbenv->log_set_config(DB_LOG_IN_MEMORY, 1); + int ret = dbenv->open(NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -134,7 +140,7 @@ void CDBEnv::MakeMock() DB_PRIVATE, S_IRUSR | S_IWUSR); if (ret > 0) - throw runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret)); + throw std::runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret)); fDbEnvInit = true; fMockDb = true; @@ -145,7 +151,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDB LOCK(cs_db); assert(mapFileUseCount.count(strFile) == 0); - Db db(&dbenv, 0); + Db db(dbenv, 0); int result = db.verify(strFile.c_str(), NULL, NULL, 0); if (result == 0) return VERIFY_OK; @@ -166,9 +172,9 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vectortxn_checkpoint(0, 0, 0); if (fMockDb) return; - dbenv.lsn_reset(strFile.c_str(), 0); + dbenv->lsn_reset(strFile.c_str(), 0); } @@ -231,20 +237,20 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, int nSerVersion) : { LOCK(bitdb.cs_db); if (!bitdb.Open(GetDataDir())) - throw runtime_error("CDB : Failed to open database environment."); + throw std::runtime_error("CDB : Failed to open database environment."); strFile = strFilename; ++bitdb.mapFileUseCount[strFile]; pdb = bitdb.mapDb[strFile]; if (pdb == NULL) { - pdb = new Db(&bitdb.dbenv, 0); + pdb = new Db(bitdb.dbenv, 0); bool fMockDb = bitdb.IsMock(); if (fMockDb) { DbMpoolFile* mpf = pdb->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); if (ret != 0) - throw runtime_error(strprintf("CDB : Failed to configure for no temp file backing for database %s", strFile)); + throw std::runtime_error(strprintf("CDB : Failed to configure for no temp file backing for database %s", strFile)); } ret = pdb->open(NULL, // Txn pointer @@ -259,10 +265,10 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, int nSerVersion) : pdb = NULL; --bitdb.mapFileUseCount[strFile]; strFile = ""; - throw runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, strFile)); + throw std::runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, strFile)); } - if (fCreate && !Exists(string("version"))) { + if (fCreate && !Exists(std::string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; WriteVersion(CLIENT_VERSION); @@ -284,7 +290,7 @@ void CDB::Flush() if (fReadOnly) nMinutes = 1; - bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); + bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); } void CDB::Close() @@ -304,7 +310,7 @@ void CDB::Close() } } -void CDBEnv::CloseDb(const string& strFile) +void CDBEnv::CloseDb(const std::string& strFile) { { LOCK(cs_db); @@ -318,16 +324,16 @@ void CDBEnv::CloseDb(const string& strFile) } } -bool CDBEnv::RemoveDb(const string& strFile) +bool CDBEnv::RemoveDb(const std::string& strFile) { this->CloseDb(strFile); LOCK(cs_db); - int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); + int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); return (rc == 0); } -bool CDB::Rewrite(const string& strFile, const char* pszSkip) +bool CDB::Rewrite(const std::string& strFile, const char* pszSkip) { while (true) { { @@ -340,10 +346,10 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) bool fSuccess = true; LogPrintf("CDB::Rewrite : Rewriting %s...\n", strFile); - string strFileRes = strFile + ".rewrite"; + std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); - Db* pdbCopy = new Db(&bitdb.dbenv, 0); + Db* pdbCopy = new Db(bitdb.dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename @@ -393,10 +399,10 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) } } if (fSuccess) { - Db dbA(&bitdb.dbenv, 0); + Db dbA(bitdb.dbenv, 0); if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; - Db dbB(&bitdb.dbenv, 0); + Db dbB(bitdb.dbenv, 0); if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) fSuccess = false; } @@ -420,20 +426,20 @@ void CDBEnv::Flush(bool fShutdown) return; { LOCK(cs_db); - map::iterator mi = mapFileUseCount.begin(); + std::map::iterator mi = mapFileUseCount.begin(); while (mi != mapFileUseCount.end()) { - string strFile = (*mi).first; + std::string strFile = (*mi).first; int nRefCount = (*mi).second; LogPrint("db", "CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount); if (nRefCount == 0) { // Move log data to the dat file CloseDb(strFile); - LogPrint("db", "CDBEnv::Flush : %s checkpoint\n", strFile); - dbenv.txn_checkpoint(0, 0, 0); - LogPrint("db", "CDBEnv::Flush : %s detach\n", strFile); + LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile); + dbenv->txn_checkpoint(0, 0, 0); + LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile); if (!fMockDb) - dbenv.lsn_reset(strFile.c_str(), 0); - LogPrint("db", "CDBEnv::Flush : %s closed\n", strFile); + dbenv->lsn_reset(strFile.c_str(), 0); + LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile); mapFileUseCount.erase(mi++); } else mi++; @@ -442,7 +448,7 @@ void CDBEnv::Flush(bool fShutdown) if (fShutdown) { char** listp; if (mapFileUseCount.empty()) { - dbenv.log_archive(&listp, DB_ARCH_REMOVE); + dbenv->log_archive(&listp, DB_ARCH_REMOVE); Close(); if (!fMockDb) boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database"); diff --git a/src/wallet/db.h b/src/wallet/db.h index 4fdd6b0929cf..7048da49be68 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -43,12 +43,14 @@ class CDBEnv public: mutable CCriticalSection cs_db; - DbEnv dbenv; + DbEnv *dbenv; std::map mapFileUseCount; std::map mapDb; CDBEnv(); ~CDBEnv(); + void Reset(); + void MakeMock(); bool IsMock() { return fMockDb; } @@ -83,7 +85,7 @@ class CDBEnv DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) { DbTxn* ptxn = NULL; - int ret = dbenv.txn_begin(NULL, &ptxn, flags); + int ret = dbenv->txn_begin(NULL, &ptxn, flags); if (!ptxn || ret != 0) return NULL; return ptxn; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 8b39ba213e4a..13bb773613fe 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -7,7 +7,7 @@ #include "bip38.h" #include "init.h" #include "main.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "script/script.h" #include "script/standard.h" #include "sync.h" @@ -27,8 +27,6 @@ #include -using namespace std; - void EnsureWalletIsUnlocked(bool fAllowAnonOnly); std::string static EncodeDumpTime(int64_t nTime) @@ -53,7 +51,7 @@ int64_t static DecodeDumpTime(const std::string& str) std::string static EncodeDumpString(const std::string& str) { std::stringstream ret; - BOOST_FOREACH (unsigned char c, str) { + for (unsigned char c : str) { if (c <= 32 || c >= 128 || c == '%') { ret << '%' << HexStr(&c, &c + 1); } else { @@ -81,7 +79,7 @@ std::string DecodeDumpString(const std::string& str) UniValue importprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "importprivkey \"phoreprivkey\" ( \"label\" rescan )\n" "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" "\nArguments:\n" @@ -100,8 +98,8 @@ UniValue importprivkey(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - string strSecret = params[0].get_str(); - string strLabel = ""; + std::string strSecret = params[0].get_str(); + std::string strLabel = ""; if (params.size() > 1) strLabel = params[1].get_str(); @@ -149,8 +147,8 @@ UniValue importprivkey(const UniValue& params, bool fHelp) return NullUniValue; } -void ImportAddress(const CTxDestination& dest, const string& strLabel); -void ImportScript(const CScript& script, const string& strLabel, bool isRedeemScript) +void ImportAddress(const CTxDestination& dest, const std::string& strLabel); +void ImportScript(const CScript& script, const std::string& strLabel, bool isRedeemScript) { if (!isRedeemScript && ::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); @@ -173,7 +171,7 @@ void ImportScript(const CScript& script, const string& strLabel, bool isRedeemSc } } -void ImportAddress(const CTxDestination& dest, const string& strLabel) +void ImportAddress(const CTxDestination& dest, const std::string& strLabel) { CScript script = GetScriptForDestination(dest); ImportScript(script, strLabel, false); @@ -184,7 +182,7 @@ void ImportAddress(const CTxDestination& dest, const string& strLabel) UniValue importaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "importaddress \"address\" ( \"label\" rescan p2sh )\n" "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" @@ -206,7 +204,7 @@ UniValue importaddress(const UniValue& params, bool fHelp) ); - string strLabel = ""; + std::string strLabel = ""; if (params.size() > 1) strLabel = params[1].get_str(); @@ -245,7 +243,7 @@ UniValue importaddress(const UniValue& params, bool fHelp) UniValue importpubkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "importpubkey \"pubkey\" ( \"label\" rescan )\n" "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" @@ -263,7 +261,7 @@ UniValue importpubkey(const UniValue& params, bool fHelp) ); - string strLabel = ""; + std::string strLabel = ""; if (params.size() > 1) strLabel = params[1].get_str(); @@ -296,7 +294,7 @@ UniValue importpubkey(const UniValue& params, bool fHelp) UniValue importwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "importwallet \"filename\"\n" "\nImports keys from a wallet dump file (see dumpallprivatekeys).\n" "\nArguments:\n" @@ -311,7 +309,7 @@ UniValue importwallet(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - ifstream file; + std::ifstream file; file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -394,7 +392,7 @@ UniValue importwallet(const UniValue& params, bool fHelp) UniValue dumpprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpprivkey \"phoreaddress\"\n" "\nReveals the private key corresponding to 'phoreaddress'.\n" "Then the importprivkey can be used with this output\n" @@ -412,7 +410,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - string strAddress = params[0].get_str(); + std::string strAddress = params[0].get_str(); if (!IsValidDestinationString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Phore address"); const CTxDestination dest = DecodeDestination(strAddress); @@ -432,7 +430,7 @@ UniValue dumphdinfo(const UniValue& params, bool fHelp) return NullUniValue; if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "dumphdinfo\n" "Returns an object containing sensitive private info about this HD wallet.\n" "\nResult:\n" @@ -472,7 +470,7 @@ UniValue dumphdinfo(const UniValue& params, bool fHelp) UniValue dumpwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpwallet \"filename\"\n" "\nDumps all wallet keys in a human-readable format.\n" + HelpRequiringPassphrase() + "\n" @@ -487,7 +485,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); boost::filesystem::path filepath = params[0].get_str().c_str(); filepath = boost::filesystem::absolute(filepath); - ofstream file; + std::ofstream file; file.open(params[0].get_str().c_str()); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -570,7 +568,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) UniValue dumpallprivatekeys(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpallprivatekeys \"filename\"\n" "\nDumps all wallet private keys in an unencrypted, human-readable format.\n" "\nSCAM WARNING: If anyone asks you to run this command and send them the file,\n" @@ -586,7 +584,7 @@ UniValue dumpallprivatekeys(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - ofstream file; + std::ofstream file; file.open(params[0].get_str().c_str()); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet private key dump file"); @@ -635,7 +633,7 @@ UniValue dumpallprivatekeys(const UniValue& params, bool fHelp) UniValue bip38encrypt(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "bip38encrypt \"phoreaddress\"\n" "\nEncrypts a private key corresponding to 'phoreaddress'.\n" "\nArguments:\n" @@ -649,8 +647,8 @@ UniValue bip38encrypt(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - string strAddress = params[0].get_str(); - string strPassphrase = params[1].get_str(); + std::string strAddress = params[0].get_str(); + std::string strPassphrase = params[1].get_str(); if (!IsValidDestinationString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Phore address"); @@ -663,7 +661,7 @@ UniValue bip38encrypt(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); uint256 privKey = vchSecret.GetPrivKey_256(); - string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey, vchSecret.IsCompressed()); + std::string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey, vchSecret.IsCompressed()); UniValue result(UniValue::VOBJ); result.push_back(Pair("Addess", strAddress)); @@ -675,7 +673,7 @@ UniValue bip38encrypt(const UniValue& params, bool fHelp) UniValue bip38decrypt(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "bip38decrypt \"phoreaddress\"\n" "\nDecrypts and then imports password protected private key.\n" "\nArguments:\n" @@ -691,8 +689,8 @@ UniValue bip38decrypt(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); /** Collect private key and passphrase **/ - string strKey = params[0].get_str(); - string strPassphrase = params[1].get_str(); + std::string strKey = params[0].get_str(); + std::string strPassphrase = params[1].get_str(); uint256 privKey; bool fCompressed; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fff7f700039d..9f4fd263f556 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -13,7 +13,7 @@ #include "init.h" #include "net.h" #include "netbase.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "timedata.h" #include "util.h" #include "utilmoneystr.h" @@ -30,10 +30,6 @@ #include -using namespace std; -using namespace boost; -using namespace boost::assign; - int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -64,18 +60,18 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) uint256 hash = wtx.GetHash(); entry.push_back(Pair("txid", hash.GetHex())); UniValue conflicts(UniValue::VARR); - BOOST_FOREACH (const uint256& conflict, wtx.GetConflicts()) + for (const uint256& conflict : wtx.GetConflicts()) conflicts.push_back(conflict.GetHex()); entry.push_back(Pair("walletconflicts", conflicts)); entry.push_back(Pair("time", wtx.GetTxTime())); entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); - BOOST_FOREACH (const PAIRTYPE(string, string) & item, wtx.mapValue) + for (const PAIRTYPE(std::string, std::string) & item : wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } -string AccountFromValue(const UniValue& value) +std::string AccountFromValue(const UniValue& value) { - string strAccount = value.get_str(); + std::string strAccount = value.get_str(); if (strAccount == "*") throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); return strAccount; @@ -84,7 +80,7 @@ string AccountFromValue(const UniValue& value) UniValue getnewaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getnewaddress ( \"account\" \"address_type\" )\n" "\nReturns a new Phore address for receiving payments.\n" "If 'account' is specified (recommended), it is added to the address book \n" @@ -100,7 +96,7 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); // Parse the account first so we don't generate a key if there's an error - string strAccount; + std::string strAccount; if (params.size() > 0) strAccount = AccountFromValue(params[0]); @@ -129,7 +125,7 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) } -CTxDestination GetAccountDestination(string strAccount, bool bForceNew = false) +CTxDestination GetAccountDestination(std::string strAccount, bool bForceNew = false) { CWalletDB walletdb(pwalletMain->strWalletFile); @@ -141,11 +137,11 @@ CTxDestination GetAccountDestination(string strAccount, bool bForceNew = false) // Check if the current key has been used if (account.vchPubKey.IsValid()) { CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (map::iterator it = pwalletMain->mapWallet.begin(); + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); ++it) { const CWalletTx& wtx = (*it).second; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (txout.scriptPubKey == scriptPubKey) bKeyUsed = true; } @@ -166,7 +162,7 @@ CTxDestination GetAccountDestination(string strAccount, bool bForceNew = false) UniValue getaccountaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getaccountaddress \"account\"\n" "\nReturns the current Phore address for receiving payments to this account.\n" "\nArguments:\n" @@ -179,7 +175,7 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); // Parse the account first so we don't generate a key if there's an error - string strAccount = AccountFromValue(params[0]); + std::string strAccount = AccountFromValue(params[0]); UniValue ret(UniValue::VSTR); @@ -191,7 +187,7 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp) UniValue getrawchangeaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getrawchangeaddress ( \"address_type\" )\n" "\nReturns a new Phore address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n" @@ -232,7 +228,7 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp) UniValue setaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "setaccount \"phoreaddress\" \"account\"\n" "\nSets the account associated with the given address.\n" "\nArguments:\n" @@ -248,7 +244,7 @@ UniValue setaccount(const UniValue& params, bool fHelp) CTxDestination address = DecodeDestination(params[0].get_str()); - string strAccount; + std::string strAccount; if (params.size() > 1) strAccount = AccountFromValue(params[1]); @@ -256,7 +252,7 @@ UniValue setaccount(const UniValue& params, bool fHelp) if (IsMine(*pwalletMain, address)) { // Detect when changing the account of an address that is the 'unused current key' of another account: if (pwalletMain->mapAddressBook.count(address)) { - string strOldAccount = pwalletMain->mapAddressBook[address].name; + std::string strOldAccount = pwalletMain->mapAddressBook[address].name; if (address == GetAccountDestination(strOldAccount)) GetAccountDestination(strOldAccount, true); } @@ -271,7 +267,7 @@ UniValue setaccount(const UniValue& params, bool fHelp) UniValue getaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getaccount \"phoreaddress\"\n" "\nReturns the account associated with the given address.\n" "\nArguments:\n" @@ -288,8 +284,8 @@ UniValue getaccount(const UniValue& params, bool fHelp) CTxDestination address = DecodeDestination(params[0].get_str()); - string strAccount; - map::iterator mi = pwalletMain->mapAddressBook.find(address); + std::string strAccount; + std::map::iterator mi = pwalletMain->mapAddressBook.find(address); if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) strAccount = (*mi).second.name; return strAccount; @@ -299,7 +295,7 @@ UniValue getaccount(const UniValue& params, bool fHelp) UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getaddressesbyaccount \"account\"\n" "\nReturns the list of addresses for the given account.\n" "\nArguments:\n" @@ -314,13 +310,13 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - string strAccount = AccountFromValue(params[0]); + std::string strAccount = AccountFromValue(params[0]); // Find all addresses that have the given account UniValue ret(UniValue::VARR); - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, pwalletMain->mapAddressBook) { + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : pwalletMain->mapAddressBook) { const CTxDestination& address = item.first; - const string& strName = item.second.name; + const std::string& strName = item.second.name; if (strName == strAccount) ret.push_back(EncodeDestination(address)); } @@ -336,7 +332,7 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, if (nValue > pwalletMain->GetBalance()) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); - string strError; + std::string strError; if (pwalletMain->IsLocked()) { strError = "Error: Wallet locked, unable to create transaction!"; LogPrintf("SendMoney() : %s", strError); @@ -362,7 +358,7 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, UniValue sendtoaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "sendtoaddress \"phoreaddress\" amount ( \"comment\" \"comment-to\" )\n" "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + HelpRequiringPassphrase() + @@ -406,7 +402,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp) UniValue sendtoaddressix(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "sendtoaddressix \"phoreaddress\" amount ( \"comment\" \"comment-to\" )\n" "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + HelpRequiringPassphrase() + @@ -450,7 +446,7 @@ UniValue sendtoaddressix(const UniValue& params, bool fHelp) UniValue listaddressgroupings(const UniValue& params, bool fHelp) { if (fHelp) - throw runtime_error( + throw std::runtime_error( "listaddressgroupings\n" "\nLists groups of addresses which have had their common ownership\n" "made public by common use as inputs or as the resulting change\n" @@ -473,10 +469,10 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); UniValue jsonGroupings(UniValue::VARR); - map balances = pwalletMain->GetAddressBalances(); - BOOST_FOREACH (set grouping, pwalletMain->GetAddressGroupings()) { + std::map balances = pwalletMain->GetAddressBalances(); + for (std::set grouping : pwalletMain->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); - BOOST_FOREACH (CTxDestination address, grouping) { + for (CTxDestination address : grouping) { UniValue addressInfo(UniValue::VARR); addressInfo.push_back(EncodeDestination(address)); addressInfo.push_back(ValueFromAmount(balances[address])); @@ -494,7 +490,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) UniValue signmessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "signmessage \"phoreaddress\" \"message\"\n" "\nSign a message with the private key of an address" + HelpRequiringPassphrase() + "\n" @@ -514,8 +510,8 @@ UniValue signmessage(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - string strAddress = params[0].get_str(); - string strMessage = params[1].get_str(); + std::string strAddress = params[0].get_str(); + std::string strMessage = params[1].get_str(); if (!IsValidDestinationString(strAddress)) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); @@ -534,7 +530,7 @@ UniValue signmessage(const UniValue& params, bool fHelp) ss << strMessageMagic; ss << strMessage; - vector vchSig; + std::vector vchSig; if (!key.SignCompact(ss.GetHash(), vchSig)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); @@ -544,9 +540,10 @@ UniValue signmessage(const UniValue& params, bool fHelp) UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getreceivedbyaddress \"phoreaddress\" ( minconf )\n" "\nReturns the total amount received by the given phoreaddress in transactions with at least minconf confirmations.\n" + "\nArguments:\n" "1. \"phoreaddress\" (string, required) The phore address for transactions.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -568,7 +565,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) CTxDestination address = DecodeDestination(params[0].get_str()); CScript scriptPubKey = GetScriptForDestination(address); if (!IsMine(*pwalletMain, scriptPubKey)) - return (double)0.0; + throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet"); // Minimum confirmations int nMinDepth = 1; @@ -577,12 +574,12 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) // Tally CAmount nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (txout.scriptPubKey == scriptPubKey) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; @@ -595,7 +592,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getreceivedbyaccount \"account\" ( minconf )\n" "\nReturns the total amount received by addresses with in transactions with at least [minconf] confirmations.\n" "\nArguments:\n" @@ -618,17 +615,17 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) nMinDepth = params[1].get_int(); // Get the set of pub keys assigned to account - string strAccount = AccountFromValue(params[0]); - set setAddress = pwalletMain->GetAccountAddresses(strAccount); + std::string strAccount = AccountFromValue(params[0]); + std::set setAddress = pwalletMain->GetAccountAddresses(strAccount); // Tally CAmount nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) if (wtx.GetDepthInMainChain() >= nMinDepth) @@ -640,12 +637,12 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) } -CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) +CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter) { CAmount nBalance = 0; // Tally wallet transactions - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) continue; @@ -664,7 +661,7 @@ CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi return nBalance; } -CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) +CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter) { CWalletDB walletdb(pwalletMain->strWalletFile); return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); @@ -674,7 +671,7 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef UniValue getbalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "getbalance ( \"account\" minconf includeWatchonly )\n" "\nIf account is not specified, returns the server's total available balance (excluding zerocoins).\n" "If account is specified, returns the balance in the account.\n" @@ -712,28 +709,28 @@ UniValue getbalance(const UniValue& params, bool fHelp) // (GetBalance() sums up all unspent TxOuts) // getbalance and "getbalance * 1 true" should return the same number CAmount nBalance = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) continue; CAmount allFee; - string strSentAccount; - list listReceived; - list listSent; + std::string strSentAccount; + std::list listReceived; + std::list listSent; wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH (const COutputEntry& r, listReceived) + for (const COutputEntry& r : listReceived) nBalance += r.amount; } - BOOST_FOREACH (const COutputEntry& s, listSent) + for (const COutputEntry& s : listSent) nBalance -= s.amount; nBalance -= allFee; } return ValueFromAmount(nBalance); } - string strAccount = AccountFromValue(params[0]); + std::string strAccount = AccountFromValue(params[0]); CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter); @@ -743,7 +740,7 @@ UniValue getbalance(const UniValue& params, bool fHelp) UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp) { if (fHelp || params.size() > 0) - throw runtime_error( + throw std::runtime_error( "getunconfirmedbalance\n" "Returns the server's total unconfirmed balance\n"); @@ -756,31 +753,36 @@ UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp) UniValue movecmd(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 5) - throw runtime_error( + throw std::runtime_error( "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" "\nMove a specified amount from one account in your wallet to another.\n" "\nArguments:\n" "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n" "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n" - "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" - "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" + "3. amount (numeric, required) Quantity of PHR to move between accounts.\n" + "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" + "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" + "\nResult:\n" - "true|false (boolean) true if successfull.\n" + "true|false (boolean) true if successful.\n" + "\nExamples:\n" "\nMove 0.01 phore from the default account to the account named tabby\n" + HelpExampleCli("move", "\"\" \"tabby\" 0.01") + - "\nMove 0.01 phore timotei to akiko with a comment and funds have 6 confirmations\n" + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")); + "\nMove 0.01 phore from timotei to akiko with a comment\n" + + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 1 \"happy birthday!\"") + + "\nAs a json rpc call\n" + + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 1, \"happy birthday!\"")); LOCK2(cs_main, pwalletMain->cs_wallet); - string strFrom = AccountFromValue(params[0]); - string strTo = AccountFromValue(params[1]); + std::string strFrom = AccountFromValue(params[0]); + std::string strTo = AccountFromValue(params[1]); CAmount nAmount = AmountFromValue(params[2]); if (params.size() > 3) // unused parameter, used to be nMinDepth, keep type-checking it though (void)params[3].get_int(); - string strComment; + std::string strComment; if (params.size() > 4) strComment = params[4].get_str(); @@ -820,7 +822,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) UniValue sendfrom(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 6) - throw runtime_error( + throw std::runtime_error( "sendfrom \"fromaccount\" \"tophoreaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" "\nSent an amount from an account to a phore address.\n" "The amount is a real and is rounded to the nearest 0.00000001." + @@ -845,7 +847,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - string strAccount = AccountFromValue(params[0]); + std::string strAccount = AccountFromValue(params[0]); if (!IsValidDestinationString(params[1].get_str())) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Phore address"); @@ -878,7 +880,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp) UniValue sendmany(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" )\n" "\nSend multiple times. Amounts are double-precision floating point numbers." + HelpRequiringPassphrase() + "\n" @@ -902,7 +904,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - string strAccount = AccountFromValue(params[0]); + std::string strAccount = AccountFromValue(params[0]); UniValue sendTo = params[1].get_obj(); int nMinDepth = 1; if (params.size() > 2) @@ -913,26 +915,26 @@ UniValue sendmany(const UniValue& params, bool fHelp) if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) wtx.mapValue["comment"] = params[3].get_str(); - set setAddress; - vector > vecSend; + std::set setAddress; + std::vector > vecSend; CAmount totalAmount = 0; - vector keys = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, keys) { + std::vector keys = sendTo.getKeys(); + for (const std::string& name_ : keys) { if (!IsValidDestinationString(name_)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Phore address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Phore address: ")+name_); CTxDestination address = DecodeDestination(name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address); CAmount nAmount = AmountFromValue(sendTo[name_]); totalAmount += nAmount; - vecSend.push_back(make_pair(scriptPubKey, nAmount)); + vecSend.push_back(std::make_pair(scriptPubKey, nAmount)); } EnsureWalletIsUnlocked(); @@ -945,7 +947,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) // Send CReserveKey keyChange(pwalletMain); CAmount nFeeRequired = 0; - string strFailReason; + std::string strFailReason; bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); @@ -955,13 +957,13 @@ UniValue sendmany(const UniValue& params, bool fHelp) return wtx.GetHash().GetHex(); } -// Defined in rpcmisc.cpp +// Defined in rpc/misc.cpp extern CScript _createmultisig_redeemScript(const UniValue& params); UniValue addmultisigaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) { - string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" + std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" "\nAdd a nrequired-to-sign multisignature address to the wallet.\n" "Each key is a Phore address or hex-encoded public key.\n" "If 'account' is specified, assign address to that account.\n" @@ -982,12 +984,12 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp) "\nAdd a multisig address from 2 addresses\n" + HelpExampleCli("addmultisigaddress", "2 \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\"") + "\nAs json rpc call\n" + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\""); - throw runtime_error(msg); + throw std::runtime_error(msg); } LOCK2(cs_main, pwalletMain->cs_wallet); - string strAccount; + std::string strAccount; if (params.size() > 2) strAccount = AccountFromValue(params[2]); @@ -1064,7 +1066,7 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) { - string msg = "addwitnessaddress \"address\" ( p2sh )\n" + std::string msg = "addwitnessaddress \"address\" ( p2sh )\n" "\nAdd a witness address for a script (with pubkey or redeemscript known).\n" "It returns the witness script.\n" @@ -1076,7 +1078,7 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp) "\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n" "}\n" ; - throw runtime_error(msg); + throw std::runtime_error(msg); } if (!IsSporkActive(SPORK_17_SEGWIT_ACTIVATION) && !GetBoolArg("-walletprematurewitness", false)) { @@ -1121,7 +1123,7 @@ struct tallyitem { CAmount nAmount; int nConf; int nBCConf; - vector txids; + std::vector txids; bool fIsWatchonly; tallyitem() { @@ -1150,8 +1152,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) filter = filter | ISMINE_WATCH_ONLY; // Tally - map mapTally; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + std::map mapTally; + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) @@ -1162,7 +1164,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (nDepth < nMinDepth) continue; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { CTxDestination address; if (!ExtractDestination(txout.scriptPubKey, address)) continue; @@ -1173,8 +1175,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) tallyitem& item = mapTally[address]; item.nAmount += txout.nValue; - item.nConf = min(item.nConf, nDepth); - item.nBCConf = min(item.nBCConf, nBCDepth); + item.nConf = std::min(item.nConf, nDepth); + item.nBCConf = std::min(item.nBCConf, nBCDepth); item.txids.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) item.fIsWatchonly = true; @@ -1183,11 +1185,11 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) // Reply UniValue ret(UniValue::VARR); - map mapAccountTally; - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, pwalletMain->mapAddressBook) { + std::map mapAccountTally; + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : pwalletMain->mapAddressBook) { const CTxDestination& address = item.first; - const string& strAccount = item.second.name; - map::iterator it = mapTally.find(address); + const std::string& strAccount = item.second.name; + std::map::iterator it = mapTally.find(address); if (it == mapTally.end() && !fIncludeEmpty) continue; @@ -1205,8 +1207,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (fByAccounts) { tallyitem& item = mapAccountTally[strAccount]; item.nAmount += nAmount; - item.nConf = min(item.nConf, nConf); - item.nBCConf = min(item.nBCConf, nBCConf); + item.nConf = std::min(item.nConf, nConf); + item.nBCConf = std::min(item.nBCConf, nBCConf); item.fIsWatchonly = fIsWatchonly; } else { UniValue obj(UniValue::VOBJ); @@ -1219,7 +1221,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { - BOOST_FOREACH (const uint256& item, (*it).second.txids) { + for (const uint256& item : (*it).second.txids) { transactions.push_back(item.GetHex()); } } @@ -1229,7 +1231,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) } if (fByAccounts) { - for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { + for (std::map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { CAmount nAmount = (*it).second.nAmount; int nConf = (*it).second.nConf; int nBCConf = (*it).second.nBCConf; @@ -1250,7 +1252,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n" "\nList balances by receiving address.\n" "\nArguments:\n" @@ -1282,7 +1284,7 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) - throw runtime_error( + throw std::runtime_error( "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n" "\nList balances by account.\n" "\nArguments:\n" @@ -1316,21 +1318,21 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) entry.push_back(Pair("address", EncodeDestination(dest))); } -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) +void ListTransactions(const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) { CAmount nFee; - string strSentAccount; - list listReceived; - list listSent; + std::string strSentAccount; + std::list listReceived; + std::list listSent; wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); - bool fAllAccounts = (strAccount == string("*")); + bool fAllAccounts = (strAccount == std::string("*")); bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); // Sent if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { - BOOST_FOREACH (const COutputEntry& s, listSent) { + for (const COutputEntry& s : listSent) { UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); @@ -1349,8 +1351,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH (const COutputEntry& r, listReceived) { - string account; + for (const COutputEntry& r : listReceived) { + std::string account; if (pwalletMain->mapAddressBook.count(r.destination)) account = pwalletMain->mapAddressBook[r.destination].name; if (fAllAccounts || (account == strAccount)) { @@ -1379,9 +1381,9 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe } } -void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret) +void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret) { - bool fAllAccounts = (strAccount == string("*")); + bool fAllAccounts = (strAccount == std::string("*")); if (fAllAccounts || acentry.strAccount == strAccount) { UniValue entry(UniValue::VOBJ); @@ -1398,7 +1400,7 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Un UniValue listtransactions(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 4) - throw runtime_error( + throw std::runtime_error( "listtransactions ( \"account\" count from includeWatchonly)\n" "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" "\nArguments:\n" @@ -1452,7 +1454,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - string strAccount = "*"; + std::string strAccount = "*"; if (params.size() > 0) strAccount = params[0].get_str(); int nCount = 10; @@ -1493,11 +1495,11 @@ UniValue listtransactions(const UniValue& params, bool fHelp) if ((nFrom + nCount) > (int)ret.size()) nCount = ret.size() - nFrom; - vector arrTmp = ret.getValues(); + std::vector arrTmp = ret.getValues(); - vector::iterator first = arrTmp.begin(); + std::vector::iterator first = arrTmp.begin(); std::advance(first, nFrom); - vector::iterator last = arrTmp.begin(); + std::vector::iterator last = arrTmp.begin(); std::advance(last, nFrom+nCount); if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); @@ -1515,7 +1517,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) UniValue listaccounts(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "listaccounts ( minconf includeWatchonly)\n" "\nReturns Object that has account names as keys, account balances as values.\n" "\nArguments:\n" @@ -1543,27 +1545,27 @@ UniValue listaccounts(const UniValue& params, bool fHelp) if (params[1].get_bool()) includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; - map mapAccountBalances; - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & entry, pwalletMain->mapAddressBook) { + std::map mapAccountBalances; + for (const PAIRTYPE(CTxDestination, CAddressBookData) & entry : pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me mapAccountBalances[entry.second.name] = 0; } - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; CAmount nFee; - string strSentAccount; - list listReceived; - list listSent; + std::string strSentAccount; + std::list listReceived; + std::list listSent; int nDepth = wtx.GetDepthInMainChain(); if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) continue; wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); mapAccountBalances[strSentAccount] -= nFee; - BOOST_FOREACH (const COutputEntry& s, listSent) + for (const COutputEntry& s : listSent) mapAccountBalances[strSentAccount] -= s.amount; if (nDepth >= nMinDepth) { - BOOST_FOREACH (const COutputEntry& r, listReceived) + for (const COutputEntry& r : listReceived) if (pwalletMain->mapAddressBook.count(r.destination)) mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount; else @@ -1571,12 +1573,12 @@ UniValue listaccounts(const UniValue& params, bool fHelp) } } - const list & acentries = pwalletMain->laccentries; - BOOST_FOREACH (const CAccountingEntry& entry, acentries) + const std::list & acentries = pwalletMain->laccentries; + for (const CAccountingEntry& entry : acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; UniValue ret(UniValue::VOBJ); - BOOST_FOREACH (const PAIRTYPE(string, CAmount) & accountBalance, mapAccountBalances) { + for (const PAIRTYPE(std::string, CAmount) & accountBalance : mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; @@ -1585,7 +1587,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) UniValue listsinceblock(const UniValue& params, bool fHelp) { if (fHelp) - throw runtime_error( + throw std::runtime_error( "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n" "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n" "\nArguments:\n" @@ -1648,7 +1650,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) UniValue transactions(UniValue::VARR); - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { CWalletTx tx = (*it).second; if (depth == -1 || tx.GetDepthInMainChain(false) < depth) @@ -1668,7 +1670,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) UniValue gettransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "gettransaction \"txid\" ( includeWatchonly )\n" "\nGet detailed information about in-wallet transaction \n" "\nArguments:\n" @@ -1731,7 +1733,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp) ListTransactions(wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); - string strHex = EncodeHexTx(static_cast(wtx), PROTOCOL_VERSION | RPCSerializationFlags()); + std::string strHex = EncodeHexTx(static_cast(wtx), PROTOCOL_VERSION | RPCSerializationFlags()); entry.push_back(Pair("hex", strHex)); return entry; @@ -1741,7 +1743,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp) UniValue backupwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "backupwallet \"destination\"\n" "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n" "\nArguments:\n" @@ -1751,7 +1753,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - string strDest = params[0].get_str(); + std::string strDest = params[0].get_str(); if (!BackupWallet(*pwalletMain, strDest)) throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); @@ -1762,7 +1764,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp) UniValue keypoolrefill(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "keypoolrefill ( newsize )\n" "\nFills the keypool." + HelpRequiringPassphrase() + "\n" @@ -1802,7 +1804,7 @@ static void LockWallet(CWallet* pWallet) UniValue walletpassphrase(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3)) - throw runtime_error( + throw std::runtime_error( "walletpassphrase \"passphrase\" timeout ( anonymizeonly )\n" "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" "This is needed prior to performing transactions related to private keys such as sending PHRs\n" @@ -1841,15 +1843,23 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) if (!pwalletMain->IsLocked() && pwalletMain->fWalletUnlockAnonymizeOnly && anonymizeOnly) throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked."); + // Get the timeout + int64_t nSleepTime = params[1].get_int64(); + // Timeout cannot be negative, otherwise it will relock immediately + if (nSleepTime < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); + } + // Clamp timeout + constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug? + if (nSleepTime > MAX_SLEEP_TIME) { + nSleepTime = MAX_SLEEP_TIME; + } + if (!pwalletMain->Unlock(strWalletPass, anonymizeOnly)) throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); pwalletMain->TopUpKeyPool(); - int64_t nSleepTime = params[1].get_int64(); - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = GetTime() + nSleepTime; - if (nSleepTime > 0) { nWalletUnlockTime = GetTime () + nSleepTime; RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); @@ -1862,7 +1872,7 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) UniValue walletpassphrasechange(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) - throw runtime_error( + throw std::runtime_error( "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n" "\nArguments:\n" @@ -1889,7 +1899,7 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp) strNewWalletPass = params[1].get_str().c_str(); if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) - throw runtime_error( + throw std::runtime_error( "walletpassphrasechange \n" "Changes the wallet passphrase from to ."); @@ -1903,7 +1913,7 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp) UniValue walletlock(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) - throw runtime_error( + throw std::runtime_error( "walletlock\n" "\nRemoves the wallet encryption key from memory, locking the wallet.\n" "After calling this method, you will need to call walletpassphrase again\n" @@ -1935,7 +1945,7 @@ UniValue walletlock(const UniValue& params, bool fHelp) UniValue encryptwallet(const UniValue& params, bool fHelp) { if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) - throw runtime_error( + throw std::runtime_error( "encryptwallet \"passphrase\"\n" "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" "After this, any calls that interact with private keys such as sending or signing \n" @@ -1967,7 +1977,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp) strWalletPass = params[0].get_str().c_str(); if (strWalletPass.length() < 1) - throw runtime_error( + throw std::runtime_error( "encryptwallet \n" "Encrypts the wallet with ."); @@ -1984,7 +1994,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp) UniValue lockunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" @@ -2038,7 +2048,7 @@ UniValue lockunspent(const UniValue& params, bool fHelp) RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)); - string txid = find_value(o, "txid").get_str(); + std::string txid = find_value(o, "txid").get_str(); if (!IsHex(txid)) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); @@ -2060,7 +2070,7 @@ UniValue lockunspent(const UniValue& params, bool fHelp) UniValue listlockunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) - throw runtime_error( + throw std::runtime_error( "listlockunspent\n" "\nReturns list of temporarily unspendable outputs.\n" "See the lockunspent call to lock and unlock transactions for spending.\n" @@ -2082,12 +2092,12 @@ UniValue listlockunspent(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - vector vOutpts; + std::vector vOutpts; pwalletMain->ListLockedCoins(vOutpts); UniValue ret(UniValue::VARR); - BOOST_FOREACH (COutPoint& outpt, vOutpts) { + for (COutPoint& outpt : vOutpts) { UniValue o(UniValue::VOBJ); o.push_back(Pair("txid", outpt.hash.GetHex())); @@ -2101,7 +2111,7 @@ UniValue listlockunspent(const UniValue& params, bool fHelp) UniValue settxfee(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "settxfee amount\n" "\nSet the transaction fee per kB.\n" "\nArguments:\n" @@ -2125,7 +2135,7 @@ UniValue settxfee(const UniValue& params, bool fHelp) UniValue getwalletinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getwalletinfo\n" "Returns an object containing various wallet state info.\n" "\nResult:\n" @@ -2147,6 +2157,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) " }\n" " ,...\n" " ]\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in PHR/kB\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); @@ -2185,6 +2196,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) } obj.push_back(Pair("hdaccounts", accounts)); } + obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); return obj; } @@ -2192,7 +2204,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) UniValue reservebalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "reservebalance ( reserve amount )\n" "\nShow or set the reserve amount not participating in network protection\n" "If no parameters provided current setting is printed.\n" @@ -2212,15 +2224,15 @@ UniValue reservebalance(const UniValue& params, bool fHelp) bool fReserve = params[0].get_bool(); if (fReserve) { if (params.size() == 1) - throw runtime_error("must provide amount to reserve balance.\n"); + throw std::runtime_error("must provide amount to reserve balance.\n"); CAmount nAmount = AmountFromValue(params[1]); nAmount = (nAmount / CENT) * CENT; // round to cent if (nAmount < 0) - throw runtime_error("amount cannot be negative.\n"); + throw std::runtime_error("amount cannot be negative.\n"); nReserveBalance = nAmount; } else { if (params.size() > 1) - throw runtime_error("cannot specify amount to turn off reserve.\n"); + throw std::runtime_error("cannot specify amount to turn off reserve.\n"); nReserveBalance = 0; } } @@ -2235,7 +2247,7 @@ UniValue reservebalance(const UniValue& params, bool fHelp) UniValue setstakesplitthreshold(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "setstakesplitthreshold value\n" "\nThis will set the output size of your stakes to never be below this number\n" @@ -2253,7 +2265,7 @@ UniValue setstakesplitthreshold(const UniValue& params, bool fHelp) uint64_t nStakeSplitThreshold = params[0].get_int(); if (nStakeSplitThreshold > 999999) - throw runtime_error("Value out of range, max allowed is 999999"); + throw std::runtime_error("Value out of range, max allowed is 999999"); CWalletDB walletdb(pwalletMain->strWalletFile); LOCK(pwalletMain->cs_wallet); @@ -2277,7 +2289,7 @@ UniValue setstakesplitthreshold(const UniValue& params, bool fHelp) UniValue getstakesplitthreshold(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getstakesplitthreshold\n" "Returns the threshold for stake splitting\n" "\nResult:\n" @@ -2295,7 +2307,7 @@ UniValue autocombinerewards(const UniValue& params, bool fHelp) fEnable = params[0].get_bool(); if (fHelp || params.size() < 1 || (fEnable && params.size() != 2) || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "autocombinerewards true|false ( threshold )\n" "\nWallet will automatically monitor for any coins with value below the threshold amount, and combine them if they reside with the same Phore address\n" "When autocombinerewards runs it will create a transaction, and therefore will be subject to transaction fees.\n" @@ -2316,7 +2328,7 @@ UniValue autocombinerewards(const UniValue& params, bool fHelp) pwalletMain->nAutoCombineThreshold = nThreshold; if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) - throw runtime_error("Changed settings in wallet but failed to save to database\n"); + throw std::runtime_error("Changed settings in wallet but failed to save to database\n"); return NullUniValue; } @@ -2354,7 +2366,7 @@ UniValue printAddresses() std::vector vCoins; pwalletMain->AvailableCoins(vCoins); std::map mapAddresses; - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { CTxDestination utxoAddress; ExtractDestination(out.tx->vout[out.i].scriptPubKey, utxoAddress); std::string strAdd = EncodeDestination(utxoAddress); @@ -2366,7 +2378,7 @@ UniValue printAddresses() } UniValue ret(UniValue::VARR); - for (map::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); ++it) { + for (std::map::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); ++it) { UniValue obj(UniValue::VOBJ); const std::string* strAdd = &(*it).first; const double* nBalance = &(*it).second; @@ -2392,7 +2404,7 @@ UniValue multisend(const UniValue& params, bool fHelp) bool fFileBacked; //MultiSend Commands if (params.size() == 1) { - string strCommand = params[0].get_str(); + std::string strCommand = params[0].get_str(); UniValue ret(UniValue::VOBJ); if (strCommand == "print") { return printMultiSend(); @@ -2469,7 +2481,7 @@ UniValue multisend(const UniValue& params, bool fHelp) } } if (params.size() == 2 && params[0].get_str() == "delete") { - int del = boost::lexical_cast(params[1].get_str()); + int del = std::stoi(params[1].get_str().c_str()); if (!walletdb.EraseMultiSend(pwalletMain->vMultiSend)) throw JSONRPCError(RPC_DATABASE_ERROR, "failed to delete old MultiSend vector from database"); @@ -2497,7 +2509,7 @@ UniValue multisend(const UniValue& params, bool fHelp) //if no commands are used if (fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "multisend \n" "****************************************************************\n" "WHAT IS MULTISEND?\n" @@ -2521,14 +2533,14 @@ UniValue multisend(const UniValue& params, bool fHelp) "****************************************************************\n"); //if the user is entering a new MultiSend item - string strAddress = params[0].get_str(); + std::string strAddress = params[0].get_str(); if (!IsValidDestinationString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PHR address"); - if (boost::lexical_cast(params[1].get_str()) < 0) + if (std::stoi(params[1].get_str().c_str()) < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid percentage"); if (pwalletMain->IsLocked()) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); - unsigned int nPercent = boost::lexical_cast(params[1].get_str()); + unsigned int nPercent = (unsigned int) std::stoul(params[1].get_str().c_str()); LOCK(pwalletMain->cs_wallet); { @@ -2565,7 +2577,7 @@ UniValue getzerocoinbalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getzerocoinbalance\n" "\nReturn the wallet's total zPHR balance.\n" + HelpRequiringPassphrase() + "\n" @@ -2588,7 +2600,7 @@ UniValue listmintedzerocoins(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "listmintedzerocoins\n" "\nList all zPHR mints in the wallet.\n" + HelpRequiringPassphrase() + "\n" @@ -2608,7 +2620,7 @@ UniValue listmintedzerocoins(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); CWalletDB walletdb(pwalletMain->strWalletFile); - set setMints = pwalletMain->zphrTracker->ListMints(true, true, true); + std::set setMints = pwalletMain->zphrTracker->ListMints(true, true, true); UniValue jsonList(UniValue::VARR); for (const CMintMeta& meta : setMints) { @@ -2622,7 +2634,7 @@ UniValue listzerocoinamounts(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "listzerocoinamounts\n" "\nGet information about your zerocoin amounts.\n" + HelpRequiringPassphrase() + "\n" @@ -2644,7 +2656,7 @@ UniValue listzerocoinamounts(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); CWalletDB walletdb(pwalletMain->strWalletFile); - set setMints = pwalletMain->zphrTracker->ListMints(true, true, true); + std::set setMints = pwalletMain->zphrTracker->ListMints(true, true, true); std::map spread; for (const auto& denom : libzerocoin::zerocoinDenomList) @@ -2666,7 +2678,7 @@ UniValue listspentzerocoins(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "listspentzerocoins\n" "\nList all the spent zPHR mints in the wallet.\n" + HelpRequiringPassphrase() + "\n" @@ -2685,7 +2697,7 @@ UniValue listspentzerocoins(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(true); CWalletDB walletdb(pwalletMain->strWalletFile); - list listPubCoin = walletdb.ListSpentCoinsSerial(); + std::list listPubCoin = walletdb.ListSpentCoinsSerial(); UniValue jsonList(UniValue::VARR); for (const CBigNum& pubCoinItem : listPubCoin) { @@ -2698,7 +2710,7 @@ UniValue listspentzerocoins(const UniValue& params, bool fHelp) UniValue mintzerocoin(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "mintzerocoin amount ( utxos )\n" "\nMint the specified zPHR amount\n" + HelpRequiringPassphrase() + "\n" @@ -2755,9 +2767,9 @@ UniValue mintzerocoin(const UniValue& params, bool fHelp) CAmount nAmount = params[0].get_int() * COIN; CWalletTx wtx; - vector vDMints; - string strError; - vector vOutpts; + std::vector vDMints; + std::string strError; + std::vector vOutpts; if (params.size() == 2) { @@ -2770,7 +2782,7 @@ UniValue mintzerocoin(const UniValue& params, bool fHelp) RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)); - string txid = find_value(o, "txid").get_str(); + std::string txid = find_value(o, "txid").get_str(); if (!IsHex(txid)) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); @@ -2809,7 +2821,7 @@ UniValue mintzerocoin(const UniValue& params, bool fHelp) UniValue spendzerocoin(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 5 || params.size() < 4) - throw runtime_error( + throw std::runtime_error( "spendzerocoin amount mintchange minimizechange securitylevel ( \"address\" )\n" "\nSpend zPHR to a PHR address.\n" + HelpRequiringPassphrase() + "\n" @@ -2879,7 +2891,7 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp) } CWalletTx wtx; - vector vMintsSelected; + std::vector vMintsSelected; CZerocoinSpendReceipt receipt; bool fSuccess; @@ -2935,7 +2947,7 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp) UniValue resetmintzerocoin(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "resetmintzerocoin ( fullscan )\n" "\nScan the blockchain for all of the zerocoins that are held in the wallet.dat.\n" "Update any meta-data that is incorrect. Archive any mints that are not able to be found.\n" + @@ -2963,10 +2975,10 @@ UniValue resetmintzerocoin(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); CzPHRTracker* zphrTracker = pwalletMain->zphrTracker.get(); - set setMints = zphrTracker->ListMints(false, false, true); - vector vMintsToFind(setMints.begin(), setMints.end()); - vector vMintsMissing; - vector vMintsToUpdate; + std::set setMints = zphrTracker->ListMints(false, false, true); + std::vector vMintsToFind(setMints.begin(), setMints.end()); + std::vector vMintsMissing; + std::vector vMintsToUpdate; // search all of our available data for these mints FindMints(vMintsToFind, vMintsToUpdate, vMintsMissing); @@ -2994,7 +3006,7 @@ UniValue resetmintzerocoin(const UniValue& params, bool fHelp) UniValue resetspentzerocoin(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "resetspentzerocoin\n" "\nScan the blockchain for all of the zerocoins that are held in the wallet.dat.\n" "Reset mints that are considered spent that did not make it into the blockchain.\n" @@ -3016,9 +3028,9 @@ UniValue resetspentzerocoin(const UniValue& params, bool fHelp) CWalletDB walletdb(pwalletMain->strWalletFile); CzPHRTracker* zphrTracker = pwalletMain->zphrTracker.get(); - set setMints = zphrTracker->ListMints(false, false, false); - list listSpends = walletdb.ListSpentCoins(); - list listUnconfirmedSpends; + std::set setMints = zphrTracker->ListMints(false, false, false); + std::list listSpends = walletdb.ListSpentCoins(); + std::list listUnconfirmedSpends; for (CZerocoinSpend spend : listSpends) { CTransaction tx; @@ -3056,7 +3068,7 @@ UniValue resetspentzerocoin(const UniValue& params, bool fHelp) UniValue getarchivedzerocoin(const UniValue& params, bool fHelp) { if(fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getarchivedzerocoin\n" "\nDisplay zerocoins that were archived because they were believed to be orphans.\n" "Provides enough information to recover mint if it was incorrectly archived.\n" + @@ -3082,8 +3094,8 @@ UniValue getarchivedzerocoin(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); CWalletDB walletdb(pwalletMain->strWalletFile); - list listMints = walletdb.ListArchivedZerocoins(); - list listDMints = walletdb.ListArchivedDeterministicMints(); + std::list listMints = walletdb.ListArchivedZerocoins(); + std::list listDMints = walletdb.ListArchivedDeterministicMints(); UniValue arrRet(UniValue::VARR); for (const CZerocoinMint& mint : listMints) { @@ -3114,7 +3126,7 @@ UniValue getarchivedzerocoin(const UniValue& params, bool fHelp) UniValue exportzerocoins(const UniValue& params, bool fHelp) { if(fHelp || params.empty() || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "exportzerocoins include_spent ( denomination )\n" "\nExports zerocoin mints that are held by this wallet.dat\n" + HelpRequiringPassphrase() + "\n" @@ -3154,7 +3166,7 @@ UniValue exportzerocoins(const UniValue& params, bool fHelp) denomination = libzerocoin::IntToZerocoinDenomination(params[1].get_int()); CzPHRTracker* zphrTracker = pwalletMain->zphrTracker.get(); - set setMints = zphrTracker->ListMints(!fIncludeSpent, false, false); + std::set setMints = zphrTracker->ListMints(!fIncludeSpent, false, false); UniValue jsonList(UniValue::VARR); for (const CMintMeta& meta : setMints) { @@ -3186,7 +3198,7 @@ UniValue exportzerocoins(const UniValue& params, bool fHelp) UniValue importzerocoins(const UniValue& params, bool fHelp) { if(fHelp || params.size() == 0) - throw runtime_error( + throw std::runtime_error( "importzerocoins importdata \n" "\n[{\"d\":denomination,\"p\":\"pubcoin_hex\",\"s\":\"serial_hex\",\"r\":\"randomness_hex\",\"t\":\"txid\",\"h\":height, \"u\":used},{\"d\":...}]\n" "\nImport zerocoin mints.\n" @@ -3211,7 +3223,7 @@ UniValue importzerocoins(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - RPCTypeCheck(params, list_of(UniValue::VARR)(UniValue::VOBJ)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); UniValue arrMints = params[0].get_array(); CWalletDB walletdb(pwalletMain->strWalletFile); @@ -3277,7 +3289,7 @@ UniValue importzerocoins(const UniValue& params, bool fHelp) UniValue reconsiderzerocoins(const UniValue& params, bool fHelp) { if(fHelp || !params.empty()) - throw runtime_error( + throw std::runtime_error( "reconsiderzerocoins\n" "\nCheck archived zPHR list to see if any mints were added to the blockchain.\n" + HelpRequiringPassphrase() + "\n" @@ -3300,8 +3312,8 @@ UniValue reconsiderzerocoins(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - list listMints; - list listDMints; + std::list listMints; + std::list listDMints; pwalletMain->ReconsiderZerocoins(listMints, listDMints); UniValue arrRet(UniValue::VARR); @@ -3330,12 +3342,12 @@ UniValue reconsiderzerocoins(const UniValue& params, bool fHelp) UniValue makekeypair(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) - throw runtime_error( + throw std::runtime_error( "makekeypair [prefix]\n" "Make a public/private key pair.\n" "[prefix] is optional preferred prefix for the public key.\n"); - string strPrefix = ""; + std::string strPrefix = ""; if (params.size() > 0) strPrefix = params[0].get_str(); @@ -3351,7 +3363,7 @@ UniValue makekeypair(const UniValue& params, bool fHelp) UniValue setzphrseed(const UniValue& params, bool fHelp) { if(fHelp || params.size() != 1) - throw runtime_error( + throw std::runtime_error( "setzphrseed \"seed\"\n" "\nSet the wallet's deterministic zphr seed to a specific value.\n" + HelpRequiringPassphrase() + "\n" @@ -3385,7 +3397,7 @@ UniValue setzphrseed(const UniValue& params, bool fHelp) UniValue getzphrseed(const UniValue& params, bool fHelp) { if(fHelp || !params.empty()) - throw runtime_error( + throw std::runtime_error( "getzphrseed\n" "\nCheck archived zPHR list to see if any mints were added to the blockchain.\n" + HelpRequiringPassphrase() + "\n" @@ -3410,7 +3422,7 @@ UniValue getzphrseed(const UniValue& params, bool fHelp) UniValue generatemintlist(const UniValue& params, bool fHelp) { if(fHelp || params.size() != 2) - throw runtime_error( + throw std::runtime_error( "generatemintlist\n" "\nShow mints that are derived from the deterministic zPHR seed.\n" + HelpRequiringPassphrase() + "\n" @@ -3458,7 +3470,7 @@ UniValue generatemintlist(const UniValue& params, bool fHelp) UniValue dzphrstate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) - throw runtime_error( + throw std::runtime_error( "dzphrstate\n" "\nThe current state of the mintpool of the deterministic zPHR wallet.\n" + HelpRequiringPassphrase() + "\n" @@ -3497,7 +3509,7 @@ void static SearchThread(CzPHRWallet* zwallet, int nCountStart, int nCountEnd) zwallet->SeedToZPHR(zerocoinSeed, bnValue, bnSerial, bnRandomness, key); uint256 hashPubcoin = GetPubCoinHash(bnValue); - zwallet->AddToMintPool(make_pair(hashPubcoin, i), true); + zwallet->AddToMintPool(std::make_pair(hashPubcoin, i), true); walletDB.WriteMintPoolPair(hashSeed, hashPubcoin, i); } } catch (std::exception& e) { @@ -3510,7 +3522,7 @@ void static SearchThread(CzPHRWallet* zwallet, int nCountStart, int nCountEnd) UniValue searchdzphr(const UniValue& params, bool fHelp) { if(fHelp || params.size() != 3) - throw runtime_error( + throw std::runtime_error( "searchdzphr\n" "\nMake an extended search for deterministically generated zPHR that have not yet been recognized by the wallet.\n" + HelpRequiringPassphrase() + "\n" diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4d2cb5927ffa..7cfc8bf7eaeb 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -40,7 +40,6 @@ #include #include -using namespace std; /** * Settings @@ -70,8 +69,8 @@ CFeeRate CWallet::minTxFee = CFeeRate(10000); */ struct CompareValueOnly { - bool operator()(const pair >& t1, - const pair >& t2) const + bool operator()(const std::pair >& t1, + const std::pair >& t2) const { return t1.first < t2.first; } @@ -299,7 +298,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey& pubkey) } bool CWallet::AddCryptedKey(const CPubKey& vchPubKey, - const vector& vchCryptedSecret) + const std::vector& vchCryptedSecret) { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; @@ -418,23 +417,13 @@ bool CWallet::LoadMultiSig(const CScript& dest) bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly) { - SecureString strWalletPassphraseFinal; - - if (!IsLocked()) { - fWalletUnlockAnonymizeOnly = anonymizeOnly; - return true; - } - - strWalletPassphraseFinal = strWalletPassphrase; - - CCrypter crypter; CKeyingMaterial vMasterKey; { LOCK(cs_wallet); - BOOST_FOREACH (const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { - if (!crypter.SetKeyFromPassphrase(strWalletPassphraseFinal, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys) { + if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) continue; // try another master key @@ -458,7 +447,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, CCrypter crypter; CKeyingMaterial vMasterKey; - BOOST_FOREACH (MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { + for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys) { if (!crypter.SetKeyFromPassphrase(strOldWalletPassphraseFinal, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) @@ -537,9 +526,9 @@ bool CWallet::SetMaxVersion(int nVersion) return true; } -set CWallet::GetConflicts(const uint256& txid) const +std::set CWallet::GetConflicts(const uint256& txid) const { - set result; + std::set result; AssertLockHeld(cs_wallet); std::map::const_iterator it = mapWallet.find(txid); @@ -549,7 +538,7 @@ set CWallet::GetConflicts(const uint256& txid) const std::pair range; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { if (mapTxSpends.count(txin.prevout) <= 1 || wtx.IsZerocoinSpend()) continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); @@ -559,7 +548,7 @@ set CWallet::GetConflicts(const uint256& txid) const return result; } -void CWallet::SyncMetaData(pair range) +void CWallet::SyncMetaData(std::pair range) { // We want all the wallet transactions in range to have the same metadata as // the oldest (smallest nOrderPos). @@ -599,7 +588,7 @@ void CWallet::SyncMetaData(pair range) bool CWallet::IsSpent(const uint256& hash, unsigned int n) const { const COutPoint outpoint(hash, n); - pair range; + std::pair range; range = mapTxSpends.equal_range(outpoint); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { const uint256& wtxid = it->second; @@ -612,8 +601,8 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid) { - mapTxSpends.insert(make_pair(outpoint, wtxid)); - pair range; + mapTxSpends.insert(std::make_pair(outpoint, wtxid)); + std::pair range; range = mapTxSpends.equal_range(outpoint); SyncMetaData(range); } @@ -626,7 +615,7 @@ void CWallet::AddToSpends(const uint256& wtxid) if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; - BOOST_FOREACH (const CTxIn& txin, thisTx.vin) + for (const CTxIn& txin : thisTx.vin) AddToSpends(txin.prevout, wtxid); } @@ -666,7 +655,7 @@ bool CWallet::GetMasternodeVinAndKeys(CTxIn& txinRet, CPubKey& pubKeyRet, CKey& return false; } - BOOST_FOREACH (COutput& out, vPossibleCoins) + for (COutput& out : vPossibleCoins) if (out.tx->GetHash() == txHash && out.i == nOutputIndex) // found it! return GetVinAndKeysFromOutput(out, txinRet, pubKeyRet, keyRet); @@ -937,7 +926,7 @@ void CWallet::MarkDirty() { { LOCK(cs_wallet); - BOOST_FOREACH (PAIRTYPE(const uint256, CWalletTx) & item, mapWallet) + for (PAIRTYPE(const uint256, CWalletTx) & item : mapWallet) item.second.MarkDirty(); } } @@ -950,12 +939,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) mapWallet[hash] = wtxIn; CWalletTx& wtx = mapWallet[hash]; wtx.BindWallet(this); - wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(hash); } else { LOCK(cs_wallet); // Inserts only if not already there, returns tx inserted or tx found - pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); + std::pair::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; wtx.BindWallet(this); bool fInsertedNew = ret.second; @@ -968,7 +957,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) AddToSpends(hash); // wqking -- fix a bug that listtransactions doesn't return recent transactions. - wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); } bool fUpdated = false; @@ -1045,7 +1034,7 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be // recomputed, also: - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { if (!tx.IsZerocoinSpend() && mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } @@ -1068,7 +1057,7 @@ isminetype CWallet::IsMine(const CTxIn& txin) const { { LOCK(cs_wallet); - map::const_iterator mi = mapWallet.find(txin.prevout.hash); + std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.vout.size()) @@ -1087,7 +1076,7 @@ CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const { { LOCK(cs_wallet); - map::const_iterator mi = mapWallet.find(txin.prevout.hash); + std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.vout.size()) @@ -1098,98 +1087,11 @@ CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const return 0; } -// Recursively determine the rounds of a given input (How deep is the Obfuscation chain for a given input) -int CWallet::GetRealInputObfuscationRounds(CTxIn in, int rounds) const -{ - static std::map mDenomWtxes; - - if (rounds >= 16) return 15; // 16 rounds max - - uint256 hash = in.prevout.hash; - unsigned int nout = in.prevout.n; - - const CWalletTx* wtx = GetWalletTx(hash); - if (wtx != NULL) { - std::map::const_iterator mdwi = mDenomWtxes.find(hash); - // not known yet, let's add it - if (mdwi == mDenomWtxes.end()) { - LogPrint("obfuscation", "GetInputObfuscationRounds INSERTING %s\n", hash.ToString()); - mDenomWtxes[hash] = CMutableTransaction(*wtx); - } - // found and it's not an initial value, just return it - else if (mDenomWtxes[hash].vout[nout].nRounds != -10) { - return mDenomWtxes[hash].vout[nout].nRounds; - } - - - // bounds check - if (nout >= wtx->vout.size()) { - // should never actually hit this - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, -4); - return -4; - } - - if (pwalletMain->IsCollateralAmount(wtx->vout[nout].nValue)) { - mDenomWtxes[hash].vout[nout].nRounds = -3; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - //make sure the final output is non-denominate - if (/*rounds == 0 && */ !IsDenominatedAmount(wtx->vout[nout].nValue)) //NOT DENOM - { - mDenomWtxes[hash].vout[nout].nRounds = -2; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - bool fAllDenoms = true; - BOOST_FOREACH (CTxOut out, wtx->vout) { - fAllDenoms = fAllDenoms && IsDenominatedAmount(out.nValue); - } - // this one is denominated but there is another non-denominated output found in the same tx - if (!fAllDenoms) { - mDenomWtxes[hash].vout[nout].nRounds = 0; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - int nShortest = -10; // an initial value, should be no way to get this by calculations - bool fDenomFound = false; - // only denoms here so let's look up - BOOST_FOREACH (CTxIn in2, wtx->vin) { - if (IsMine(in2)) { - int n = GetRealInputObfuscationRounds(in2, rounds + 1); - // denom found, find the shortest chain or initially assign nShortest with the first found value - if (n >= 0 && (n < nShortest || nShortest == -10)) { - nShortest = n; - fDenomFound = true; - } - } - } - mDenomWtxes[hash].vout[nout].nRounds = fDenomFound ? (nShortest >= 15 ? 16 : nShortest + 1) // good, we a +1 to the shortest one but only 16 rounds max allowed - : - 0; // too bad, we are the fist one in that chain - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - return rounds - 1; -} - -// respect current settings -int CWallet::GetInputObfuscationRounds(CTxIn in) const -{ - LOCK(cs_wallet); - int realObfuscationRounds = GetRealInputObfuscationRounds(in, 0); - return realObfuscationRounds > nZeromintPercentage ? nZeromintPercentage : realObfuscationRounds; -} - bool CWallet::IsDenominated(const CTxIn& txin) const { { LOCK(cs_wallet); - map::const_iterator mi = mapWallet.find(txin.prevout.hash); + std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.vout.size()) return IsDenominatedAmount(prev.vout[txin.prevout.n].nValue); @@ -1198,24 +1100,9 @@ bool CWallet::IsDenominated(const CTxIn& txin) const return false; } -bool CWallet::IsDenominated(const CTransaction& tx) const -{ - /* - Return false if ANY inputs are non-denom - */ - bool ret = true; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { - if (!IsDenominated(txin)) { - ret = false; - } - } - return ret; -} - - bool CWallet::IsDenominatedAmount(CAmount nInputAmount) const { - BOOST_FOREACH (CAmount d, obfuScationDenominations) + for (CAmount d : obfuScationDenominations) if (nInputAmount == d) return true; return false; @@ -1269,19 +1156,19 @@ int CWalletTx::GetRequestCount() const if (IsCoinBase()) { // Generated block if (hashBlock != 0) { - map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + std::map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; } } else { // Did anyone request this transaction? - map::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); + std::map::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; // How about the block it's in? if (nRequests == 0 && hashBlock != 0) { - map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + std::map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; else @@ -1392,73 +1279,6 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const return nCredit; } -CAmount CWalletTx::GetAnonymizableCredit(bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizableCreditCached) - return nAnonymizableCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - const CTxIn vin = CTxIn(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; - if (fMasterNode && vout[i].nValue == 10000 * COIN) continue; // do not count MN-like outputs - - const int rounds = pwallet->GetInputObfuscationRounds(vin); - if (rounds >= -2 && rounds < nZeromintPercentage) { - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetAnonamizableCredit() : value out of range"); - } - } - - nAnonymizableCreditCached = nCredit; - fAnonymizableCreditCached = true; - return nCredit; -} - -CAmount CWalletTx::GetAnonymizedCredit(bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizedCreditCached) - return nAnonymizedCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - const CTxIn vin = CTxIn(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominated(vin)) continue; - - const int rounds = pwallet->GetInputObfuscationRounds(vin); - if (rounds >= nZeromintPercentage) { - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetAnonymizedCredit() : value out of range"); - } - } - - nAnonymizedCreditCached = nCredit; - fAnonymizedCreditCached = true; - return nCredit; -} - // Return sum of unlocked coins CAmount CWalletTx::GetUnlockedCredit() const { @@ -1509,7 +1329,7 @@ CAmount CWalletTx::GetLockedCredit() const } // Add masternode collaterals which are handled likc locked coins - if (fMasterNode && vout[i].nValue == 10000 * COIN) { + else if (fMasterNode && vout[i].nValue == 10000 * COIN) { nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); } @@ -1520,50 +1340,6 @@ CAmount CWalletTx::GetLockedCredit() const return nCredit; } -CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - int nDepth = GetDepthInMainChain(false); - if (nDepth < 0) return 0; - - bool isUnconfirmed = !IsFinalTx(*this) || (!IsTrusted() && nDepth == 0); - if (unconfirmed != isUnconfirmed) return 0; - - if (fUseCache) { - if (unconfirmed && fDenomUnconfCreditCached) - return nDenomUnconfCreditCached; - else if (!unconfirmed && fDenomConfCreditCached) - return nDenomConfCreditCached; - } - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominatedAmount(vout[i].nValue)) continue; - - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetDenominatedCredit() : value out of range"); - } - - if (unconfirmed) { - nDenomUnconfCreditCached = nCredit; - fDenomUnconfCreditCached = true; - } else { - nDenomConfCreditCached = nCredit; - fDenomConfCreditCached = true; - } - return nCredit; -} - CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const { LOCK(cs_main); @@ -1628,7 +1404,7 @@ CAmount CWalletTx::GetLockedWatchOnlyCredit() const } // Add masternode collaterals which are handled likc locked coins - if (fMasterNode && vout[i].nValue == 10000 * COIN) { + else if (fMasterNode && vout[i].nValue == 10000 * COIN) { nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); } @@ -1639,10 +1415,10 @@ CAmount CWalletTx::GetLockedWatchOnlyCredit() const return nCredit; } -void CWalletTx::GetAmounts(list& listReceived, - list& listSent, +void CWalletTx::GetAmounts(std::list& listReceived, + std::list& listSent, CAmount& nFee, - string& strSentAccount, + std::string& strSentAccount, const isminefilter& filter) const { nFee = 0; @@ -1695,26 +1471,26 @@ void CWalletTx::GetAmounts(list& listReceived, } } -void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, CAmount& nSent, CAmount& nFee, const isminefilter& filter) const +void CWalletTx::GetAccountAmounts(const std::string& strAccount, CAmount& nReceived, CAmount& nSent, CAmount& nFee, const isminefilter& filter) const { nReceived = nSent = nFee = 0; CAmount allFee; - string strSentAccount; - list listReceived; - list listSent; + std::string strSentAccount; + std::list listReceived; + std::list listSent; GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (strAccount == strSentAccount) { - BOOST_FOREACH (const COutputEntry& s, listSent) + for (const COutputEntry& s : listSent) nSent += s.amount; nFee = allFee; } { LOCK(pwallet->cs_wallet); - BOOST_FOREACH (const COutputEntry& r, listReceived) { + for (const COutputEntry& r : listReceived) { if (pwallet->mapAddressBook.count(r.destination)) { - map::const_iterator mi = pwallet->mapAddressBook.find(r.destination); + std::map::const_iterator mi = pwallet->mapAddressBook.find(r.destination); if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount) nReceived += r.amount; } else if (strAccount.empty()) { @@ -1756,21 +1532,21 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup double dProgressStart = Checkpoints::GuessVerificationProgress(pindex, false); double dProgressTip = Checkpoints::GuessVerificationProgress(chainActive.Tip(), false); - set setAddedToWallet; + std::set setAddedToWallet; while (pindex) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; ReadBlockFromDisk(block, pindex); - BOOST_FOREACH (CTransaction& tx, block.vtx) { + for (CTransaction& tx : block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) ret++; } //If this is a zapwallettx, need to readd zphr if (fCheckZPHR && pindex->nHeight >= Params().Zerocoin_StartHeight()) { - list listMints; + std::list listMints; BlockToZerocoinMintList(block, listMints); for (auto& m : listMints) { @@ -1828,7 +1604,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) void CWallet::ReacceptWalletTransactions() { LOCK2(cs_main, cs_wallet); - BOOST_FOREACH (PAIRTYPE(const uint256, CWalletTx) & item, mapWallet) { + for (PAIRTYPE(const uint256, CWalletTx) & item : mapWallet) { const uint256& wtxid = item.first; CWalletTx& wtx = item.second; assert(wtx.GetHash() == wtxid); @@ -1861,7 +1637,7 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand) LogPrintf("Relaying wtx %s\n", hash.ToString()); if (strCommand == NetMsgType::IX) { - mapTxLockReq.insert(make_pair(hash, (CTransaction) * this)); + mapTxLockReq.insert(std::make_pair(hash, (CTransaction) * this)); CreateNewLock(((CTransaction) * this)); RelayTransactionLockReq((CTransaction) * this, true); } else { @@ -1871,9 +1647,9 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand) } } -set CWalletTx::GetConflicts() const +std::set CWalletTx::GetConflicts() const { - set result; + std::set result; if (pwallet != NULL) { uint256 myHash = GetHash(); result = pwallet->GetConflicts(myHash); @@ -1903,15 +1679,15 @@ void CWallet::ResendWalletTransactions() { LOCK(cs_wallet); // Sort them in chronological order - multimap mapSorted; - BOOST_FOREACH (PAIRTYPE(const uint256, CWalletTx) & item, mapWallet) { + std::multimap mapSorted; + for (PAIRTYPE(const uint256, CWalletTx) & item : mapWallet) { CWalletTx& wtx = item.second; // Don't rebroadcast until it's had plenty of time that // it should have gotten in already by now. if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) - mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); + mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx)); } - BOOST_FOREACH (PAIRTYPE(const unsigned int, CWalletTx*) & item, mapSorted) { + for (PAIRTYPE(const unsigned int, CWalletTx*) & item : mapSorted) { CWalletTx& wtx = *item.second; wtx.RelayWalletTransaction(); } @@ -1931,7 +1707,7 @@ CAmount CWallet::GetBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) nTotal += pcoin->GetAvailableCredit(); @@ -1950,7 +1726,7 @@ CAmount CWallet::GetZerocoinBalance(bool fMatureOnly) const mapMintMaturity = GetMintMaturityHeight(); nLastMaturityCheck = chainActive.Height(); CAmount nBalance = 0; - vector vMints = zphrTracker->GetMints(true); + std::vector vMints = zphrTracker->GetMints(true); for (auto meta : vMints) { if (meta.nHeight >= mapMintMaturity.at(meta.denom) || meta.nHeight >= chainActive.Height() || meta.nHeight == 0) continue; @@ -1978,7 +1754,7 @@ CAmount CWallet::GetUnlockedCoins() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted() && pcoin->GetDepthInMainChain() > 0) @@ -1996,7 +1772,7 @@ CAmount CWallet::GetLockedCoins() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted() && pcoin->GetDepthInMainChain() > 0) @@ -2015,7 +1791,7 @@ std::map CWallet::GetMyZerocoinDistribut spread.insert(std::pair(denom, 0)); { LOCK(cs_wallet); - set setMints = zphrTracker->ListMints(true, true, true); + std::set setMints = zphrTracker->ListMints(true, true, true); for (auto& mint : setMints) spread.at(mint.denom)++; } @@ -2023,128 +1799,12 @@ std::map CWallet::GetMyZerocoinDistribut } -CAmount CWallet::GetAnonymizableBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - if (pcoin->IsTrusted()) - nTotal += pcoin->GetAnonymizableCredit(); - } - } - - return nTotal; -} - -CAmount CWallet::GetAnonymizedBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - if (pcoin->IsTrusted()) - nTotal += pcoin->GetAnonymizedCredit(); - } - } - - return nTotal; -} - -// Note: calculated including unconfirmed, -// that's ok as long as we use it for informational purposes only -double CWallet::GetAverageAnonymizedRounds() const -{ - if (fLiteMode) return 0; - - double fTotal = 0; - double fCount = 0; - - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - uint256 hash = (*it).first; - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxIn vin = CTxIn(hash, i); - - if (IsSpent(hash, i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - - int rounds = GetInputObfuscationRounds(vin); - fTotal += (float)rounds; - fCount += 1; - } - } - } - - if (fCount == 0) return 0; - - return fTotal / fCount; -} - -// Note: calculated including unconfirmed, -// that's ok as long as we use it for informational purposes only -CAmount CWallet::GetNormalizedAnonymizedBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - uint256 hash = (*it).first; - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxIn vin = CTxIn(hash, i); - - if (IsSpent(hash, i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - if (pcoin->GetDepthInMainChain() < 0) continue; - - int rounds = GetInputObfuscationRounds(vin); - nTotal += pcoin->vout[i].nValue * rounds / nZeromintPercentage; - } - } - } - - return nTotal; -} - -CAmount CWallet::GetDenominatedBalance(bool unconfirmed) const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - nTotal += pcoin->GetDenominatedCredit(unconfirmed); - } - } - - return nTotal; -} - CAmount CWallet::GetUnconfirmedBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) nTotal += pcoin->GetAvailableCredit(); @@ -2158,7 +1818,7 @@ CAmount CWallet::GetImmatureBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureCredit(); } @@ -2171,7 +1831,7 @@ CAmount CWallet::GetWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) nTotal += pcoin->GetAvailableWatchOnlyCredit(); @@ -2186,7 +1846,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) nTotal += pcoin->GetAvailableWatchOnlyCredit(); @@ -2200,7 +1860,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureWatchOnlyCredit(); } @@ -2213,7 +1873,7 @@ CAmount CWallet::GetLockedWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted() && pcoin->GetDepthInMainChain() > 0) nTotal += pcoin->GetLockedWatchOnlyCredit(); @@ -2225,13 +1885,13 @@ CAmount CWallet::GetLockedWatchOnlyBalance() const /** * populate vCoins with vector of available COutputs. */ -void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl* coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseIX, int nWatchonlyConfig) const +void CWallet::AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed, const CCoinControl* coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseIX, int nWatchonlyConfig) const { vCoins.clear(); { LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const uint256& wtxid = it->first; const CWalletTx* pcoin = &(*it).second; @@ -2304,13 +1964,13 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const } } -map > CWallet::AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue) +std::map > CWallet::AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue) { - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, fConfirmed); - map > mapCoins; - BOOST_FOREACH (COutput out, vCoins) { + std::map > mapCoins; + for (COutput out : vCoins) { if (maxCoinValue > 0 && out.tx->vout[out.i].nValue > maxCoinValue) continue; @@ -2324,9 +1984,9 @@ map > CWallet::AvailableCoinsByAddress(bool fCon return mapCoins; } -static void ApproximateBestSubset(vector > > vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, vector& vfBest, CAmount& nBest, int iterations = 1000) +static void ApproximateBestSubset(std::vector > > vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, std::vector& vfBest, CAmount& nBest, int iterations = 1000) { - vector vfIncluded; + std::vector vfIncluded; vfBest.assign(vValue.size(), true); nBest = nTotalLower; @@ -2373,7 +2033,7 @@ bool less_then_denom(const COutput& out1, const COutput& out2) bool found1 = false; bool found2 = false; - BOOST_FOREACH (CAmount d, obfuScationDenominations) // loop through predefined denoms + for (CAmount d : obfuScationDenominations) // loop through predefined denoms { if (pcoin1->vout[out1.i].nValue == d) found1 = true; if (pcoin2->vout[out2.i].nValue == d) found2 = true; @@ -2385,7 +2045,7 @@ bool CWallet::SelectStakeCoins(std::set vCoins; + std::vector vCoins; AvailableCoins(vCoins, true, NULL, false, STAKABLE_COINS); CAmount nAmountSelected = 0; @@ -2411,7 +2071,7 @@ bool CWallet::SelectStakeCoins(std::setvout[out.i].nValue; } return true; @@ -2426,7 +2086,7 @@ bool CWallet::MintableCoins() if (nBalance <= nReserveBalance) return false; - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, true); for (const COutput& out : vCoins) { @@ -2444,29 +2104,29 @@ bool CWallet::MintableCoins() return false; } -bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector vCoins, set >& setCoinsRet, CAmount& nValueRet) const +bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target - pair > coinLowestLarger; + std::pair > coinLowestLarger; coinLowestLarger.first = std::numeric_limits::max(); coinLowestLarger.second.first = NULL; - vector > > vValue; + std::vector > > vValue; CAmount nTotalLower = 0; random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); // move denoms down on the list - sort(vCoins.begin(), vCoins.end(), less_then_denom); + std::sort(vCoins.begin(), vCoins.end(), less_then_denom); // try to find nondenom first to prevent unneeded spending of mixed coins for (unsigned int tryDenom = 0; tryDenom < 2; tryDenom++) { if (fDebug) LogPrint("selectcoins", "tryDenom: %d\n", tryDenom); vValue.clear(); nTotalLower = 0; - BOOST_FOREACH (const COutput& output, vCoins) { + for (const COutput& output : vCoins) { if (!output.fSpendable) continue; @@ -2480,7 +2140,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int CAmount n = pcoin->vout[i].nValue; if (tryDenom == 0 && IsDenominatedAmount(n)) continue; // we don't want denom values on first run - pair > coin = make_pair(n, make_pair(pcoin, i)); + std::pair > coin = std::make_pair(n, std::make_pair(pcoin, i)); if (n == nTargetValue) { setCoinsRet.insert(coin.second); @@ -2522,8 +2182,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int } // Solve subset sum by stochastic approximation - sort(vValue.rbegin(), vValue.rend(), CompareValueOnly()); - vector vfBest; + std::sort(vValue.rbegin(), vValue.rend(), CompareValueOnly()); + std::vector vfBest; CAmount nBest; ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000); @@ -2537,7 +2197,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int setCoinsRet.insert(coinLowestLarger.second); nValueRet += coinLowestLarger.first; } else { - string s = "CWallet::SelectCoinsMinConf best subset: "; + std::string s = "CWallet::SelectCoinsMinConf best subset: "; for (unsigned int i = 0; i < vValue.size(); i++) { if (vfBest[i]) { setCoinsRet.insert(vValue[i].second); @@ -2551,48 +2211,21 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int return true; } -bool CWallet::SelectCoins(const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX) const +bool CWallet::SelectCoins(const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX) const { // Note: this function should never be used for "always free" tx types like dstx - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, true, coinControl, false, coin_type, useIX); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected()) { - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { if (!out.fSpendable) continue; - if (coin_type == ONLY_DENOMINATED) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - int rounds = GetInputObfuscationRounds(vin); - // make sure it's actually anonymized - if (rounds < nZeromintPercentage) continue; - } - nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.insert(make_pair(out.tx, out.i)); - } - return (nValueRet >= nTargetValue); - } - - //if we're doing only denominated, we need to round up to the nearest .1 PHR - if (coin_type == ONLY_DENOMINATED) { - // Make outputs by looping through denominations, from large to small - BOOST_FOREACH (CAmount v, obfuScationDenominations) { - BOOST_FOREACH (const COutput& out, vCoins) { - if (out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for - && nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1 * COIN) + 100 //round the amount up to .1 PHR over - ) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - int rounds = GetInputObfuscationRounds(vin); - // make sure it's actually anonymized - if (rounds < nZeromintPercentage) continue; - nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.insert(make_pair(out.tx, out.i)); - } - } + setCoinsRet.insert(std::make_pair(out.tx, out.i)); } return (nValueRet >= nTargetValue); } @@ -2602,292 +2235,11 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set t2.Priority(); - } -}; - -bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) -{ - vCoinsRet.clear(); - nValueRet = 0; - - vCoinsRet2.clear(); - vector vCoins; - AvailableCoins(vCoins, true, NULL, false, ONLY_DENOMINATED); - - std::random_shuffle(vCoins.rbegin(), vCoins.rend()); - - //keep track of each denomination that we have - bool fFound10000 = false; - bool fFound1000 = false; - bool fFound100 = false; - bool fFound10 = false; - bool fFound1 = false; - bool fFoundDot1 = false; - - //Check to see if any of the denomination are off, in that case mark them as fulfilled - if (!(nDenom & (1 << 0))) fFound10000 = true; - if (!(nDenom & (1 << 1))) fFound1000 = true; - if (!(nDenom & (1 << 2))) fFound100 = true; - if (!(nDenom & (1 << 3))) fFound10 = true; - if (!(nDenom & (1 << 4))) fFound1 = true; - if (!(nDenom & (1 << 5))) fFoundDot1 = true; - - BOOST_FOREACH (const COutput& out, vCoins) { - // masternode-like input should not be selected by AvailableCoins now anyway - //if(out.tx->vout[out.i].nValue == 10000*COIN) continue; - if (nValueRet + out.tx->vout[out.i].nValue <= nValueMax) { - bool fAccepted = false; - - // Function returns as follows: - // - // bit 0 - 10000 PHR+1 ( bit on if present ) - // bit 1 - 1000 PHR+1 - // bit 2 - 100 PHR+1 - // bit 3 - 10 PHR+1 - // bit 4 - 1 PHR+1 - // bit 5 - .1 PHR+1 - - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - int rounds = GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRoundsMax) continue; - if (rounds < nObfuscationRoundsMin) continue; - - if (fFound10000 && fFound1000 && fFound100 && fFound10 && fFound1 && fFoundDot1) { //if fulfilled - //we can return this for submission - if (nValueRet >= nValueMin) { - //random reduce the max amount we'll submit for anonymity - nValueMax -= (rand() % (nValueMax / 5)); - //on average use 50% of the inputs or less - int r = (rand() % (int)vCoins.size()); - if ((int)vCoinsRet.size() > r) return true; - } - //Denomination criterion has been met, we can take any matching denominations - if ((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((10000 * COIN) + 10000000)) { - fAccepted = true; - } else if ((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((1000 * COIN) + 1000000)) { - fAccepted = true; - } else if ((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((nDenom & (1 << 4)) && out.tx->vout[out.i].nValue == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((nDenom & (1 << 5)) && out.tx->vout[out.i].nValue == ((.1 * COIN) + 100)) { - fAccepted = true; - } - } else { - //Criterion has not been satisfied, we will only take 1 of each until it is. - if ((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((10000 * COIN) + 10000000)) { - fAccepted = true; - fFound10000 = true; - } else if ((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((1000 * COIN) + 1000000)) { - fAccepted = true; - fFound1000 = true; - } else if ((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((100 * COIN) + 100000)) { - fAccepted = true; - fFound100 = true; - } else if ((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((10 * COIN) + 10000)) { - fAccepted = true; - fFound10 = true; - } else if ((nDenom & (1 << 4)) && out.tx->vout[out.i].nValue == ((1 * COIN) + 1000)) { - fAccepted = true; - fFound1 = true; - } else if ((nDenom & (1 << 5)) && out.tx->vout[out.i].nValue == ((.1 * COIN) + 100)) { - fAccepted = true; - fFoundDot1 = true; - } - } - if (!fAccepted) continue; - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += out.tx->vout[out.i].nValue; - vCoinsRet.push_back(vin); - vCoinsRet2.push_back(out); - } - } - - return (nValueRet >= nValueMin && fFound10000 && fFound1000 && fFound100 && fFound10 && fFound1 && fFoundDot1); -} - -bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& setCoinsRet, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) const -{ - CCoinControl* coinControl = NULL; - - setCoinsRet.clear(); - nValueRet = 0; - - vector vCoins; - AvailableCoins(vCoins, true, coinControl, false, nObfuscationRoundsMin < 0 ? ONLY_NONDENOMINATED_NOT10000IFMN : ONLY_DENOMINATED); - - set > setCoinsRet2; - - //order the array so largest nondenom are first, then denominations, then very small inputs. - sort(vCoins.rbegin(), vCoins.rend(), CompareByPriority()); - - BOOST_FOREACH (const COutput& out, vCoins) { - //do not allow inputs less than 1 CENT - if (out.tx->vout[out.i].nValue < CENT) continue; - //do not allow collaterals to be selected - if (IsCollateralAmount(out.tx->vout[out.i].nValue)) continue; - if (fMasterNode && out.tx->vout[out.i].nValue == 10000 * COIN) continue; //masternode input - - if (nValueRet + out.tx->vout[out.i].nValue <= nValueMax) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - int rounds = GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRoundsMax) continue; - if (rounds < nObfuscationRoundsMin) continue; - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.push_back(vin); - setCoinsRet2.insert(make_pair(out.tx, out.i)); - } - } - - // if it's more than min, we're good to return - if (nValueRet >= nValueMin) return true; - - return false; -} - -bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) const -{ - vector vCoins; - - //LogPrintf(" selecting coins for collateral\n"); - AvailableCoins(vCoins); - - //LogPrintf("found coins %d\n", (int)vCoins.size()); - - - BOOST_FOREACH (const COutput& out, vCoins) { - // collateral inputs will always be a multiple of DARSEND_COLLATERAL, up to five - if (IsCollateralAmount(out.tx->vout[out.i].nValue)) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += out.tx->vout[out.i].nValue; - - CTxPair txPair; - txPair.prevout = out.tx->vout[out.i]; - txPair.vin = vin; - - setCoinsRet.push_back(txPair); - return true; - } - } - - return false; -} - -int CWallet::CountInputsWithAmount(CAmount nInputAmount) -{ - CAmount nTotal = 0; - { - LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - if (pcoin->IsTrusted()) { - int nDepth = pcoin->GetDepthInMainChain(false); - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - COutput out = COutput(pcoin, i, nDepth, true); - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - if (out.tx->vout[out.i].nValue != nInputAmount) continue; - if (!IsDenominatedAmount(pcoin->vout[i].nValue)) continue; - if (IsSpent(out.tx->GetHash(), i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - - nTotal++; - } - } - } - } - - return nTotal; -} - -bool CWallet::HasCollateralInputs(bool fOnlyConfirmed) const -{ - vector vCoins; - AvailableCoins(vCoins, fOnlyConfirmed); - - int nFound = 0; - BOOST_FOREACH (const COutput& out, vCoins) - if (IsCollateralAmount(out.tx->vout[out.i].nValue)) nFound++; - - return nFound > 0; -} - bool CWallet::IsCollateralAmount(CAmount nInputAmount) const { return nInputAmount != 0 && nInputAmount % OBFUSCATION_COLLATERAL == 0 && nInputAmount < OBFUSCATION_COLLATERAL * 5 && nInputAmount > OBFUSCATION_COLLATERAL; } -bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason) -{ - /* - To doublespend a collateral transaction, it will require a fee higher than this. So there's - still a significant cost. - */ - CAmount nFeeRet = 1 * COIN; - - txCollateral.vin.clear(); - txCollateral.vout.clear(); - - CReserveKey reservekey(this); - CAmount nValueIn2 = 0; - std::vector vCoinsCollateral; - - if (!SelectCoinsCollateral(vCoinsCollateral, nValueIn2)) { - strReason = "Error: Obfuscation requires a collateral transaction and could not locate an acceptable input!"; - return false; - } - - // make our change address - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey, false)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey.GetID()); - reservekey.KeepKey(); - - if (nValueIn2 - OBFUSCATION_COLLATERAL - nFeeRet > 0) { - //pay collateral charge in fees - CTxOut vout3 = CTxOut(nValueIn2 - OBFUSCATION_COLLATERAL, scriptChange); - txCollateral.vout.push_back(vout3); - } - - int vinNumber = 0; - bool success = true; - BOOST_FOREACH (CTxPair v, vCoinsCollateral) { - txCollateral.vin.push_back(v.vin); - if (!SignSignature(*this, v.vin.prevPubKey, txCollateral, vinNumber, v.prevout.nValue, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { - success = false; - break; - } - vinNumber++; - } - - // if signing was not successful, unlock the inputs - if (!success) { - BOOST_FOREACH (CTxPair v, vCoinsCollateral) - UnlockCoin(v.vin.prevout); - - strReason = "CObfuscationPool::Sign - Unable to sign collateral transaction! \n"; - return false; - } - - return success; -} - - bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX) { // make our change address @@ -2898,8 +2250,8 @@ bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useI CAmount nFeeRet = 0; std::string strFail = ""; - vector > vecSend; - vecSend.push_back(make_pair(scriptChange, GetBudgetSystemCollateralAmount(chainActive.Height()))); // Old 50 PHR collateral + std::vector > vecSend; + vecSend.push_back(std::make_pair(scriptChange, GetBudgetSystemCollateralAmount(chainActive.Height()))); // Old 50 PHR collateral CCoinControl* coinControl = NULL; bool success = CreateTransaction(vecSend, tx, reservekey, nFeeRet, strFail, coinControl, ALL_COINS, useIX, (CAmount)0); @@ -2911,23 +2263,7 @@ bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useI return true; } - -bool CWallet::ConvertList(std::vector vCoins, std::vector& vecAmounts) -{ - BOOST_FOREACH (CTxIn i, vCoins) { - if (mapWallet.count(i.prevout.hash)) { - CWalletTx& wtx = mapWallet[i.prevout.hash]; - if (i.prevout.n < wtx.vout.size()) { - vecAmounts.push_back(wtx.vout[i.prevout.n].nValue); - } - } else { - LogPrintf("ConvertList -- Couldn't find transaction\n"); - } - } - return true; -} - -bool CWallet::CreateTransaction(const vector >& vecSend, +bool CWallet::CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, @@ -2941,7 +2277,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CAmount nValue = 0; - BOOST_FOREACH (const PAIRTYPE(CScript, CAmount) & s, vecSend) { + for (const PAIRTYPE(CScript, CAmount) & s : vecSend) { if (nValue < 0) { strFailReason = _("Transaction amounts must be positive"); return false; @@ -2975,7 +2311,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, // vouts to the payees if (coinControl && !coinControl->fSplitBlock) { - BOOST_FOREACH (const PAIRTYPE(CScript, CAmount) & s, vecSend) { + for (const PAIRTYPE(CScript, CAmount) & s : vecSend) { CTxOut txout(s.second, s.first); if (txout.IsDust(::minRelayTxFee)) { strFailReason = _("Transaction amount too small"); @@ -2992,7 +2328,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, else nSplitBlock = 1; - BOOST_FOREACH (const PAIRTYPE(CScript, CAmount) & s, vecSend) { + for (const PAIRTYPE(CScript, CAmount) & s : vecSend) { for (int i = 0; i < nSplitBlock; i++) { if (i == nSplitBlock - 1) { uint64_t nRemainder = s.second % nSplitBlock; @@ -3004,7 +2340,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } // Choose coins to use - set > setCoins; + std::set > setCoins; CAmount nValueIn = 0; if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX)) { @@ -3027,7 +2363,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } - BOOST_FOREACH (PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { + for (PAIRTYPE(const CWalletTx*, unsigned int) pcoin : setCoins) { CAmount nCredit = pcoin.first->vout[pcoin.second].nValue; //The coin age after the next block (depth+1) is used instead of the current, //reflecting an assumption the user would accept a bit more delay for @@ -3059,7 +2395,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, if (coinControl && !boost::get(&coinControl->destChange)) { scriptChange = GetScriptForDestination(coinControl->destChange); - vector::iterator it = txNew.vout.begin(); + std::vector::iterator it = txNew.vout.begin(); while (it != txNew.vout.end()) { if (scriptChange == it->scriptPubKey) { it->nValue += nChange; @@ -3101,7 +2437,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, reservekey.ReturnKey(); } else { // Insert change txn at random position: - vector::iterator position = txNew.vout.begin() + GetRandInt(txNew.vout.size() + 1); + std::vector::iterator position = txNew.vout.begin() + GetRandInt(txNew.vout.size() + 1); txNew.vout.insert(position, newTxOut); } } @@ -3109,13 +2445,13 @@ bool CWallet::CreateTransaction(const vector >& vecSend, reservekey.ReturnKey(); // Fill vin - BOOST_FOREACH (const PAIRTYPE(const CWalletTx*, unsigned int) & coin, setCoins) + for (const PAIRTYPE(const CWalletTx*, unsigned int) & coin : setCoins) txNew.vin.push_back(CTxIn(coin.first->GetHash(), coin.second)); // Sign int nIn = 0; CTransaction txNewConst(txNew); - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) + for (const PAIRTYPE(const CWalletTx*,unsigned int)& coin : setCoins) { const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; SignatureData sigdata; @@ -3156,7 +2492,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, break; } - CAmount nFeeNeeded = max(nFeePay, GetMinimumFee(nBytes, nTxConfirmTarget, mempool)); + CAmount nFeeNeeded = std::max(nFeePay, GetMinimumFee(nBytes, nTxConfirmTarget, mempool)); // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. @@ -3179,8 +2515,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, bool CWallet::CreateTransaction(CScript scriptPubKey, const CAmount& nValue, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX, CAmount nFeePay) { - vector > vecSend; - vecSend.push_back(make_pair(scriptPubKey, nValue)); + std::vector > vecSend; + vecSend.push_back(std::make_pair(scriptPubKey, nValue)); return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason, coinControl, coin_type, useIX, nFeePay); } @@ -3209,7 +2545,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int return false; // presstab HyperStake - Initialize as static and don't update the set on every run of CreateCoinStake() in order to lighten resource use - static std::set > setStakeCoins; + static std::set > setStakeCoins; static int nLastStakeSetUpdate = 0; if (GetTime() - nLastStakeSetUpdate > nStakeSetUpdateTime) { @@ -3226,7 +2562,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int return false; } - vector vwtxPrev; + std::vector vwtxPrev; CAmount nCredit = 0; CScript scriptPubKeyKernel; @@ -3236,7 +2572,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (GetAdjustedTime() <= chainActive.Tip()->nTime) MilliSleep(10000); - BOOST_FOREACH (PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setStakeCoins) { + for (PAIRTYPE(const CWalletTx*, unsigned int) pcoin : setStakeCoins) { //make sure that enough time has elapsed between CBlockIndex* pindex = NULL; BlockMap::iterator it = mapBlockIndex.find(pcoin.first->hashBlock); @@ -3267,7 +2603,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (fDebug && GetBoolArg("-printcoinstake", false)) LogPrintf("CreateCoinStake : kernel found\n"); - vector vSolutions; + std::vector vSolutions; txnouttype whichType; CScript scriptPubKeyOut; scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey; @@ -3286,7 +2622,8 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int { //convert to pay to public key type CKey key; - if (!keystore.GetKey(uint160(vSolutions[0]), key)) { + CKeyID keyID = CKeyID(uint160(vSolutions[0])); + if (!keystore.GetKey(keyID, key)) { if (fDebug && GetBoolArg("-printcoinstake", false)) LogPrintf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key @@ -3358,7 +2695,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int // Sign int nIn = 0; - BOOST_FOREACH (const CWalletTx* pcoin, vwtxPrev) { + for (const CWalletTx* pcoin : vwtxPrev) { if (!SignSignature(*this, *pcoin, txNew, nIn++, SIGHASH_ALL)) return error("CreateCoinStake : failed to sign coinstake"); } @@ -3394,8 +2731,8 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std: // Notify that old coins are spent if (!wtxNew.IsZerocoinSpend()) { - set updated_hahes; - BOOST_FOREACH (const CTxIn& txin, wtxNew.vin) { + std::set updated_hahes; + for (const CTxIn& txin : wtxNew.vin) { // notify only once if (updated_hahes.find(txin.prevout.hash) != updated_hahes.end()) continue; @@ -3431,7 +2768,7 @@ bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pw laccentries.push_back(acentry); CAccountingEntry & entry = laccentries.back(); - wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); return true; } @@ -3459,154 +2796,6 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge return nFeeNeeded; } -CAmount CWallet::GetTotalValue(std::vector vCoins) -{ - CAmount nTotalValue = 0; - CWalletTx wtx; - BOOST_FOREACH (CTxIn i, vCoins) { - if (mapWallet.count(i.prevout.hash)) { - CWalletTx& wtx = mapWallet[i.prevout.hash]; - if (i.prevout.n < wtx.vout.size()) { - nTotalValue += wtx.vout[i.prevout.n].nValue; - } - } else { - LogPrintf("GetTotalValue -- Couldn't find transaction\n"); - } - } - return nTotalValue; -} - -string CWallet::PrepareObfuscationDenominate(int minRounds, int maxRounds) -{ - if (IsLocked()) - return _("Error: Wallet locked, unable to create transaction!"); - - if (obfuScationPool.GetState() != POOL_STATUS_ERROR && obfuScationPool.GetState() != POOL_STATUS_SUCCESS) - if (obfuScationPool.GetEntriesCount() > 0) - return _("Error: You already have pending entries in the Obfuscation pool"); - - // ** find the coins we'll use - std::vector vCoins; - std::vector vCoinsResult; - std::vector vCoins2; - CAmount nValueIn = 0; - CReserveKey reservekey(this); - - /* - Select the coins we'll use - - if minRounds >= 0 it means only denominated inputs are going in and coming out - */ - if (minRounds >= 0) { - if (!SelectCoinsByDenominations(obfuScationPool.sessionDenom, 0.1 * COIN, OBFUSCATION_POOL_MAX, vCoins, vCoins2, nValueIn, minRounds, maxRounds)) - return _("Error: Can't select current denominated inputs"); - } - - LogPrintf("PrepareObfuscationDenominate - preparing obfuscation denominate . Got: %d \n", nValueIn); - - { - LOCK(cs_wallet); - BOOST_FOREACH (CTxIn v, vCoins) - LockCoin(v.prevout); - } - - CAmount nValueLeft = nValueIn; - std::vector vOut; - - /* - TODO: Front load with needed denominations (e.g. .1, 1 ) - */ - - // Make outputs by looping through denominations: try to add every needed denomination, repeat up to 5-10 times. - // This way we can be pretty sure that it should have at least one of each needed denomination. - // NOTE: No need to randomize order of inputs because they were - // initially shuffled in CWallet::SelectCoinsByDenominations already. - int nStep = 0; - int nStepsMax = 5 + GetRandInt(5); - while (nStep < nStepsMax) { - BOOST_FOREACH (CAmount v, obfuScationDenominations) { - // only use the ones that are approved - bool fAccepted = false; - if ((obfuScationPool.sessionDenom & (1 << 0)) && v == ((10000 * COIN) + 10000000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 1)) && v == ((1000 * COIN) + 1000000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 2)) && v == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 3)) && v == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 4)) && v == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 5)) && v == ((.1 * COIN) + 100)) { - fAccepted = true; - } - if (!fAccepted) continue; - - // try to add it - if (nValueLeft - v >= 0) { - // Note: this relies on a fact that both vectors MUST have same size - std::vector::iterator it = vCoins.begin(); - std::vector::iterator it2 = vCoins2.begin(); - while (it2 != vCoins2.end()) { - // we have matching inputs - if ((*it2).tx->vout[(*it2).i].nValue == v) { - // add new input in resulting vector - vCoinsResult.push_back(*it); - // remove corresponting items from initial vectors - vCoins.erase(it); - vCoins2.erase(it2); - - CScript scriptChange; - CPubKey vchPubKey; - // use a unique change address - assert(reservekey.GetReservedKey(vchPubKey, true)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey.GetID()); - reservekey.KeepKey(); - - // add new output - CTxOut o(v, scriptChange); - vOut.push_back(o); - - // subtract denomination amount - nValueLeft -= v; - - break; - } - ++it; - ++it2; - } - } - } - - nStep++; - - if (nValueLeft == 0) break; - } - - { - // unlock unused coins - LOCK(cs_wallet); - BOOST_FOREACH (CTxIn v, vCoins) - UnlockCoin(v.prevout); - } - - if (obfuScationPool.GetDenominations(vOut) != obfuScationPool.sessionDenom) { - // unlock used coins on failure - LOCK(cs_wallet); - BOOST_FOREACH (CTxIn v, vCoinsResult) - UnlockCoin(v.prevout); - return "Error: can't make current denominated outputs"; - } - - // randomize the output order - std::random_shuffle(vOut.begin(), vOut.end()); - - // We also do not care about full amount as long as we have right denominations, just pass what we found - obfuScationPool.SendObfuscationDenominate(vCoinsResult, vOut, nValueIn - nValueLeft); - - return ""; -} - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) @@ -3654,7 +2843,7 @@ DBErrors CWallet::ZapWalletTx(std::vector& vWtx) return DB_LOAD_OK; } -bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) +bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose) { bool fUpdated = false; { @@ -3682,7 +2871,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address) if (fFileBacked) { // Delete destdata tuples associated with address std::string strAddress = EncodeDestination(address); - BOOST_FOREACH (const PAIRTYPE(string, string) & item, mapAddressBook[address].destdata) { + for (const PAIRTYPE(std::string, std::string) & item : mapAddressBook[address].destdata) { CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); } } @@ -3759,7 +2948,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) if (kpSize > 0) nTargetSize = kpSize; else - nTargetSize = max(GetArg("-keypool", 1000), (int64_t)0); + nTargetSize = std::max(GetArg("-keypool", 1000), (int64_t)0); // count amount of available keys (internal, external) // make sure the keypool of external and internal keys fits the user selected target (-keypool) @@ -3790,7 +2979,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) } // TODO: implement keypools for all accounts? if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(0, fInternal), fInternal))) - throw runtime_error("TopUpKeyPool() : writing generated key failed"); + throw std::runtime_error("TopUpKeyPool() : writing generated key failed"); if (fInternal) { setInternalKeyPool.insert(nEnd); } else { @@ -3914,11 +3103,11 @@ int64_t CWallet::GetOldestKeyPoolTime() std::map CWallet::GetAddressBalances() { - map balances; + std::map balances; { LOCK(cs_wallet); - BOOST_FOREACH (PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { + for (PAIRTYPE(uint256, CWalletTx) walletEntry : mapWallet) { CWalletTx* pcoin = &walletEntry.second; if (!IsFinalTx(*pcoin) || !pcoin->IsTrusted()) @@ -3950,19 +3139,19 @@ std::map CWallet::GetAddressBalances() return balances; } -set > CWallet::GetAddressGroupings() +std::set > CWallet::GetAddressGroupings() { AssertLockHeld(cs_wallet); // mapWallet - set > groupings; - set grouping; + std::set > groupings; + std::set grouping; - BOOST_FOREACH (PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { + for (PAIRTYPE(uint256, CWalletTx) walletEntry : mapWallet) { CWalletTx* pcoin = &walletEntry.second; if (pcoin->vin.size() > 0) { bool any_mine = false; // group all input addresses with each other - BOOST_FOREACH (CTxIn txin, pcoin->vin) { + for (CTxIn txin : pcoin->vin) { CTxDestination address; if (!IsMine(txin)) /* If this input isn't mine, ignore it */ continue; @@ -3974,7 +3163,7 @@ set > CWallet::GetAddressGroupings() // group change with input addresses if (any_mine) { - BOOST_FOREACH (CTxOut txout, pcoin->vout) + for (CTxOut txout : pcoin->vout) if (IsChange(txout)) { CTxDestination txoutAddr; if (!ExtractDestination(txout.scriptPubKey, txoutAddr)) @@ -4000,19 +3189,19 @@ set > CWallet::GetAddressGroupings() } } - set*> uniqueGroupings; // a set of pointers to groups of addresses - map*> setmap; // map addresses to the unique group containing it - BOOST_FOREACH (set grouping, groupings) { + std::set*> uniqueGroupings; // a set of pointers to groups of addresses + std::map*> setmap; // map addresses to the unique group containing it + for (std::set grouping : groupings) { // make a set of all the groups hit by this new group - set*> hits; - map*>::iterator it; - BOOST_FOREACH (CTxDestination address, grouping) + std::set*> hits; + std::map*>::iterator it; + for (CTxDestination address : grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); // merge all hit groups into a new single group and delete old groups - set* merged = new set(grouping); - BOOST_FOREACH (set* hit, hits) { + std::set* merged = new std::set(grouping); + for (std::set* hit : hits) { merged->insert(hit->begin(), hit->end()); uniqueGroupings.erase(hit); delete hit; @@ -4020,12 +3209,12 @@ set > CWallet::GetAddressGroupings() uniqueGroupings.insert(merged); // update setmap - BOOST_FOREACH (CTxDestination element, *merged) + for (CTxDestination element : *merged) setmap[element] = merged; } - set > ret; - BOOST_FOREACH (set* uniqueGrouping, uniqueGroupings) { + std::set > ret; + for (std::set* uniqueGrouping : uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; } @@ -4033,13 +3222,13 @@ set > CWallet::GetAddressGroupings() return ret; } -set CWallet::GetAccountAddresses(string strAccount) const +std::set CWallet::GetAccountAddresses(std::string strAccount) const { LOCK(cs_wallet); - set result; - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, mapAddressBook) { + std::set result; + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : mapAddressBook) { const CTxDestination& address = item.first; - const string& strName = item.second.name; + const std::string& strName = item.second.name; if (strName == strAccount) result.insert(address); } @@ -4085,7 +3274,7 @@ static void LoadReserveKeysToSet(std::set& setAddress, const std::set::const_iterator mi = mapWallet.find(hashTx); + std::map::const_iterator mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) { NotifyTransactionChanged(this, hashTx, CT_UPDATED); return true; @@ -4174,7 +3363,7 @@ class CAffectedKeysVisitor : public boost::static_visitor std::vector vDest; int nRequired; if (ExtractDestinations(script, type, vDest, nRequired)) { - BOOST_FOREACH (const CTxDestination& dest, vDest) + for (const CTxDestination& dest : vDest) boost::apply_visitor(*this, dest); } } @@ -4229,7 +3418,7 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const std::map mapKeyFirstBlock; std::set setKeys; GetKeys(setKeys); - BOOST_FOREACH (const CKeyID& keyid, setKeys) { + for (const CKeyID& keyid : setKeys) { if (mapKeyBirth.count(keyid) == 0) mapKeyFirstBlock[keyid] = pindexMax; } @@ -4248,10 +3437,10 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { // ... which are already in a block int nHeight = blit->second->nHeight; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { // iterate over all their outputs CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey); - BOOST_FOREACH (const CKeyID& keyid, vAffected) { + for (const CKeyID& keyid : vAffected) { // ... and all their affected keys std::map::iterator rit = mapKeyFirstBlock.find(keyid); if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) @@ -4335,20 +3524,6 @@ bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, c return true; } -bool CWallet::GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const -{ - std::map::const_iterator i = mapAddressBook.find(dest); - if (i != mapAddressBook.end()) { - CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); - if (j != i->second.destdata.end()) { - if (value) - *value = j->second; - return true; - } - } - return false; -} - // CWallet::AutoZeromint() gets called with each new incoming block void CWallet::AutoZeromint() { @@ -4433,8 +3608,8 @@ void CWallet::AutoZeromint() if (nMintAmount > 0){ CWalletTx wtx; - vector vDMints; - string strError = pwalletMain->MintZerocoin(nMintAmount*COIN, wtx, vDMints); + std::vector vDMints; + std::string strError = pwalletMain->MintZerocoin(nMintAmount*COIN, wtx, vDMints); // Return if something went wrong during minting if (strError != ""){ @@ -4461,11 +3636,12 @@ void CWallet::AutoCombineDust() return; } - map > mapCoinsByAddress = AvailableCoinsByAddress(true, nAutoCombineThreshold * COIN); + std::map > mapCoinsByAddress = AvailableCoinsByAddress(true, nAutoCombineThreshold * COIN); //coins are sectioned by address. This combination code only wants to combine inputs that belong to the same address - for (map >::iterator it = mapCoinsByAddress.begin(); it != mapCoinsByAddress.end(); it++) { - vector vCoins, vRewardCoins; + for (std::map >::iterator it = mapCoinsByAddress.begin(); it != mapCoinsByAddress.end(); it++) { + std::vector vCoins, vRewardCoins; + bool maxSize = false; vCoins = it->second; // We don't want the tx to be refused for being too large @@ -4475,7 +3651,7 @@ void CWallet::AutoCombineDust() //find masternode rewards that need to be combined CCoinControl* coinControl = new CCoinControl(); CAmount nTotalRewardsValue = 0; - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { if (!out.fSpendable) continue; //no coins should get this far if they dont have proper maturity, this is double checking @@ -4493,8 +3669,11 @@ void CWallet::AutoCombineDust() // Around 180 bytes per input. We use 190 to be certain txSizeEstimate += 190; - if (txSizeEstimate * WITNESS_SCALE_FACTOR >= MAX_STANDARD_TX_COST - (200 * WITNESS_SCALE_FACTOR)) + + if (txSizeEstimate * WITNESS_SCALE_FACTOR >= MAX_STANDARD_TX_COST - (200 * WITNESS_SCALE_FACTOR)) { + maxSize = true; break; + } } //if no inputs found then return @@ -4505,9 +3684,9 @@ void CWallet::AutoCombineDust() if (vRewardCoins.size() <= 1) continue; - vector > vecSend; + std::vector > vecSend; CScript scriptPubKey = GetScriptForDestination(it->first); - vecSend.push_back(make_pair(scriptPubKey, nTotalRewardsValue)); + vecSend.push_back(std::make_pair(scriptPubKey, nTotalRewardsValue)); //Send change to same address CTxDestination destMyAddress; @@ -4520,7 +3699,7 @@ void CWallet::AutoCombineDust() // Create the transaction and commit it to the network CWalletTx wtx; CReserveKey keyChange(this); // this change address does not end up being used, because change is returned with coin control switch - string strErr; + std::string strErr; CAmount nFeeRet = 0; // 10% safety margin to avoid "Insufficient funds" errors @@ -4532,7 +3711,7 @@ void CWallet::AutoCombineDust() } //we don't combine below the threshold unless the fees are 0 to avoid paying fees over fees over fees - if (nTotalRewardsValue < nAutoCombineThreshold * COIN && nFeeRet > 0) + if (!maxSize && nTotalRewardsValue < nAutoCombineThreshold * COIN && nFeeRet > 0) continue; if (!CommitTransaction(wtx, keyChange)) { @@ -4601,7 +3780,7 @@ bool CWallet::MultiSend() CWalletTx wtx; CReserveKey keyChange(this); // this change address does not end up being used, because change is returned with coin control switch CAmount nFeeRet = 0; - vector > vecSend; + std::vector > vecSend; // loop through multisend vector and add amounts and addresses to the sending vector const isminefilter filter = ISMINE_SPENDABLE; @@ -4612,12 +3791,12 @@ bool CWallet::MultiSend() CTxDestination strAddSend = DecodeDestination(vMultiSend[i].first); CScript scriptPubKey; scriptPubKey = GetScriptForDestination(strAddSend); - vecSend.push_back(make_pair(scriptPubKey, nAmount)); + vecSend.push_back(std::make_pair(scriptPubKey, nAmount)); } //get the fee amount CWalletTx wtxdummy; - string strErr; + std::string strErr; CreateTransaction(vecSend, wtxdummy, keyChange, nFeeRet, strErr, &cControl, ALL_COINS, false, CAmount(0)); CAmount nLastSendAmount = vecSend[vecSend.size() - 1].second; if (nLastSendAmount < nFeeRet + 500) { @@ -4760,7 +3939,7 @@ int CMerkleTx::GetBlocksToMaturity() const LOCK(cs_main); if (!(IsCoinBase() || IsCoinStake())) return 0; - return max(0, (Params().COINBASE_MATURITY() + 1) - GetDepthInMainChain()); + return std::max(0, (Params().COINBASE_MATURITY() + 1) - GetDepthInMainChain()); } @@ -4905,9 +4084,9 @@ CTxDestination CWallet::AddAndGetDestinationForScript(const CScript& script, Out } // Given a set of inputs, find the public key that contributes the most coins to the input set -CScript GetLargestContributor(set >& setCoins) +CScript GetLargestContributor(std::set >& setCoins) { - map mapScriptsOut; + std::map mapScriptsOut; for (const std::pair& coin : setCoins) { CTxOut out = coin.first->vout[coin.second]; mapScriptsOut[out.scriptPubKey] += out.nValue; @@ -4955,7 +4134,7 @@ bool CWallet::CreateZPHROutput(libzerocoin::CoinDenomination denomination, CTxOu return true; } -bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, vector& vDMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, const bool isZCSpendChange) +bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, std::vector& vDMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, const bool isZCSpendChange) { if (IsLocked()) { strFailReason = _("Error: Wallet locked, unable to create transaction!"); @@ -4968,7 +4147,7 @@ bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransa CAmount nValueRemaining = 0; while (true) { //mint a coin with the closest denomination to what is being requested - nFeeRet = max(static_cast(txNew.vout.size()), 1) * Params().Zerocoin_MintFee(); + nFeeRet = std::max(static_cast(txNew.vout.size()), 1) * Params().Zerocoin_MintFee(); nValueRemaining = nValue - nMintingValue - (isZCSpendChange ? nFeeRet : 0); // if this is change of a zerocoinspend, then we can't mint all change, at least something must be given as a fee @@ -5004,7 +4183,7 @@ bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransa // check for a zerocoinspend that mints the change CAmount nValueIn = 0; - set > setCoins; + std::set > setCoins; if (isZCSpendChange) { nValueIn = nValue; } else { @@ -5072,7 +4251,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con // 3. Compute Accumulator and Witness libzerocoin::Accumulator accumulator(paramsAccumulator, pubCoinSelected.getDenomination()); libzerocoin::AccumulatorWitness witness(paramsAccumulator, accumulator, pubCoinSelected); - string strFailReason = ""; + std::string strFailReason = ""; int nMintsAdded = 0; if (!GenerateAccumulatorWitness(pubCoinSelected, accumulator, witness, nSecurityLevel, nMintsAdded, strFailReason, pindexCheckpoint)) { receipt.SetStatus(_("Try to spend with a higher security level to include more coins"), ZPHR_FAILED_ACCUMULATOR_INITIALIZATION); @@ -5168,7 +4347,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con return true; } -bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CTxDestination* address) +bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, std::vector& vSelectedMints, std::vector& vNewMints, bool fMintChange, bool fMinimizeChange, CTxDestination* address) { // Check available funds int nStatus = ZPHR_TRX_FUNDS_PROBLEMS; @@ -5187,12 +4366,12 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, // If not already given pre-selected mints, then select mints from the wallet CWalletDB walletdb(pwalletMain->strWalletFile); - set setMints; + std::set setMints; CAmount nValueSelected = 0; int nCoinsReturned = 0; // Number of coins returned in change from function below (for debug) int nNeededSpends = 0; // Number of spends which would be needed if selection failed const int nMaxSpends = Params().Zerocoin_MaxSpendsPerTransaction(); // Maximum possible spends for one zPHR transaction - vector vMintsToFetch; + std::vector vMintsToFetch; if (vSelectedMints.empty()) { setMints = zphrTracker->ListMints(true, true, true); // need to find mints to spend if(setMints.empty()) { @@ -5209,7 +4388,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, // Select the zPHR mints to use in this spend std::map DenomMap = GetMyZerocoinDistribution(); - list listMints(setMints.begin(), setMints.end()); + std::list listMints(setMints.begin(), setMints.end()); vMintsToFetch = SelectMintsFromList(nValueToSelect, nValueSelected, nMaxSpends, fMinimizeChange, nCoinsReturned, listMints, DenomMap, nNeededSpends); for (auto& meta : vMintsToFetch) { @@ -5335,7 +4514,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, //mint change as zerocoins if (fMintChange) { CAmount nFeeRet = 0; - string strFailReason = ""; + std::string strFailReason = ""; if (!CreateZerocoinMintTransaction(nChange, txNew, vNewMints, &reserveKey, nFeeRet, strFailReason, NULL, true)) { receipt.SetStatus(_("Failed to create mint"), nStatus); return false; @@ -5392,16 +4571,16 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, return true; } -string CWallet::ResetMintZerocoin() +std::string CWallet::ResetMintZerocoin() { long updates = 0; long deletions = 0; CWalletDB walletdb(pwalletMain->strWalletFile); - set setMints = zphrTracker->ListMints(false, false, true); - vector vMintsToFind(setMints.begin(), setMints.end()); - vector vMintsMissing; - vector vMintsToUpdate; + std::set setMints = zphrTracker->ListMints(false, false, true); + std::vector vMintsToFind(setMints.begin(), setMints.end()); + std::vector vMintsMissing; + std::vector vMintsToUpdate; // search all of our available data for these mints FindMints(vMintsToFind, vMintsToUpdate, vMintsMissing); @@ -5419,18 +4598,18 @@ string CWallet::ResetMintZerocoin() LogPrintf("%s: failed to archive mint\n", __func__); } - string strResult = _("ResetMintZerocoin finished: ") + to_string(updates) + _(" mints updated, ") + to_string(deletions) + _(" mints deleted\n"); + std::string strResult = _("ResetMintZerocoin finished: ") + std::to_string(updates) + _(" mints updated, ") + std::to_string(deletions) + _(" mints deleted\n"); return strResult; } -string CWallet::ResetSpentZerocoin() +std::string CWallet::ResetSpentZerocoin() { long removed = 0; CWalletDB walletdb(pwalletMain->strWalletFile); - set setMints = zphrTracker->ListMints(false, false, true); - list listSpends = walletdb.ListSpentCoins(); - list listUnconfirmedSpends; + std::set setMints = zphrTracker->ListMints(false, false, true); + std::list listSpends = walletdb.ListSpentCoins(); + std::list listUnconfirmedSpends; for (CZerocoinSpend spend : listSpends) { CTransaction tx; @@ -5457,7 +4636,7 @@ string CWallet::ResetSpentZerocoin() } } - string strResult = _("ResetSpentZerocoin finished: ") + to_string(removed) + _(" unconfirmed transactions removed\n"); + std::string strResult = _("ResetSpentZerocoin finished: ") + std::to_string(removed) + _(" unconfirmed transactions removed\n"); return strResult; } @@ -5481,8 +4660,8 @@ bool IsMintInChain(const uint256& hashPubcoin, uint256& txid, int& nHeight) void CWallet::ReconsiderZerocoins(std::list& listMintsRestored, std::list& listDMintsRestored) { CWalletDB walletdb(pwalletMain->strWalletFile); - list listMints = walletdb.ListArchivedZerocoins(); - list listDMints = walletdb.ListArchivedDeterministicMints(); + std::list listMints = walletdb.ListArchivedZerocoins(); + std::list listDMints = walletdb.ListArchivedDeterministicMints(); if (listMints.empty() && listDMints.empty()) return; @@ -5525,34 +4704,33 @@ void CWallet::ReconsiderZerocoins(std::list& listMintsRestored, s } } -string CWallet::GetUniqueWalletBackupName(bool fzphrAuto) const +std::string CWallet::GetUniqueWalletBackupName(bool fzphrAuto) const { - posix_time::ptime timeLocal = posix_time::second_clock::local_time(); - stringstream ssDateTime; - + std::stringstream ssDateTime; + std::string strWalletBackupName = strprintf("%s", DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime())); + ssDateTime << strWalletBackupName; - ssDateTime << gregorian::to_iso_extended_string(timeLocal.date()) << "-" << timeLocal.time_of_day(); return strprintf("wallet%s.dat%s", fzphrAuto ? "-autozphrbackup" : "", DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime())); } void CWallet::ZPhrBackupWallet() { - filesystem::path backupDir = GetDataDir() / "backups"; - filesystem::path backupPath; - string strNewBackupName; + boost::filesystem::path backupDir = GetDataDir() / "backups"; + boost::filesystem::path backupPath; + std::string strNewBackupName; for (int i = 0; i < 10; i++) { strNewBackupName = strprintf("wallet-autozphrbackup-%d.dat", i); backupPath = backupDir / strNewBackupName; - if (filesystem::exists(backupPath)) { + if (boost::filesystem::exists(backupPath)) { //Keep up to 10 backups if (i <= 8) { //If the next file backup exists and is newer, then iterate - filesystem::path nextBackupPath = backupDir / strprintf("wallet-autozphrbackup-%d.dat", i + 1); - if (filesystem::exists(nextBackupPath)) { - time_t timeThis = filesystem::last_write_time(backupPath); - time_t timeNext = filesystem::last_write_time(nextBackupPath); + boost::filesystem::path nextBackupPath = backupDir / strprintf("wallet-autozphrbackup-%d.dat", i + 1); + if (boost::filesystem::exists(nextBackupPath)) { + time_t timeThis = boost::filesystem::last_write_time(backupPath); + time_t timeNext = boost::filesystem::last_write_time(nextBackupPath); if (timeThis > timeNext) { //The next backup is created before this backup was //The next backup is the correct path to use @@ -5575,8 +4753,8 @@ void CWallet::ZPhrBackupWallet() BackupWallet(*this, backupPath.string()); if(!GetArg("-zphrbackuppath", "").empty()) { - filesystem::path customPath(GetArg("-zphrbackuppath", "")); - filesystem::create_directories(customPath); + boost::filesystem::path customPath(GetArg("-zphrbackuppath", "")); + boost::filesystem::create_directories(customPath); if(!customPath.has_extension()) { customPath /= GetUniqueWalletBackupName(true); @@ -5586,23 +4764,23 @@ void CWallet::ZPhrBackupWallet() } } -string CWallet::MintZerocoinFromOutPoint(CAmount nValue, CWalletTx& wtxNew, vector& vDMints, const vector vOutpts) +std::string CWallet::MintZerocoinFromOutPoint(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const std::vector vOutpts) { CCoinControl* coinControl = new CCoinControl(); for (const COutPoint& outpt : vOutpts) { coinControl->Select(outpt); } if (!coinControl->HasSelected()){ - string strError = _("Error: No valid utxo!"); + std::string strError = _("Error: No valid utxo!"); LogPrintf("MintZerocoin() : %s", strError.c_str()); return strError; } - string strError = MintZerocoin(nValue, wtxNew, vDMints, coinControl); + std::string strError = MintZerocoin(nValue, wtxNew, vDMints, coinControl); delete coinControl; return strError; } -string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vDMints, const CCoinControl* coinControl) +std::string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const CCoinControl* coinControl) { // Check amount if (nValue <= 0) @@ -5615,12 +4793,12 @@ string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector GetBalance()) @@ -5657,7 +4835,7 @@ string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CTxDestination* addressTo) +bool CWallet::SpendZerocoin(CAmount nAmount, int nSecurityLevel, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, std::vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CTxDestination* addressTo) { // Default: assume something goes wrong. Depending on the problem this gets more specific below int nStatus = ZPHR_SPEND_ERROR; @@ -5668,7 +4846,7 @@ bool CWallet::SpendZerocoin(CAmount nAmount, int nSecurityLevel, CWalletTx& wtxN } CReserveKey reserveKey(this); - vector vNewMints; + std::vector vNewMints; if (!CreateZerocoinSpendTransaction(nAmount, nSecurityLevel, wtxNew, reserveKey, receipt, vMintsSelected, vNewMints, fMintChange, fMinimizeChange, addressTo)) { return false; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6039150087d1..152d0465e6f8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -232,22 +232,15 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface public: bool MintableCoins(); bool SelectStakeCoins(std::set >& setCoins, CAmount nTargetAmount) const; - bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& setCoinsRet, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) const; - bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax); - bool SelectCoinsDarkDenominated(CAmount nTargetValue, std::vector& setCoinsRet, CAmount& nValueRet) const; - bool HasCollateralInputs(bool fOnlyConfirmed = true) const; bool IsCollateralAmount(CAmount nInputAmount) const; - int CountInputsWithAmount(CAmount nInputAmount); - - bool SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) const; // Zerocoin additions - bool CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, vector& vDMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, const bool isZCSpendChange = false); - bool CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CTxDestination* destination = NULL); + bool CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, std::vector& vDMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, const bool isZCSpendChange = false); + bool CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, std::vector& vSelectedMints, std::vector& vNewMints, bool fMintChange, bool fMinimizeChange, CTxDestination* destination = NULL); bool MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); - std::string MintZerocoinFromOutPoint(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const vector vOutpts); - std::string MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vDMints, const CCoinControl* coinControl = NULL); - bool SpendZerocoin(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CTxDestination* addressTo = NULL); + std::string MintZerocoinFromOutPoint(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const std::vector vOutpts); + std::string MintZerocoin(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const CCoinControl* coinControl = NULL); + bool SpendZerocoin(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, std::vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CTxDestination* addressTo = NULL); std::string ResetMintZerocoin(); std::string ResetSpentZerocoin(); void ReconsiderZerocoins(std::list& listMintsRestored, std::list& listDMintsRestored); @@ -259,7 +252,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool DatabaseMint(CDeterministicMint& dMint); bool SetMintUnspent(const CBigNum& bnSerial); bool UpdateMint(const CBigNum& bnValue, const int& nHeight, const uint256& txid, const libzerocoin::CoinDenomination& denom); - string GetUniqueWalletBackupName(bool fzphrAuto) const; + std::string GetUniqueWalletBackupName(bool fzphrAuto) const; /** Zerocin entry changed. * @note called with lock cs_wallet held. @@ -457,7 +450,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void UnlockCoin(COutPoint& output); void UnlockAllCoins(); void ListLockedCoins(std::vector& vOutpts); - CAmount GetTotalValue(std::vector vCoins); /** * keystore implementation @@ -504,8 +496,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool EraseDestData(const CTxDestination& dest, const std::string& key); //! Adds a destination data tuple to the store, without saving it to disk bool LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value); - //! Look up a destination data tuple in the store, return true if found false otherwise - bool GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const; //! Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnly(const CScript& dest); @@ -570,11 +560,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::map GetMyZerocoinDistribution() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; - CAmount GetAnonymizableBalance() const; - CAmount GetAnonymizedBalance() const; - double GetAverageAnonymizedRounds() const; - CAmount GetNormalizedAnonymizedBalance() const; - CAmount GetDenominatedBalance(bool unconfirmed = false) const; CAmount GetWatchOnlyBalance() const; CAmount GetUnconfirmedWatchOnlyBalance() const; CAmount GetImmatureWatchOnlyBalance() const; @@ -592,10 +577,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool CreateTransaction(CScript scriptPubKey, const CAmount& nValue, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, AvailableCoinsType coin_type = ALL_COINS, bool useIX = false, CAmount nFeePay = 0); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand = NetMsgType::TX); bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); - std::string PrepareObfuscationDenominate(int minRounds, int maxRounds); int GenerateObfuscationOutputs(int nTotalValue, std::vector& vout); - bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); - bool ConvertList(std::vector vCoins, std::vector& vecAmounts); bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime); bool MultiSend(); void AutoCombineDust(); @@ -621,13 +603,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX); - // get the Obfuscation chain depth for a given input - int GetRealInputObfuscationRounds(CTxIn in, int rounds) const; - // respect current settings - int GetInputObfuscationRounds(CTxIn in) const; - bool IsDenominated(const CTxIn& txin) const; - bool IsDenominated(const CTransaction& tx) const; bool IsDenominatedAmount(CAmount nInputAmount) const; @@ -654,7 +630,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface } bool IsMine(const CTransaction& tx) const { - BOOST_FOREACH (const CTxOut& txout, tx.vout) + for (const CTxOut& txout : tx.vout) if (IsMine(txout)) return true; return false; @@ -667,7 +643,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const { CAmount nDebit = 0; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { nDebit += GetDebit(txin, filter); if (!MoneyRange(nDebit)) throw std::runtime_error("CWallet::GetDebit() : value out of range"); @@ -677,7 +653,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const { CAmount nCredit = 0; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { nCredit += GetCredit(txout, filter); if (!MoneyRange(nCredit)) throw std::runtime_error("CWallet::GetCredit() : value out of range"); @@ -687,7 +663,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetChange(const CTransaction& tx) const { CAmount nChange = 0; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { nChange += GetChange(txout); if (!MoneyRange(nChange)) throw std::runtime_error("CWallet::GetChange() : value out of range"); @@ -1078,13 +1054,10 @@ class CWalletTx : public CMerkleTx CAmount GetCredit(const isminefilter& filter) const; CAmount GetImmatureCredit(bool fUseCache = true) const; CAmount GetAvailableCredit(bool fUseCache = true) const; - CAmount GetAnonymizableCredit(bool fUseCache = true) const; - CAmount GetAnonymizedCredit(bool fUseCache = true) const; // Return sum of unlocked coins CAmount GetUnlockedCredit() const; // Return sum of unlocked coins CAmount GetLockedCredit() const; - CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache = true) const; CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetLockedWatchOnlyCredit() const; @@ -1127,7 +1100,7 @@ class CWalletTx : public CMerkleTx return false; // Trusted if all inputs are from us and are in the mempool: - BOOST_FOREACH (const CTxIn& txin, vin) { + for (const CTxIn& txin : vin) { // Transactions not sent by us: not trusted const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); if (parent == NULL) @@ -1169,7 +1142,7 @@ class COutput //Used with Obfuscation. Will return largest nondenom, then denominations, then very small inputs int Priority() const { - BOOST_FOREACH (CAmount d, obfuScationDenominations) + for (CAmount d : obfuScationDenominations) if (tx->vout[i].nValue == d) return 10000; if (tx->vout[i].nValue < 1 * COIN) return 20000; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 577c5560fd9e..b62659cbe9aa 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -20,44 +20,41 @@ #include "primitives/deterministicmint.h" #include -#include + #include #include #include -using namespace boost; -using namespace std; - static uint64_t nAccountingEntryNumber = 0; // // CWalletDB // -bool CWalletDB::WriteName(const string& strAddress, const string& strName) +bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName) { nWalletDBUpdated++; - return Write(make_pair(string("name"), strAddress), strName); + return Write(std::make_pair(std::string("name"), strAddress), strName); } -bool CWalletDB::EraseName(const string& strAddress) +bool CWalletDB::EraseName(const std::string& strAddress) { // This should only be used for sending addresses, never for receiving addresses, // receiving addresses must always have an address book entry if they're not change return. nWalletDBUpdated++; - return Erase(make_pair(string("name"), strAddress)); + return Erase(std::make_pair(std::string("name"), strAddress)); } -bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose) +bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose) { nWalletDBUpdated++; - return Write(make_pair(string("purpose"), strAddress), strPurpose); + return Write(std::make_pair(std::string("purpose"), strAddress), strPurpose); } -bool CWalletDB::ErasePurpose(const string& strPurpose) +bool CWalletDB::ErasePurpose(const std::string& strPurpose) { nWalletDBUpdated++; - return Erase(make_pair(string("purpose"), strPurpose)); + return Erase(std::make_pair(std::string("purpose"), strPurpose)); } bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx) @@ -263,15 +260,15 @@ bool CWalletDB::WriteMinVersion(int nVersion) return Write(std::string("minversion"), nVersion); } -bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) +bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account) { account.SetNull(); - return Read(make_pair(string("acc"), strAccount), account); + return Read(std::make_pair(std::string("acc"), strAccount), account); } -bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) +bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account) { - return Write(make_pair(string("acc"), strAccount), account); + return Write(std::make_pair(std::string("acc"), strAccount), account); } bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry) @@ -284,31 +281,31 @@ bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry) return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } -CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount) +CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount) { - list entries; + std::list entries; ListAccountCreditDebit(strAccount, entries); CAmount nCreditDebit = 0; - BOOST_FOREACH (const CAccountingEntry& entry, entries) + for (const CAccountingEntry& entry : entries) nCreditDebit += entry.nCreditDebit; return nCreditDebit; } -void CWalletDB::ListAccountCreditDebit(const string& strAccount, list& entries) +void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list& entries) { bool fAllAccounts = (strAccount == "*"); Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); + throw std::runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0))); + ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0))); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -316,11 +313,11 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, listclose(); - throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB"); + throw std::runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "acentry") break; @@ -344,18 +341,18 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) // Probably a bad idea to change the output of this // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. - typedef pair TxPair; - typedef multimap TxItems; + typedef std::pair TxPair; + typedef std::multimap TxItems; TxItems txByTime; - for (map::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) { + for (std::map::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); - txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0))); + txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0))); } - list acentries; + std::list acentries; ListAccountCreditDebit("", acentries); - BOOST_FOREACH (CAccountingEntry& entry, acentries) { - txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); + for (CAccountingEntry& entry : acentries) { + txByTime.insert(std::make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } int64_t& nOrderPosNext = pwallet->nOrderPosNext; @@ -377,7 +374,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) return DB_LOAD_FAIL; } else { int64_t nOrderPosOff = 0; - BOOST_FOREACH (const int64_t& nOffsetStart, nOrderPosOffsets) { + for (const int64_t& nOffsetStart : nOrderPosOffsets) { if (nOrderPos >= nOffsetStart) ++nOrderPosOff; } @@ -409,7 +406,7 @@ class CWalletScanState bool fIsEncrypted; bool fAnyUnordered; int nFileVersion; - vector vWalletUpgrade; + std::vector vWalletUpgrade; CWalletScanState() { @@ -420,7 +417,7 @@ class CWalletScanState } }; -bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CWalletScanState& wss, string& strType, string& strErr) +bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CWalletScanState& wss, std::string& strType, std::string& strErr) { try { // Unserialize @@ -428,11 +425,11 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW // is just the two items serialized one after the other ssKey >> strType; if (strType == "name") { - string strAddress; + std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name; } else if (strType == "purpose") { - string strAddress; + std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose; } else if (strType == "tx") { @@ -466,7 +463,7 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW pwallet->AddToWallet(wtx, true); } else if (strType == "acentry") { - string strAccount; + std::string strAccount; ssKey >> strAccount; uint64_t nNumber; ssKey >> nNumber; @@ -569,9 +566,9 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW if (pwallet->nMasterKeyMaxID < nID) pwallet->nMasterKeyMaxID = nID; } else if (strType == "ckey") { - vector vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; - vector vchPrivKey; + std::vector vchPrivKey; ssValue >> vchPrivKey; wss.nCKeys++; @@ -700,7 +697,7 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW return true; } -static bool IsKeyType(string strType) +static bool IsKeyType(std::string strType) { return (strType == "mkey" || strType == "ckey" || strType == "hdchain" || strType == "chdchain"); @@ -716,7 +713,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) try { LOCK(pwallet->cs_wallet); int nMinVersion = 0; - if (Read((string) "minversion", nMinVersion)) { + if (Read((std::string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; pwallet->LoadMinVersion(nMinVersion); @@ -742,7 +739,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) } // Try to be tolerant of single corrupt records: - string strType, strErr; + std::string strType, strErr; if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: @@ -783,7 +780,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' - BOOST_FOREACH (uint256 hash, wss.vWalletUpgrade) + for (uint256 hash : wss.vWalletUpgrade) WriteTx(hash, pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: @@ -798,14 +795,14 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) pwallet->laccentries.clear(); ListAccountCreditDebit("*", pwallet->laccentries); - BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) { - pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry))); + for (CAccountingEntry& entry : pwallet->laccentries) { + pwallet->wtxOrdered.insert(std::make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry))); } return result; } -DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vector& vWtx) +DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, std::vector& vTxHash, std::vector& vWtx) { pwallet->vchDefaultKey = CPubKey(); bool fNoncriticalErrors = false; @@ -814,7 +811,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vec try { LOCK(pwallet->cs_wallet); int nMinVersion = 0; - if (Read((string) "minversion", nMinVersion)) { + if (Read((std::string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; pwallet->LoadMinVersion(nMinVersion); @@ -839,7 +836,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vec return DB_CORRUPT; } - string strType; + std::string strType; ssKey >> strType; if (strType == "tx") { uint256 hash; @@ -865,16 +862,16 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vec return result; } -DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector& vWtx) +DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, std::vector& vWtx) { // build list of wallet TXs - vector vTxHash; + std::vector vTxHash; DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); if (err != DB_LOAD_OK) return err; // erase each wallet TX - BOOST_FOREACH (uint256& hash, vTxHash) { + for (uint256& hash : vTxHash) { if (!EraseTx(hash)) return DB_CORRUPT; } @@ -882,7 +879,7 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector& vWtx) return DB_LOAD_OK; } -void ThreadFlushWalletDB(const string& strFile) +void ThreadFlushWalletDB(const std::string& strFile) { // Make this thread recognisable as the wallet flushing thread RenameThread("phore-wallet"); @@ -910,7 +907,7 @@ void ThreadFlushWalletDB(const string& strFile) if (lockDb) { // Don't do this if any databases are in use int nRefCount = 0; - map::iterator mi = bitdb.mapFileUseCount.begin(); + std::map::iterator mi = bitdb.mapFileUseCount.begin(); while (mi != bitdb.mapFileUseCount.end()) { nRefCount += (*mi).second; mi++; @@ -918,7 +915,7 @@ void ThreadFlushWalletDB(const string& strFile) if (nRefCount == 0) { boost::this_thread::interruption_point(); - map::iterator mi = bitdb.mapFileUseCount.find(strFile); + std::map::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { LogPrint("db", "Flushing wallet.dat\n"); nLastFlushed = nWalletDBUpdated; @@ -937,16 +934,16 @@ void ThreadFlushWalletDB(const string& strFile) } } -void NotifyBacked(const CWallet& wallet, bool fSuccess, string strMessage) +void NotifyBacked(const CWallet& wallet, bool fSuccess, std::string strMessage) { LogPrintf("%s", strMessage.data()); wallet.NotifyWalletBacked(fSuccess, strMessage); } -bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool fEnableCustom) +bool BackupWallet(const CWallet& wallet, const boost::filesystem::path& strDest, bool fEnableCustom) { - filesystem::path pathCustom; - filesystem::path pathWithFile; + boost::filesystem::path pathCustom; + boost::filesystem::path pathWithFile; if (!wallet.fFileBacked) { return false; } else if(fEnableCustom) { @@ -959,8 +956,8 @@ bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool f pathCustom = pathWithFile.parent_path(); } try { - filesystem::create_directories(pathCustom); - } catch(const filesystem::filesystem_error& e) { + boost::filesystem::create_directories(pathCustom); + } catch(const boost::filesystem::filesystem_error& e) { NotifyBacked(wallet, false, strprintf("%s\n", e.what())); pathCustom = ""; } @@ -977,8 +974,8 @@ bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool f bitdb.mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat - filesystem::path pathDest(strDest); - filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; + boost::filesystem::path pathDest(strDest); + boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; if (is_directory(pathDest)) { if (!exists(pathDest)) create_directory(pathDest); pathDest /= wallet.strWalletFile; @@ -989,21 +986,21 @@ bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool f int nThreshold = GetArg("-custombackupthreshold", DEFAULT_CUSTOMBACKUPTHRESHOLD); if (nThreshold > 0) { - typedef std::multimap folder_set_t; + typedef std::multimap folder_set_t; folder_set_t folderSet; - filesystem::directory_iterator end_iter; + boost::filesystem::directory_iterator end_iter; pathCustom.make_preferred(); // Build map of backup files for current(!) wallet sorted by last write time - filesystem::path currentFile; - for (filesystem::directory_iterator dir_iter(pathCustom); dir_iter != end_iter; ++dir_iter) { + boost::filesystem::path currentFile; + for (boost::filesystem::directory_iterator dir_iter(pathCustom); dir_iter != end_iter; ++dir_iter) { // Only check regular files - if (filesystem::is_regular_file(dir_iter->status())) { + if (boost::filesystem::is_regular_file(dir_iter->status())) { currentFile = dir_iter->path().filename(); // Only add the backups for the current wallet, e.g. wallet.dat.* if (dir_iter->path().stem().string() == wallet.strWalletFile) { - folderSet.insert(folder_set_t::value_type(filesystem::last_write_time(dir_iter->path()), *dir_iter)); + folderSet.insert(folder_set_t::value_type(boost::filesystem::last_write_time(dir_iter->path()), *dir_iter)); } } } @@ -1027,11 +1024,11 @@ bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool f try { auto entry = folderSet.find(oldestBackup); if (entry != folderSet.end()) { - filesystem::remove(entry->second); + boost::filesystem::remove(entry->second); LogPrintf("Old backup deleted: %s\n", (*entry).second); } - } catch (filesystem::filesystem_error& error) { - string strMessage = strprintf("Failed to delete backup %s\n", error.what()); + } catch (boost::filesystem::filesystem_error& error) { + std::string strMessage = strprintf("Failed to delete backup %s\n", error.what()); LogPrint(nullptr, strMessage.data()); NotifyBacked(wallet, false, strMessage); } @@ -1048,13 +1045,17 @@ bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool f return false; } -bool AttemptBackupWallet(const CWallet& wallet, const filesystem::path& pathSrc, const filesystem::path& pathDest) +bool AttemptBackupWallet(const CWallet& wallet, const boost::filesystem::path& pathSrc, const boost::filesystem::path& pathDest) { bool retStatus; - string strMessage; + std::string strMessage; try { + if (boost::filesystem::equivalent(pathSrc, pathDest)) { + LogPrintf("cannot backup to wallet source file %s\n", pathDest.string()); + return false; + } #if BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ - filesystem::copy_file(pathSrc.c_str(), pathDest, filesystem::copy_option::overwrite_if_exists); + boost::filesystem::copy_file(pathSrc.c_str(), pathDest, boost::filesystem::copy_option::overwrite_if_exists); #else std::ifstream src(pathSrc.c_str(), std::ios::binary | std::ios::in); std::ofstream dst(pathDest.c_str(), std::ios::binary | std::ios::out | std::ios::trunc); @@ -1066,7 +1067,7 @@ bool AttemptBackupWallet(const CWallet& wallet, const filesystem::path& pathSrc, strMessage = strprintf("copied wallet.dat to %s\n", pathDest.string()); LogPrint(nullptr, strMessage.data()); retStatus = true; - } catch (const filesystem::filesystem_error& e) { + } catch (const boost::filesystem::filesystem_error& e) { retStatus = false; strMessage = strprintf("%s\n", e.what()); LogPrint(nullptr, strMessage.data()); @@ -1090,8 +1091,8 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) int64_t now = GetTime(); std::string newFilename = strprintf("wallet.%d.bak", now); - int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL, - newFilename.c_str(), DB_AUTO_COMMIT); + int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL, + newFilename.c_str(), DB_AUTO_COMMIT); if (result == 0) LogPrintf("Renamed %s to %s\n", filename, newFilename); else { @@ -1108,12 +1109,12 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); bool fSuccess = allOK; - boost::scoped_ptr pdbCopy(new Db(&dbenv.dbenv, 0)); - int ret = pdbCopy->open(NULL, // Txn pointer - filename.c_str(), // Filename - "main", // Logical db name - DB_BTREE, // Database type - DB_CREATE, // Flags + boost::scoped_ptr pdbCopy(new Db(dbenv.dbenv, 0)); + int ret = pdbCopy->open(NULL, // Txn pointer + filename.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags 0); if (ret > 0) { LogPrintf("Cannot create database file %s\n", filename); @@ -1123,11 +1124,11 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) CWalletScanState wss; DbTxn* ptxn = dbenv.TxnBegin(); - BOOST_FOREACH (CDBEnv::KeyValPair& row, salvagedData) { + for (CDBEnv::KeyValPair& row : salvagedData) { if (fOnlyKeys) { CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); - string strType, strErr; + std::string strType, strErr; bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, wss, strType, strErr); if (!IsKeyType(strType) && strType != "hdpubkey") @@ -1197,33 +1198,33 @@ bool CWalletDB::WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& key bool CWalletDB::WriteZerocoinSpendSerialEntry(const CZerocoinSpend& zerocoinSpend) { - return Write(make_pair(string("zcserial"), zerocoinSpend.GetSerial()), zerocoinSpend, true); + return Write(std::make_pair(std::string("zcserial"), zerocoinSpend.GetSerial()), zerocoinSpend, true); } bool CWalletDB::EraseZerocoinSpendSerialEntry(const CBigNum& serialEntry) { - return Erase(make_pair(string("zcserial"), serialEntry)); + return Erase(std::make_pair(std::string("zcserial"), serialEntry)); } bool CWalletDB::ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial) { CZerocoinSpend spend; - return Read(make_pair(string("zcserial"), bnSerial), spend); + return Read(std::make_pair(std::string("zcserial"), bnSerial), spend); } bool CWalletDB::WriteDeterministicMint(const CDeterministicMint& dMint) { uint256 hash = dMint.GetPubcoinHash(); - return Write(make_pair(string("dzphr"), hash), dMint, true); + return Write(std::make_pair(std::string("dzphr"), hash), dMint, true); } bool CWalletDB::ReadDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint) { - return Read(make_pair(string("dzphr"), hashPubcoin), dMint); + return Read(std::make_pair(std::string("dzphr"), hashPubcoin), dMint); } bool CWalletDB::EraseDeterministicMint(const uint256& hashPubcoin) { - return Erase(make_pair(string("dzphr"), hashPubcoin)); + return Erase(std::make_pair(std::string("dzphr"), hashPubcoin)); } @@ -1233,8 +1234,8 @@ bool CWalletDB::WriteZerocoinMint(const CZerocoinMint& zerocoinMint) ss << zerocoinMint.GetValue(); uint256 hash = Hash(ss.begin(), ss.end()); - Erase(make_pair(string("zerocoin"), hash)); - return Write(make_pair(string("zerocoin"), hash), zerocoinMint, true); + Erase(std::make_pair(std::string("zerocoin"), hash)); + return Write(std::make_pair(std::string("zerocoin"), hash), zerocoinMint, true); } bool CWalletDB::ReadZerocoinMint(const CBigNum &bnPubCoinValue, CZerocoinMint& zerocoinMint) @@ -1247,7 +1248,7 @@ bool CWalletDB::ReadZerocoinMint(const CBigNum &bnPubCoinValue, CZerocoinMint& z } bool CWalletDB::ReadZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint) { - return Read(make_pair(string("zerocoin"), hashPubcoin), mint); + return Read(std::make_pair(std::string("zerocoin"), hashPubcoin), mint); } bool CWalletDB::EraseZerocoinMint(const CZerocoinMint& zerocoinMint) @@ -1256,7 +1257,7 @@ bool CWalletDB::EraseZerocoinMint(const CZerocoinMint& zerocoinMint) ss << zerocoinMint.GetValue(); uint256 hash = Hash(ss.begin(), ss.end()); - return Erase(make_pair(string("zerocoin"), hash)); + return Erase(std::make_pair(std::string("zerocoin"), hash)); } bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) @@ -1265,12 +1266,12 @@ bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) ss << zerocoinMint.GetValue(); uint256 hash = Hash(ss.begin(), ss.end());; - if (!Write(make_pair(string("zco"), hash), zerocoinMint)) { + if (!Write(std::make_pair(std::string("zco"), hash), zerocoinMint)) { LogPrintf("%s : failed to database orphaned zerocoin mint\n", __func__); return false; } - if (!Erase(make_pair(string("zerocoin"), hash))) { + if (!Erase(std::make_pair(std::string("zerocoin"), hash))) { LogPrintf("%s : failed to erase orphaned zerocoin mint\n", __func__); return false; } @@ -1280,10 +1281,10 @@ bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) bool CWalletDB::ArchiveDeterministicOrphan(const CDeterministicMint& dMint) { - if (!Write(make_pair(string("dzco"), dMint.GetPubcoinHash()), dMint)) + if (!Write(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()), dMint)) return error("%s: write failed", __func__); - if (!Erase(make_pair(string("dzphr"), dMint.GetPubcoinHash()))) + if (!Erase(std::make_pair(std::string("dzphr"), dMint.GetPubcoinHash()))) return error("%s: failed to erase", __func__); return true; @@ -1291,13 +1292,13 @@ bool CWalletDB::ArchiveDeterministicOrphan(const CDeterministicMint& dMint) bool CWalletDB::UnarchiveDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint) { - if (!Read(make_pair(string("dzco"), hashPubcoin), dMint)) + if (!Read(std::make_pair(std::string("dzco"), hashPubcoin), dMint)) return error("%s: failed to retrieve deterministic mint from archive", __func__); if (!WriteDeterministicMint(dMint)) return error("%s: failed to write deterministic mint", __func__); - if (!Erase(make_pair(string("dzco"), dMint.GetPubcoinHash()))) + if (!Erase(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()))) return error("%s : failed to erase archived deterministic mint", __func__); return true; @@ -1305,14 +1306,14 @@ bool CWalletDB::UnarchiveDeterministicMint(const uint256& hashPubcoin, CDetermin bool CWalletDB::UnarchiveZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint) { - if (!Read(make_pair(string("zco"), hashPubcoin), mint)) + if (!Read(std::make_pair(std::string("zco"), hashPubcoin), mint)) return error("%s: failed to retrieve zerocoinmint from archive", __func__); if (!WriteZerocoinMint(mint)) return error("%s: failed to write zerocoinmint", __func__); uint256 hash = GetPubCoinHash(mint.GetValue()); - if (!Erase(make_pair(string("zco"), hash))) + if (!Erase(std::make_pair(std::string("zco"), hash))) return error("%s : failed to erase archived zerocoin mint", __func__); return true; @@ -1320,20 +1321,20 @@ bool CWalletDB::UnarchiveZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& bool CWalletDB::WriteCurrentSeedHash(const uint256& hashSeed) { - return Write(string("seedhash"), hashSeed); + return Write(std::string("seedhash"), hashSeed); } bool CWalletDB::ReadCurrentSeedHash(uint256& hashSeed) { - return Read(string("seedhash"), hashSeed); + return Read(std::string("seedhash"), hashSeed); } -bool CWalletDB::WriteZPHRSeed(const uint256& hashSeed, const vector& seed) +bool CWalletDB::WriteZPHRSeed(const uint256& hashSeed, const std::vector& seed) { if (!WriteCurrentSeedHash(hashSeed)) return error("%s: failed to write current seed hash", __func__); - return Write(make_pair(string("dzs"), hashSeed), seed); + return Write(std::make_pair(std::string("dzs"), hashSeed), seed); } bool CWalletDB::EraseZPHRSeed() @@ -1354,48 +1355,48 @@ bool CWalletDB::EraseZPHRSeed() bool CWalletDB::EraseZPHRSeed_deprecated() { - return Erase(string("dzs")); + return Erase(std::string("dzs")); } -bool CWalletDB::ReadZPHRSeed(const uint256& hashSeed, vector& seed) +bool CWalletDB::ReadZPHRSeed(const uint256& hashSeed, std::vector& seed) { - return Read(make_pair(string("dzs"), hashSeed), seed); + return Read(std::make_pair(std::string("dzs"), hashSeed), seed); } bool CWalletDB::ReadZPHRSeed_deprecated(uint256& seed) { - return Read(string("dzs"), seed); + return Read(std::string("dzs"), seed); } bool CWalletDB::WriteZPHRCount(const uint32_t& nCount) { - return Write(string("dzc"), nCount); + return Write(std::string("dzc"), nCount); } bool CWalletDB::ReadZPHRCount(uint32_t& nCount) { - return Read(string("dzc"), nCount); + return Read(std::string("dzc"), nCount); } bool CWalletDB::WriteMintPoolPair(const uint256& hashMasterSeed, const uint256& hashPubcoin, const uint32_t& nCount) { - return Write(make_pair(string("mintpool"), hashPubcoin), make_pair(hashMasterSeed, nCount)); + return Write(std::make_pair(std::string("mintpool"), hashPubcoin), std::make_pair(hashMasterSeed, nCount)); } //! map with hashMasterSeed as the key, paired with vector of hashPubcoins and their count -std::map > > CWalletDB::MapMintPool() +std::map > > CWalletDB::MapMintPool() { - std::map > > mapPool; + std::map > > mapPool; Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; for (;;) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("mintpool"), uint256(0)); + ssKey << std::make_pair(std::string("mintpool"), uint256(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -1404,11 +1405,11 @@ std::map > > CWalletDB::MapMintPool else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__)+" : error scanning DB"); + throw std::runtime_error(std::string(__func__)+" : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "mintpool") break; @@ -1422,15 +1423,15 @@ std::map > > CWalletDB::MapMintPool uint32_t nCount; ssValue >> nCount; - pair pMint; + std::pair pMint; pMint.first = hashPubcoin; pMint.second = nCount; if (mapPool.count(hashMasterSeed)) { mapPool.at(hashMasterSeed).emplace_back(pMint); } else { - vector > vPairs; + std::vector > vPairs; vPairs.emplace_back(pMint); - mapPool.insert(make_pair(hashMasterSeed, vPairs)); + mapPool.insert(std::make_pair(hashMasterSeed, vPairs)); } } @@ -1444,14 +1445,14 @@ std::list CWalletDB::ListDeterministicMints() std::list listMints; Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; for (;;) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("dzphr"), uint256(0)); + ssKey << std::make_pair(std::string("dzphr"), uint256(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -1460,11 +1461,11 @@ std::list CWalletDB::ListDeterministicMints() else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__)+" : error scanning DB"); + throw std::runtime_error(std::string(__func__)+" : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "dzphr") break; @@ -1487,16 +1488,16 @@ std::list CWalletDB::ListMintedCoins() std::list listPubCoin; Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; - vector vOverWrite; - vector vArchive; + std::vector vOverWrite; + std::vector vArchive; for (;;) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("zerocoin"), uint256(0)); + ssKey << std::make_pair(std::string("zerocoin"), uint256(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -1505,11 +1506,11 @@ std::list CWalletDB::ListMintedCoins() else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__)+" : error scanning DB"); + throw std::runtime_error(std::string(__func__)+" : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "zerocoin") break; @@ -1532,14 +1533,14 @@ std::list CWalletDB::ListSpentCoins() std::list listCoinSpend; Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; for (;;) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("zcserial"), CBigNum(0)); + ssKey << std::make_pair(std::string("zcserial"), CBigNum(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -1548,11 +1549,11 @@ std::list CWalletDB::ListSpentCoins() else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__)+" : error scanning DB"); + throw std::runtime_error(std::string(__func__)+" : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "zcserial") break; @@ -1575,7 +1576,7 @@ std::list CWalletDB::ListSpentCoinsSerial() { std::list listPubCoin; std::list listCoins = ListSpentCoins(); - + for ( auto& coin : listCoins) { listPubCoin.push_back(coin.GetSerial()); } @@ -1587,14 +1588,14 @@ std::list CWalletDB::ListArchivedZerocoins() std::list listMints; Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; for (;;) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("zco"), CBigNum(0)); + ssKey << std::make_pair(std::string("zco"), CBigNum(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -1603,11 +1604,11 @@ std::list CWalletDB::ListArchivedZerocoins() else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__)+" : error scanning DB"); + throw std::runtime_error(std::string(__func__)+" : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "zco") break; @@ -1630,14 +1631,14 @@ std::list CWalletDB::ListArchivedDeterministicMints() std::list listMints; Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; for (;;) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << make_pair(string("dzco"), CBigNum(0)); + ssKey << std::make_pair(std::string("dzco"), CBigNum(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -1646,11 +1647,11 @@ std::list CWalletDB::ListArchivedDeterministicMints() else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__)+" : error scanning DB"); + throw std::runtime_error(std::string(__func__)+" : error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "dzco") break; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 0b9748ef8e50..00fa6c94e236 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -228,15 +228,15 @@ class CWalletDB : public CDB bool ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial); bool WriteCurrentSeedHash(const uint256& hashSeed); bool ReadCurrentSeedHash(uint256& hashSeed); - bool WriteZPHRSeed(const uint256& hashSeed, const vector& seed); - bool ReadZPHRSeed(const uint256& hashSeed, vector& seed); + bool WriteZPHRSeed(const uint256& hashSeed, const std::vector& seed); + bool ReadZPHRSeed(const uint256& hashSeed, std::vector& seed); bool ReadZPHRSeed_deprecated(uint256& seed); bool EraseZPHRSeed(); bool EraseZPHRSeed_deprecated(); bool WriteZPHRCount(const uint32_t& nCount); bool ReadZPHRCount(uint32_t& nCount); - std::map > > MapMintPool(); + std::map > > MapMintPool(); bool WriteMintPoolPair(const uint256& hashMasterSeed, const uint256& hashPubcoin, const uint32_t& nCount); private: @@ -246,7 +246,7 @@ class CWalletDB : public CDB bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry); }; -void NotifyBacked(const CWallet& wallet, bool fSuccess, string strMessage); +void NotifyBacked(const CWallet& wallet, bool fSuccess, std::string strMessage); bool BackupWallet(const CWallet& wallet, const boost::filesystem::path& strDest, bool fEnableCustom = true); bool AttemptBackupWallet(const CWallet& wallet, const boost::filesystem::path& pathSrc, const boost::filesystem::path& pathDest); diff --git a/src/wallet_ismine.cpp b/src/wallet_ismine.cpp index 19e23c34efdd..2695395783e3 100644 --- a/src/wallet_ismine.cpp +++ b/src/wallet_ismine.cpp @@ -11,7 +11,7 @@ #include "script/standard.h" #include "script/sign.h" -#include + typedef std::vector valtype; diff --git a/src/zphrtracker.cpp b/src/zphrtracker.cpp index 509952885f2b..be6845171ce0 100644 --- a/src/zphrtracker.cpp +++ b/src/zphrtracker.cpp @@ -11,7 +11,6 @@ #include "wallet/walletdb.h" #include "accumulators.h" -using namespace std; CzPHRTracker::CzPHRTracker(std::string strWalletFile) { @@ -111,7 +110,7 @@ bool CzPHRTracker::GetMetaFromStakeHash(const uint256& hashStake, CMintMeta& met std::vector CzPHRTracker::GetSerialHashes() { - vector vHashes; + std::vector vHashes; for (auto it : mapSerialHashes) { if (it.second.isArchived) continue; @@ -129,7 +128,7 @@ CAmount CzPHRTracker::GetBalance(bool fConfirmedOnly, bool fUnconfirmedOnly) con //! zerocoin specific fields std::map myZerocoinSupply; for (auto& denom : libzerocoin::zerocoinDenomList) { - myZerocoinSupply.insert(make_pair(denom, 0)); + myZerocoinSupply.insert(std::make_pair(denom, 0)); } { @@ -166,7 +165,7 @@ CAmount CzPHRTracker::GetUnconfirmedBalance() const std::vector CzPHRTracker::GetMints(bool fConfirmedOnly) const { - vector vMints; + std::vector vMints; for (auto& it : mapSerialHashes) { CMintMeta mint = it.second; if (mint.isArchived || mint.isUsed) @@ -325,7 +324,7 @@ void CzPHRTracker::SetPubcoinUsed(const uint256& hashPubcoin, const uint256& txi return; CMintMeta meta = GetMetaFromPubcoin(hashPubcoin); meta.isUsed = true; - mapPendingSpends.insert(make_pair(meta.hashSerial, txid)); + mapPendingSpends.insert(std::make_pair(meta.hashSerial, txid)); UpdateState(meta); } diff --git a/src/zphrwallet.cpp b/src/zphrwallet.cpp index dd4c5f022b17..4ab1cac104d1 100644 --- a/src/zphrwallet.cpp +++ b/src/zphrwallet.cpp @@ -10,7 +10,6 @@ #include "wallet/wallet.h" #include "primitives/deterministicmint.h" -using namespace libzerocoin; CzPHRWallet::CzPHRWallet(std::string strWalletFile) { @@ -156,7 +155,7 @@ void CzPHRWallet::GenerateMintPool(uint32_t nCountStart, uint32_t nCountEnd) // pubcoin hashes are stored to db so that a full accounting of mints belonging to the seed can be tracked without regenerating bool CzPHRWallet::LoadMintPoolFromDB() { - map > > mapMintPool = CWalletDB(strWalletFile).MapMintPool(); + std::map > > mapMintPool = CWalletDB(strWalletFile).MapMintPool(); uint256 hashSeed = Hash(seedMaster.begin(), seedMaster.end()); for (auto& pair : mapMintPool[hashSeed]) @@ -184,7 +183,7 @@ void CzPHRWallet::SyncWithChain(bool fGenerateMintPool) bool found = true; CWalletDB walletdb(strWalletFile); - set setAddedTx; + std::set setAddedTx; while (found) { found = false; if (fGenerateMintPool) @@ -192,8 +191,8 @@ void CzPHRWallet::SyncWithChain(bool fGenerateMintPool) LogPrintf("%s: Mintpool size=%d\n", __func__, mintPool.size()); std::set setChecked; - list > listMints = mintPool.List(); - for (pair pMint : listMints) { + std::list > listMints = mintPool.List(); + for (std::pair pMint : listMints) { LOCK(cs_main); if (setChecked.count(pMint.first)) return; @@ -224,14 +223,14 @@ void CzPHRWallet::SyncWithChain(bool fGenerateMintPool) } //Find the denomination - CoinDenomination denomination = CoinDenomination::ZQ_ERROR; + libzerocoin::CoinDenomination denomination = libzerocoin::CoinDenomination::ZQ_ERROR; bool fFoundMint = false; CBigNum bnValue = 0; for (const CTxOut& out : tx.vout) { if (!out.scriptPubKey.IsZerocoinMint()) continue; - PublicCoin pubcoin(Params().Zerocoin_Params()); + libzerocoin::PublicCoin pubcoin(Params().Zerocoin_Params()); CValidationState state; if (!TxOutToPublicCoin(out, pubcoin, state)) { LogPrintf("%s : failed to get mint from txout for %s!\n", __func__, pMint.first.GetHex()); @@ -248,7 +247,7 @@ void CzPHRWallet::SyncWithChain(bool fGenerateMintPool) } } - if (!fFoundMint || denomination == ZQ_ERROR) { + if (!fFoundMint || denomination == libzerocoin::ZQ_ERROR) { LogPrintf("%s : failed to get mint %s from tx %s!\n", __func__, pMint.first.GetHex(), tx.GetHash().GetHex()); found = false; break; @@ -279,11 +278,11 @@ void CzPHRWallet::SyncWithChain(bool fGenerateMintPool) } } -bool CzPHRWallet::SetMintSeen(const CBigNum& bnValue, const int& nHeight, const uint256& txid, const CoinDenomination& denom) +bool CzPHRWallet::SetMintSeen(const CBigNum& bnValue, const int& nHeight, const uint256& txid, const libzerocoin::CoinDenomination& denom) { if (!mintPool.Has(bnValue)) return error("%s: value not in pool", __func__); - pair pMint = mintPool.Get(bnValue); + std::pair pMint = mintPool.Get(bnValue); // Regenerate the mint uint512 seedZerocoin = GetZerocoinSeed(pMint.second); @@ -303,7 +302,7 @@ bool CzPHRWallet::SetMintSeen(const CBigNum& bnValue, const int& nHeight, const uint256 hashPubcoin = GetPubCoinHash(bnValue); uint256 nSerial = bnSerial.getuint256(); uint256 hashStake = Hash(nSerial.begin(), nSerial.end()); - CDeterministicMint dMint(PrivateCoin::CURRENT_VERSION, pMint.second, hashSeed, hashSerial, hashPubcoin, hashStake); + CDeterministicMint dMint(libzerocoin::PrivateCoin::CURRENT_VERSION, pMint.second, hashSeed, hashSerial, hashPubcoin, hashStake); dMint.SetDenomination(denom); dMint.SetHeight(nHeight); dMint.SetTxHash(txid); @@ -351,7 +350,7 @@ bool IsValidCoinValue(const CBigNum& bnValue) void CzPHRWallet::SeedToZPHR(const uint512& seedZerocoin, CBigNum& bnValue, CBigNum& bnSerial, CBigNum& bnRandomness, CKey& key) { - ZerocoinParams* params = Params().Zerocoin_Params(); + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(); //convert state seed into a seed for the private key uint256 nSeedPrivKey = seedZerocoin.trim256(); @@ -413,7 +412,7 @@ void CzPHRWallet::UpdateCount() walletdb.WriteZPHRCount(nCountLastUsed); } -void CzPHRWallet::GenerateDeterministicZPHR(CoinDenomination denom, PrivateCoin& coin, CDeterministicMint& dMint, bool fGenerateOnly) +void CzPHRWallet::GenerateDeterministicZPHR(libzerocoin::CoinDenomination denom, libzerocoin::PrivateCoin& coin, CDeterministicMint& dMint, bool fGenerateOnly) { GenerateMint(nCountLastUsed + 1, denom, coin, dMint); if (fGenerateOnly) @@ -423,7 +422,7 @@ void CzPHRWallet::GenerateDeterministicZPHR(CoinDenomination denom, PrivateCoin& //LogPrintf("%s : Generated new deterministic mint. Count=%d pubcoin=%s seed=%s\n", __func__, nCount, coin.getPublicCoin().getValue().GetHex().substr(0,6), seedZerocoin.GetHex().substr(0, 4)); } -void CzPHRWallet::GenerateMint(const uint32_t& nCount, const CoinDenomination denom, PrivateCoin& coin, CDeterministicMint& dMint) +void CzPHRWallet::GenerateMint(const uint32_t& nCount, const libzerocoin::CoinDenomination denom, libzerocoin::PrivateCoin& coin, CDeterministicMint& dMint) { uint512 seedZerocoin = GetZerocoinSeed(nCount); CBigNum bnValue; @@ -431,9 +430,9 @@ void CzPHRWallet::GenerateMint(const uint32_t& nCount, const CoinDenomination de CBigNum bnRandomness; CKey key; SeedToZPHR(seedZerocoin, bnValue, bnSerial, bnRandomness, key); - coin = PrivateCoin(Params().Zerocoin_Params(), denom, bnSerial, bnRandomness); + coin = libzerocoin::PrivateCoin(Params().Zerocoin_Params(), denom, bnSerial, bnRandomness); coin.setPrivKey(key.GetPrivKey()); - coin.setVersion(PrivateCoin::CURRENT_VERSION); + coin.setVersion(libzerocoin::PrivateCoin::CURRENT_VERSION); uint256 hashSeed = Hash(seedMaster.begin(), seedMaster.end()); uint256 hashSerial = GetSerialHash(bnSerial); @@ -452,7 +451,7 @@ bool CzPHRWallet::RegenerateMint(const CDeterministicMint& dMint, CZerocoinMint& return error("%s: master seed does not match!\ndmint:\n %s \nhashSeed: %s\nseed: %s", __func__, dMint.ToString(), hashSeed.GetHex(), seedMaster.GetHex()); //Generate the coin - PrivateCoin coin(Params().Zerocoin_Params(), dMint.GetDenomination(), false); + libzerocoin::PrivateCoin coin(Params().Zerocoin_Params(), dMint.GetDenomination(), false); CDeterministicMint dMintDummy; GenerateMint(dMint.GetCount(), dMint.GetDenomination(), coin, dMintDummy); diff --git a/test/README.md b/test/README.md new file mode 100644 index 000000000000..590acec47205 --- /dev/null +++ b/test/README.md @@ -0,0 +1,187 @@ +This directory contains integration tests that test phored and its +utilities in their entirety. It does not contain unit tests, which +can be found in [/src/test](/src/test), [/src/wallet/test](/src/wallet/test), +etc. + +There are currently two sets of tests in this directory: + +- [functional](/test/functional) which test the functionality of +phored and phore-qt by interacting with them through the RPC and P2P +interfaces. +- [util](/test/util) which tests the phore utilities, currently only +phore-tx. + +The util tests are run as part of `make check` target. The functional +tests are run by the travis continuous build process whenever a pull +request is opened. Both sets of tests can also be run locally. + +# Running tests locally + +Build for your system first. Be sure to enable wallet, utils and daemon when you configure. Tests will not run otherwise. + +### Functional tests + +#### Dependencies + +The ZMQ functional test requires a python ZMQ library. To install it: + +- on Unix, run `sudo apt-get install python3-zmq` +- on mac OS, run `pip3 install pyzmq` + +#### Running the tests + +Individual tests can be run by directly calling the test script, eg: + +``` +test/functional/feature_rbf.py +``` + +or can be run through the test_runner harness, eg: + +``` +test/functional/test_runner.py feature_rbf.py +``` + +You can run any combination (incl. duplicates) of tests by calling: + +``` +test/functional/test_runner.py ... +``` + +Run the regression test suite with: + +``` +test/functional/test_runner.py +``` + +Run all possible tests with + +``` +test/functional/test_runner.py --extended +``` + +By default, up to 4 tests will be run in parallel by test_runner. To specify +how many jobs to run, append `--jobs=n` + +The individual tests and the test_runner harness have many command-line +options. Run `test_runner.py -h` to see them all. + +#### Troubleshooting and debugging test failures + +##### Resource contention + +The P2P and RPC ports used by the phored nodes-under-test are chosen to make +conflicts with other processes unlikely. However, if there is another phored +process running on the system (perhaps from a previous test which hasn't successfully +killed all its phored nodes), then there may be a port conflict which will +cause the test to fail. It is recommended that you run the tests on a system +where no other phored processes are running. + +On linux, the test_framework will warn if there is another +phored process running when the tests are started. + +If there are zombie phored processes after test failure, you can kill them +by running the following commands. **Note that these commands will kill all +phored processes running on the system, so should not be used if any non-test +phored processes are being run.** + +```bash +killall phored +``` + +or + +```bash +pkill -9 phored +``` + + +##### Data directory cache + +A pre-mined blockchain with 200 blocks is generated the first time a +functional test is run and is stored in test/cache. This speeds up +test startup times since new blockchains don't need to be generated for +each test. However, the cache may get into a bad state, in which case +tests will fail. If this happens, remove the cache directory (and make +sure phored processes are stopped as above): + +```bash +rm -rf cache +killall phored +``` + +##### Test logging + +The tests contain logging at different levels (debug, info, warning, etc). By +default: + +- when run through the test_runner harness, *all* logs are written to + `test_framework.log` and no logs are output to the console. +- when run directly, *all* logs are written to `test_framework.log` and INFO + level and above are output to the console. +- when run on Travis, no logs are output to the console. However, if a test + fails, the `test_framework.log` and phored `debug.log`s will all be dumped + to the console to help troubleshooting. + +To change the level of logs output to the console, use the `-l` command line +argument. + +`test_framework.log` and phored `debug.log`s can be combined into a single +aggregate log by running the `combine_logs.py` script. The output can be plain +text, colorized text or html. For example: + +``` +combine_logs.py -c | less -r +``` + +will pipe the colorized logs from the test into less. + +Use `--tracerpc` to trace out all the RPC calls and responses to the console. For +some tests (eg any that use `submitblock` to submit a full block over RPC), +this can result in a lot of screen output. + +By default, the test data directory will be deleted after a successful run. +Use `--nocleanup` to leave the test data directory intact. The test data +directory is never deleted after a failed test. + +##### Attaching a debugger + +A python debugger can be attached to tests at any point. Just add the line: + +```py +import pdb; pdb.set_trace() +``` + +anywhere in the test. You will then be able to inspect variables, as well as +call methods that interact with the phored nodes-under-test. + +If further introspection of the phored instances themselves becomes +necessary, this can be accomplished by first setting a pdb breakpoint +at an appropriate location, running the test to that point, then using +`gdb` to attach to the process and debug. + +For instance, to attach to `self.node[1]` during a run: + +```bash +2017-06-27 14:13:56.686000 TestFramework (INFO): Initializing test directory /tmp/user/1000/testo9vsdjo3 +``` + +use the directory path to get the pid from the pid file: + +```bash +cat /tmp/user/1000/testo9vsdjo3/node1/regtest/phored.pid +gdb /home/example/phored +``` + +Note: gdb attach step may require `sudo` + +### Util tests + +Util tests can be run locally by running `test/util/bitcoin-util-test.py`. +Use the `-v` option for verbose output. + +# Writing functional tests + +You are encouraged to write functional tests for new or existing features. +Further information about the functional test framework and individual +tests is found in [test/functional](/test/functional). diff --git a/test/functional/__init__.py b/test/functional/__init__.py old mode 100644 new mode 100755 diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py new file mode 100755 index 000000000000..8e9511699250 --- /dev/null +++ b/test/functional/create_cache.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Create a blockchain cache. +Creating a cache of the blockchain speeds up test execution when running +multiple functional tests. This helper script is executed by test_runner when multiple +tests are being run in parallel. +""" + +from test_framework.test_framework import BitcoinTestFramework + +class CreateCache(BitcoinTestFramework): + # Test network and test nodes are not required: + + def set_test_params(self): + self.num_nodes = 0 + self.supports_cli = True + + def setup_network(self): + pass + + def run_test(self): + pass + +if __name__ == '__main__': + CreateCache().main() \ No newline at end of file diff --git a/test/functional/decodetx.py b/test/functional/decodetx.py old mode 100644 new mode 100755 diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py old mode 100644 new mode 100755 diff --git a/test/functional/segwit.py b/test/functional/segwit.py old mode 100644 new mode 100755 diff --git a/test/functional/test_case_base.py b/test/functional/test_case_base.py old mode 100644 new mode 100755 diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py old mode 100644 new mode 100755 index 876f00e1fdaf..73c866b660a3 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -117,7 +117,7 @@ def main(): logging.basicConfig(format='%(message)s', level=logging_level) # Create base test directory - tmpdir = "%s/pivx_test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) + tmpdir = "%s/PHORE_test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) os.makedirs(tmpdir) logging.debug("Temporary test directory at %s" % tmpdir) @@ -215,14 +215,6 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove else: coverage = None - if len(test_list) > 1 and jobs > 1: - # Populate cache - try: - subprocess.check_output([tests_dir + 'create_cache.py'] + flags + ["--tmpdir=%s/cache" % tmpdir]) - except subprocess.CalledProcessError as e: - sys.stdout.buffer.write(e.output) - raise - #Run Tests job_queue = TestHandler(jobs, tests_dir, tmpdir, test_list, flags) time0 = time.time() diff --git a/test/functional/wallet.py b/test/functional/wallet.py old mode 100644 new mode 100755 diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py old mode 100644 new mode 100755 diff --git a/test/functional/zerocoin.py b/test/functional/zerocoin.py old mode 100644 new mode 100755 diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py new file mode 100755 index 000000000000..92fef30e1345 --- /dev/null +++ b/test/util/bitcoin-util-test.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# Copyright 2014 BitPay Inc. +# Copyright 2016-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test framework for bitcoin utils. + +Runs automatically during `make check`. + +Can also be run manually.""" + +from __future__ import division,print_function,unicode_literals + +import argparse +import binascii +try: + import configparser +except ImportError: + import ConfigParser as configparser +import difflib +import json +import logging +import os +import pprint +import subprocess +import sys + +def main(): + config = configparser.ConfigParser() + config.optionxform = str + config.read_file(open(os.path.join(os.path.dirname(__file__), "../config.ini"), encoding="utf8")) + env_conf = dict(config.items('environment')) + + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('-v', '--verbose', action='store_true') + args = parser.parse_args() + verbose = args.verbose + + if verbose: + level = logging.DEBUG + else: + level = logging.ERROR + formatter = '%(asctime)s - %(levelname)s - %(message)s' + # Add the format/level to the logger + logging.basicConfig(format=formatter, level=level) + + bctester(os.path.join(env_conf["SRCDIR"], "test", "util", "data"), "bitcoin-util-test.json", env_conf) + +def bctester(testDir, input_basename, buildenv): + """ Loads and parses the input file, runs all tests and reports results""" + input_filename = os.path.join(testDir, input_basename) + raw_data = open(input_filename, encoding="utf8").read() + input_data = json.loads(raw_data) + + failed_testcases = [] + + for testObj in input_data: + try: + bctest(testDir, testObj, buildenv) + logging.info("PASSED: " + testObj["description"]) + except: + logging.info("FAILED: " + testObj["description"]) + failed_testcases.append(testObj["description"]) + + if failed_testcases: + error_message = "FAILED_TESTCASES:\n" + error_message += pprint.pformat(failed_testcases, width=400) + logging.error(error_message) + sys.exit(1) + else: + sys.exit(0) + +def bctest(testDir, testObj, buildenv): + """Runs a single test, comparing output and RC to expected output and RC. + + Raises an error if input can't be read, executable fails, or output/RC + are not as expected. Error is caught by bctester() and reported. + """ + # Get the exec names and arguments + execprog = os.path.join(buildenv["BUILDDIR"], "src", testObj["exec"] + buildenv["EXEEXT"]) + execargs = testObj['args'] + execrun = [execprog] + execargs + + # Read the input data (if there is any) + stdinCfg = None + inputData = None + if "input" in testObj: + filename = os.path.join(testDir, testObj["input"]) + inputData = open(filename, encoding="utf8").read() + stdinCfg = subprocess.PIPE + + # Read the expected output data (if there is any) + outputFn = None + outputData = None + outputType = None + if "output_cmp" in testObj: + outputFn = testObj['output_cmp'] + outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare) + try: + outputData = open(os.path.join(testDir, outputFn), encoding="utf8").read() + except: + logging.error("Output file " + outputFn + " can not be opened") + raise + if not outputData: + logging.error("Output data missing for " + outputFn) + raise Exception + if not outputType: + logging.error("Output file %s does not have a file extension" % outputFn) + raise Exception + + # Run the test + proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + try: + outs = proc.communicate(input=inputData) + except OSError: + logging.error("OSError, Failed to execute " + execprog) + raise + + if outputData: + data_mismatch, formatting_mismatch = False, False + # Parse command output and expected output + try: + a_parsed = parse_output(outs[0], outputType) + except Exception as e: + logging.error('Error parsing command output as %s: %s' % (outputType, e)) + raise + try: + b_parsed = parse_output(outputData, outputType) + except Exception as e: + logging.error('Error parsing expected output %s as %s: %s' % (outputFn, outputType, e)) + raise + # Compare data + if a_parsed != b_parsed: + logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")") + data_mismatch = True + # Compare formatting + if outs[0] != outputData: + error_message = "Output formatting mismatch for " + outputFn + ":\n" + error_message += "".join(difflib.context_diff(outputData.splitlines(True), + outs[0].splitlines(True), + fromfile=outputFn, + tofile="returned")) + logging.error(error_message) + formatting_mismatch = True + + assert not data_mismatch and not formatting_mismatch + + # Compare the return code to the expected return code + wantRC = 0 + if "return_code" in testObj: + wantRC = testObj['return_code'] + if proc.returncode != wantRC: + logging.error("Return code mismatch for " + outputFn) + raise Exception + + if "error_txt" in testObj: + want_error = testObj["error_txt"] + # Compare error text + # TODO: ideally, we'd compare the strings exactly and also assert + # That stderr is empty if no errors are expected. However, bitcoin-tx + # emits DISPLAY errors when running as a windows application on + # linux through wine. Just assert that the expected error text appears + # somewhere in stderr. + if want_error not in outs[1]: + logging.error("Error mismatch:\n" + "Expected: " + want_error + "\nReceived: " + outs[1].rstrip()) + raise Exception + +def parse_output(a, fmt): + """Parse the output according to specified format. + + Raise an error if the output can't be parsed.""" + if fmt == 'json': # json: compare parsed data + return json.loads(a) + elif fmt == 'hex': # hex: parse and compare binary data + return binascii.a2b_hex(a.strip()) + else: + raise NotImplementedError("Don't know how to compare %s" % fmt) + +if __name__ == '__main__': + main() diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json new file mode 100644 index 000000000000..9881e1bef5c5 --- /dev/null +++ b/test/util/data/bitcoin-util-test.json @@ -0,0 +1,148 @@ +[ + { "exec": "./phore-tx", + "args": ["-create"], + "output_cmp": "blanktxv1.hex", + "description": "Creates a blank v1 transaction" + }, + { "exec": "./phore-tx", + "args": ["-json","-create", "nversion=1"], + "output_cmp": "blanktxv1.json", + "description": "Creates a blank v1 transaction (output in json)" + }, + { "exec": "./phore-tx", + "args": ["-"], + "input": "blanktxv1.hex", + "output_cmp": "blanktxv1.hex", + "description": "Creates a blank transaction when nothing is piped into phore-tx" + }, + { "exec": "./phore-tx", + "args": ["-", "delin=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delin1-out.hex", + "description": "Deletes a single input from a transaction" + }, + { "exec": "./phore-tx", + "args": ["-json", "-", "delin=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delin1-out.json", + "description": "Deletes a single input from a transaction (output in json)" + }, + { "exec": "./phore-tx", + "args": ["-", "delin=31"], + "input": "tx394b54bb.hex", + "return_code": 1, + "error_txt": "error: Invalid TX input index '31'", + "description": "Attempts to delete an input with a bad index from a transaction. Expected to fail." + }, + { "exec": "./phore-tx", + "args": ["-", "delout=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delout1-out.hex", + "description": "Deletes a single output from a transaction" + }, + { "exec": "./phore-tx", + "args": ["-json", "-", "delout=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delout1-out.json", + "description": "Deletes a single output from a transaction (output in json)" + }, + { "exec": "./phore-tx", + "args": ["-", "delout=2"], + "input": "tx394b54bb.hex", + "return_code": 1, + "error_txt": "error: Invalid TX output index '2'", + "description": "Attempts to delete an output with a bad index from a transaction. Expected to fail." + }, + { "exec": "./phore-tx", + "args": ["-", "locktime=317000"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-locktime317000-out.hex", + "description": "Adds an nlocktime to a transaction" + }, + { "exec": "./phore-tx", + "args": ["-json", "-", "locktime=317000"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-locktime317000-out.json", + "description": "Adds an nlocktime to a transaction (output in json)" + }, + { "exec": "./phore-tx", + "args": + ["-create", + "outaddr=1"], + "return_code": 1, + "error_txt": "error: TX output missing separator", + "description": "Malformed outaddr argument (no address specified). Expected to fail." + }, + { "exec": "./phore-tx", + "args": + ["-create", + "outaddr=1:DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71:garbage"], + "return_code": 1, + "error_txt": "error: invalid TX output address", + "description": "Malformed outaddr argument (too many separators). Expected to fail." + }, + { "exec": "./phore-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", + "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", + "outaddr=0.18:DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71", + "outaddr=4:D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"], + "output_cmp": "txcreate1.hex", + "description": "Creates a new transaction with three inputs and two outputs" + }, + { "exec": "./phore-tx", + "args": + ["-json", + "-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", + "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", + "outaddr=0.18:DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71", + "outaddr=4:D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"], + "output_cmp": "txcreate1.json", + "description": "Creates a new transaction with three inputs and two outputs (output in json)" + }, + { "exec": "./phore-tx", + "args": ["-create", "outscript=0:"], + "output_cmp": "txcreate2.hex", + "description": "Creates a new transaction with a single empty output script" + }, + { "exec": "./phore-tx", + "args": ["-json", "-create", "outscript=0:"], + "output_cmp": "txcreate2.json", + "description": "Creates a new transaction with a single empty output script (output in json)" + }, + { "exec": "./phore-tx", + "args": ["01000000000100000000000000000000000000"], + "output_cmp": "txcreate2.hex", + "description": "Parses a transaction with no inputs and a single output script" + }, + { "exec": "./phore-tx", + "args": ["-json", "01000000000100000000000000000000000000"], + "output_cmp": "txcreate2.json", + "description": "Parses a transaction with no inputs and a single output script (output in json)" + }, + { "exec": "./phore-tx", + "args": ["-create", "outscript=0:OP_DROP", "nversion=1"], + "output_cmp": "txcreatescript1.hex", + "description": "Create a new transaction with a single output script (OP_DROP)" + }, + { "exec": "./phore-tx", + "args": ["-json", "-create", "outscript=0:OP_DROP", "nversion=1"], + "output_cmp": "txcreatescript1.json", + "description": "Create a new transaction with a single output script (OP_DROP) (output as json)" + }, + { "exec": "./phore-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"891ns7GR4owBiozmFa8jDSaJWNZ2q4XoSYdUS2kSNuKJ9BaxLkC\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]", + "sign=ALL", + "outaddr=0.001:D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"], + "output_cmp": "txcreatesign.hex", + "description": "Creates a new transaction with a single input and a single output, and then signs the transaction" + } +] diff --git a/src/test/data/blanktx.hex b/test/util/data/blanktxv1.hex similarity index 100% rename from src/test/data/blanktx.hex rename to test/util/data/blanktxv1.hex diff --git a/test/util/data/blanktxv1.json b/test/util/data/blanktxv1.json new file mode 100644 index 000000000000..f6d6ab58842c --- /dev/null +++ b/test/util/data/blanktxv1.json @@ -0,0 +1,10 @@ +{ + "txid": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43", + "version": 1, + "locktime": 0, + "vin": [ + ], + "vout": [ + ], + "hex": "01000000000000000000" +} diff --git a/src/test/data/tt-delin1-out.hex b/test/util/data/tt-delin1-out.hex similarity index 100% rename from src/test/data/tt-delin1-out.hex rename to test/util/data/tt-delin1-out.hex diff --git a/test/util/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json new file mode 100644 index 000000000000..a1260c26a54d --- /dev/null +++ b/test/util/data/tt-delin1-out.json @@ -0,0 +1,216 @@ +{ + "txid": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd", + "vout": 332, + "scriptSig": { + "asm": "3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1", + "vout": 1, + "scriptSig": { + "asm": "3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba01 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34", + "hex": "473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34" + }, + "sequence": 4294967295 + }, + { + "txid": "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed", + "vout": 209, + "scriptSig": { + "asm": "304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df", + "vout": 0, + "scriptSig": { + "asm": "3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d813437401 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52", + "hex": "483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52" + }, + "sequence": 4294967295 + }, + { + "txid": "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae", + "vout": 1, + "scriptSig": { + "asm": "3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a40801 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3", + "vout": 0, + "scriptSig": { + "asm": "3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f96701 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52", + "hex": "483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52" + }, + "sequence": 4294967295 + }, + { + "txid": "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485", + "vout": 21, + "scriptSig": { + "asm": "3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282", + "vout": 9, + "scriptSig": { + "asm": "304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e769300517701 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88", + "vout": 30, + "scriptSig": { + "asm": "30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa40401 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766", + "vout": 114, + "scriptSig": { + "asm": "304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02", + "vout": 103, + "scriptSig": { + "asm": "3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816", + "vout": 1, + "scriptSig": { + "asm": "3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd", + "hex": "483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd" + }, + "sequence": 4294967295 + }, + { + "txid": "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19", + "vout": 0, + "scriptSig": { + "asm": "304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a01 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34", + "hex": "49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34" + }, + "sequence": 4294967295 + }, + { + "txid": "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920", + "vout": 221, + "scriptSig": { + "asm": "3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150", + "vout": 1, + "scriptSig": { + "asm": "3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd", + "hex": "483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd" + }, + "sequence": 4294967295 + }, + { + "txid": "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55", + "vout": 27, + "scriptSig": { + "asm": "304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057", + "vout": 1095, + "scriptSig": { + "asm": "304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c901 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f", + "vout": 37, + "scriptSig": { + "asm": "3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f801 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241", + "vout": 20, + "scriptSig": { + "asm": "304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f132101 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236", + "vout": 242, + "scriptSig": { + "asm": "3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d6801 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 1.3782, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "DJFXow7CYcBWKVjwe1VH4or5f6YetLH1hw" + ] + } + }, + { + "value": 0.01000001, + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "DF2cHtiK4xeXPUBhMdK7XWU5UNYSg2KFvt" + ] + } + } + ], + "hex": "0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000" +} diff --git a/src/test/data/tt-delout1-out.hex b/test/util/data/tt-delout1-out.hex similarity index 100% rename from src/test/data/tt-delout1-out.hex rename to test/util/data/tt-delout1-out.hex diff --git a/test/util/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json new file mode 100644 index 000000000000..f8e76a839eb7 --- /dev/null +++ b/test/util/data/tt-delout1-out.json @@ -0,0 +1,212 @@ +{ + "txid": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd", + "vout": 332, + "scriptSig": { + "asm": "3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "a72ec96bd0d022d1b0c2f9078cdd46b3725b8eecdd001e17b21e3ababad14ecb", + "vout": 0, + "scriptSig": { + "asm": "3046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba01 03e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505", + "hex": "493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505" + }, + "sequence": 4294967295 + }, + { + "txid": "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1", + "vout": 1, + "scriptSig": { + "asm": "3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba01 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34", + "hex": "473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34" + }, + "sequence": 4294967295 + }, + { + "txid": "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed", + "vout": 209, + "scriptSig": { + "asm": "304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df", + "vout": 0, + "scriptSig": { + "asm": "3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d813437401 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52", + "hex": "483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52" + }, + "sequence": 4294967295 + }, + { + "txid": "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae", + "vout": 1, + "scriptSig": { + "asm": "3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a40801 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3", + "vout": 0, + "scriptSig": { + "asm": "3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f96701 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52", + "hex": "483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52" + }, + "sequence": 4294967295 + }, + { + "txid": "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485", + "vout": 21, + "scriptSig": { + "asm": "3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282", + "vout": 9, + "scriptSig": { + "asm": "304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e769300517701 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88", + "vout": 30, + "scriptSig": { + "asm": "30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa40401 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766", + "vout": 114, + "scriptSig": { + "asm": "304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02", + "vout": 103, + "scriptSig": { + "asm": "3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816", + "vout": 1, + "scriptSig": { + "asm": "3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd", + "hex": "483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd" + }, + "sequence": 4294967295 + }, + { + "txid": "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19", + "vout": 0, + "scriptSig": { + "asm": "304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a01 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34", + "hex": "49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34" + }, + "sequence": 4294967295 + }, + { + "txid": "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920", + "vout": 221, + "scriptSig": { + "asm": "3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150", + "vout": 1, + "scriptSig": { + "asm": "3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd", + "hex": "483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd" + }, + "sequence": 4294967295 + }, + { + "txid": "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55", + "vout": 27, + "scriptSig": { + "asm": "304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057", + "vout": 1095, + "scriptSig": { + "asm": "304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c901 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f", + "vout": 37, + "scriptSig": { + "asm": "3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f801 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241", + "vout": 20, + "scriptSig": { + "asm": "304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f132101 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236", + "vout": 242, + "scriptSig": { + "asm": "3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d6801 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 1.3782, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "DJFXow7CYcBWKVjwe1VH4or5f6YetLH1hw" + ] + } + } + ], + "hex": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000" +} diff --git a/src/test/data/tt-locktime317000-out.hex b/test/util/data/tt-locktime317000-out.hex similarity index 100% rename from src/test/data/tt-locktime317000-out.hex rename to test/util/data/tt-locktime317000-out.hex diff --git a/test/util/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json new file mode 100644 index 000000000000..022c5ef301bf --- /dev/null +++ b/test/util/data/tt-locktime317000-out.json @@ -0,0 +1,225 @@ +{ + "txid": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5", + "version": 1, + "locktime": 317000, + "vin": [ + { + "txid": "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd", + "vout": 332, + "scriptSig": { + "asm": "3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "a72ec96bd0d022d1b0c2f9078cdd46b3725b8eecdd001e17b21e3ababad14ecb", + "vout": 0, + "scriptSig": { + "asm": "3046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba01 03e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505", + "hex": "493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505" + }, + "sequence": 4294967295 + }, + { + "txid": "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1", + "vout": 1, + "scriptSig": { + "asm": "3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba01 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34", + "hex": "473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34" + }, + "sequence": 4294967295 + }, + { + "txid": "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed", + "vout": 209, + "scriptSig": { + "asm": "304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df", + "vout": 0, + "scriptSig": { + "asm": "3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d813437401 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52", + "hex": "483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52" + }, + "sequence": 4294967295 + }, + { + "txid": "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae", + "vout": 1, + "scriptSig": { + "asm": "3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a40801 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3", + "vout": 0, + "scriptSig": { + "asm": "3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f96701 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52", + "hex": "483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52" + }, + "sequence": 4294967295 + }, + { + "txid": "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485", + "vout": 21, + "scriptSig": { + "asm": "3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282", + "vout": 9, + "scriptSig": { + "asm": "304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e769300517701 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88", + "vout": 30, + "scriptSig": { + "asm": "30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa40401 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766", + "vout": 114, + "scriptSig": { + "asm": "304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02", + "vout": 103, + "scriptSig": { + "asm": "3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816", + "vout": 1, + "scriptSig": { + "asm": "3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd", + "hex": "483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd" + }, + "sequence": 4294967295 + }, + { + "txid": "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19", + "vout": 0, + "scriptSig": { + "asm": "304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a01 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34", + "hex": "49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34" + }, + "sequence": 4294967295 + }, + { + "txid": "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920", + "vout": 221, + "scriptSig": { + "asm": "3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f01 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + }, + { + "txid": "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150", + "vout": 1, + "scriptSig": { + "asm": "3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd", + "hex": "483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd" + }, + "sequence": 4294967295 + }, + { + "txid": "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55", + "vout": 27, + "scriptSig": { + "asm": "304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc01 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057", + "vout": 1095, + "scriptSig": { + "asm": "304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c901 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f", + "vout": 37, + "scriptSig": { + "asm": "3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f801 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241", + "vout": 20, + "scriptSig": { + "asm": "304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f132101 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c", + "hex": "48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c" + }, + "sequence": 4294967295 + }, + { + "txid": "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236", + "vout": 242, + "scriptSig": { + "asm": "3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d6801 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc", + "hex": "493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 1.3782, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "DJFXow7CYcBWKVjwe1VH4or5f6YetLH1hw" + ] + } + }, + { + "value": 0.01000001, + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "DF2cHtiK4xeXPUBhMdK7XWU5UNYSg2KFvt" + ] + } + } + ], + "hex": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400" +} diff --git a/src/test/data/tx394b54bb.hex b/test/util/data/tx394b54bb.hex similarity index 100% rename from src/test/data/tx394b54bb.hex rename to test/util/data/tx394b54bb.hex diff --git a/src/test/data/txcreate1.hex b/test/util/data/txcreate1.hex similarity index 100% rename from src/test/data/txcreate1.hex rename to test/util/data/txcreate1.hex diff --git a/test/util/data/txcreate1.json b/test/util/data/txcreate1.json new file mode 100644 index 000000000000..a40786c59d17 --- /dev/null +++ b/test/util/data/txcreate1.json @@ -0,0 +1,63 @@ +{ + "txid": "bf8ee16a00913c0bacbf86a75f2c00c595e8048724c9f0db9f09ed71fce3c946", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f", + "vout": 0, + "scriptSig": { + "asm": "", + "hex": "" + }, + "sequence": 4294967295 + }, + { + "txid": "bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c", + "vout": 18, + "scriptSig": { + "asm": "", + "hex": "" + }, + "sequence": 4294967295 + }, + { + "txid": "22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc", + "vout": 1, + "scriptSig": { + "asm": "", + "hex": "" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.18, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 ce1c388c454d63b21ebb202010bda79a3b165b4b OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914ce1c388c454d63b21ebb202010bda79a3b165b4b88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71" + ] + } + }, + { + "value": 4.00, + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 14b70d03a3536907a7843f9d9243ddca79d43e38 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91414b70d03a3536907a7843f9d9243ddca79d43e3888ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "D72dLgywmL73JyTwQBfuU29CADz9yCJ99v" + ] + } + } + ], + "hex": "01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a914ce1c388c454d63b21ebb202010bda79a3b165b4b88ac0084d717000000001976a91414b70d03a3536907a7843f9d9243ddca79d43e3888ac00000000" +} diff --git a/src/test/data/txcreate2.hex b/test/util/data/txcreate2.hex similarity index 100% rename from src/test/data/txcreate2.hex rename to test/util/data/txcreate2.hex diff --git a/test/util/data/txcreate2.json b/test/util/data/txcreate2.json new file mode 100644 index 000000000000..c56293eaf2c6 --- /dev/null +++ b/test/util/data/txcreate2.json @@ -0,0 +1,19 @@ +{ + "txid": "cf90229625e9eb10f6be8156bf6aa5ec2eca19a42b1e05c11f3029b560a32e13", + "version": 1, + "locktime": 0, + "vin": [ + ], + "vout": [ + { + "value": 0.00, + "n": 0, + "scriptPubKey": { + "asm": "", + "hex": "", + "type": "nonstandard" + } + } + ], + "hex": "01000000000100000000000000000000000000" +} diff --git a/test/util/data/txcreatescript1.hex b/test/util/data/txcreatescript1.hex new file mode 100644 index 000000000000..0adce270fbec --- /dev/null +++ b/test/util/data/txcreatescript1.hex @@ -0,0 +1 @@ +0100000000010000000000000000017500000000 diff --git a/test/util/data/txcreatescript1.json b/test/util/data/txcreatescript1.json new file mode 100644 index 000000000000..e54564fbada7 --- /dev/null +++ b/test/util/data/txcreatescript1.json @@ -0,0 +1,19 @@ +{ + "txid": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9", + "version": 1, + "locktime": 0, + "vin": [ + ], + "vout": [ + { + "value": 0.00, + "n": 0, + "scriptPubKey": { + "asm": "OP_DROP", + "hex": "75", + "type": "nonstandard" + } + } + ], + "hex": "0100000000010000000000000000017500000000" +} diff --git a/src/test/data/txcreatesign.hex b/test/util/data/txcreatesign.hex similarity index 100% rename from src/test/data/txcreatesign.hex rename to test/util/data/txcreatesign.hex diff --git a/test/util/data/txcreatesign.json b/test/util/data/txcreatesign.json new file mode 100644 index 000000000000..64e5137f4b53 --- /dev/null +++ b/test/util/data/txcreatesign.json @@ -0,0 +1,36 @@ +{ + "txid": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af", + "hash": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af", + "version": 1, + "size": 224, + "vsize": 224, + "weight": 896, + "locktime": 0, + "vin": [ + { + "txid": "4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485", + "vout": 0, + "scriptSig": { + "asm": "304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e2[ALL] 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "hex": "48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.00100000, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 5834479edbbe0539b31ffd3a8f8ebadc2165ed01 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7" + ] + } + } + ], + "hex": "01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000" +} diff --git a/test/util/rpcauth-test.py b/test/util/rpcauth-test.py new file mode 100755 index 000000000000..46e9fbc7398f --- /dev/null +++ b/test/util/rpcauth-test.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test share/rpcauth/rpcauth.py +""" +import base64 +import configparser +import hmac +import importlib +import os +import sys +import unittest + +class TestRPCAuth(unittest.TestCase): + def setUp(self): + config = configparser.ConfigParser() + config_path = os.path.abspath( + os.path.join(os.sep, os.path.abspath(os.path.dirname(__file__)), + "../config.ini")) + with open(config_path, encoding="utf8") as config_file: + config.read_file(config_file) + sys.path.insert(0, os.path.dirname(config['environment']['RPCAUTH'])) + self.rpcauth = importlib.import_module('rpcauth') + + def test_generate_salt(self): + self.assertLessEqual(len(self.rpcauth.generate_salt()), 32) + self.assertGreaterEqual(len(self.rpcauth.generate_salt()), 16) + + def test_generate_password(self): + password = self.rpcauth.generate_password() + expected_password = base64.urlsafe_b64encode( + base64.urlsafe_b64decode(password)).decode('utf-8') + self.assertEqual(expected_password, password) + + def test_check_password_hmac(self): + salt = self.rpcauth.generate_salt() + password = self.rpcauth.generate_password() + password_hmac = self.rpcauth.password_to_hmac(salt, password) + + m = hmac.new(bytearray(salt, 'utf-8'), + bytearray(password, 'utf-8'), 'SHA256') + expected_password_hmac = m.hexdigest() + + self.assertEqual(expected_password_hmac, password_hmac) + +if __name__ == '__main__': + unittest.main()