diff options
241 files changed, 11441 insertions, 4537 deletions
diff --git a/.travis.yml b/.travis.yml index 8e9684826f..d2fbfee6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,6 +69,6 @@ script: - 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 make check; fi - - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py; fi + - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi after_script: - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then (echo "Upload goes here. Something like: scp -r $BASE_OUTDIR server" || echo "upload failed"); fi diff --git a/Makefile.am b/Makefile.am index 303ad3b06f..b2b7811729 100644 --- a/Makefile.am +++ b/Makefile.am @@ -111,7 +111,7 @@ $(APP_DIST_DIR)/Applications: $(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_DMG): $(APP_DIST_EXTRAS) - $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -apple -o $@ dist + $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -dir-mode 0755 -apple -o $@ dist $(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) $(MKDIR_P) $(@D) @@ -49,23 +49,22 @@ lots of money. ### Automated Testing Developers are strongly encouraged to write unit tests for new code, and to -submit new unit tests for old code. Unit tests can be compiled and run (assuming they weren't disabled in configure) with: `make check` +submit new unit tests for old code. Unit tests can be compiled and run +(assuming they weren't disabled in configure) with: `make check` -There are also regression and integration tests of the RPC interface, written +There are also [regression and integration tests](/qa) of the RPC interface, written in Python, that are run automatically on the build server. These tests can be run with: `qa/pull-tester/rpc-tests.py` -Every pull request is built for both Windows and Linux on a dedicated server, -and unit and sanity tests are automatically run. The binaries produced may be -used for manual QA testing — a link to them will appear in a comment on the -pull request posted by [BitcoinPullTester](https://github.com/BitcoinPullTester). See https://github.com/TheBlueMatt/test-scripts -for the build/test scripts. +The Travis CI system makes sure that every pull request is built for Windows +and Linux, OSX, and that unit and sanity tests are automatically run. ### Manual Quality Assurance (QA) Testing -Large changes should have a test plan, and should be tested by somebody other -than the developer who wrote the code. -See https://github.com/bitcoin/QA/ for how to create a test plan. +Changes should be tested by somebody other than the developer who wrote the +code. This is especially important for large or high-risk changes. It is useful +to add a test plan to the pull request description if testing the changes is +not straightforward. Translations ------------ diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 4ea2e734e8..2480267dc1 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -106,7 +106,9 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ dnl results to QT_LIBS. BITCOIN_QT_CHECK([ TEMP_CPPFLAGS=$CPPFLAGS + TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + CXXFLAGS="$PIC_FLAGS $CXXFLAGS" if test x$bitcoin_qt_got_major_vers = x5; then _BITCOIN_QT_IS_STATIC if test x$bitcoin_cv_static_qt = xyes; then @@ -149,6 +151,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi fi CPPFLAGS=$TEMP_CPPFLAGS + CXXFLAGS=$TEMP_CXXFLAGS ]) if test x$use_pkgconfig$qt_bin_path = xyes; then @@ -157,6 +160,43 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi fi + if test x$use_hardening != xno; then + BITCOIN_QT_CHECK([ + AC_MSG_CHECKING(whether -fPIE can be used with this Qt config) + TEMP_CPPFLAGS=$CPPFLAGS + TEMP_CXXFLAGS=$CXXFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + CXXFLAGS="$PIE_FLAGS $CXXFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <QtCore/qconfig.h>]], + [[ + #if defined(QT_REDUCE_RELOCATIONS) + choke; + #endif + ]])], + [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIE_FLAGS ], + [ AC_MSG_RESULT(no); QT_PIE_FLAGS=$PIC_FLAGS] + ) + CPPFLAGS=$TEMP_CPPFLAGS + CXXFLAGS=$TEMP_CXXFLAGS + ]) + else + BITCOIN_QT_CHECK([ + AC_MSG_CHECKING(whether -fPIC is needed with this Qt config) + TEMP_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <QtCore/qconfig.h>]], + [[ + #if defined(QT_REDUCE_RELOCATIONS) + choke; + #endif + ]])], + [ AC_MSG_RESULT(no)], + [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIC_FLAGS] + ) + CPPFLAGS=$TEMP_CPPFLAGS + ]) + 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) @@ -202,6 +242,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ ]) AC_MSG_RESULT([$bitcoin_enable_qt (Qt${bitcoin_qt_got_major_vers})]) + AC_SUBST(QT_PIE_FLAGS) AC_SUBST(QT_INCLUDES) AC_SUBST(QT_LIBS) AC_SUBST(QT_LDFLAGS) @@ -373,6 +414,8 @@ 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" + TEMP_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$PIC_FLAGS $CXXFLAGS" TEMP_LIBS="$LIBS" BITCOIN_QT_CHECK([ if test x$qt_include_path != x; then @@ -442,6 +485,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ fi ]) CPPFLAGS="$TEMP_CPPFLAGS" + CXXFLAGS="$TEMP_CXXFLAGS" LIBS="$TEMP_LIBS" ]) diff --git a/configure.ac b/configure.ac index d94dd0c3dc..63a745393e 100644 --- a/configure.ac +++ b/configure.ac @@ -326,6 +326,7 @@ case $host in AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) CPPFLAGS="$CPPFLAGS -DMAC_OSX" + OBJCXXFLAGS="$CXXFLAGS" ;; *linux*) TARGET_OS=linux @@ -424,6 +425,11 @@ if test x$use_glibc_compat != xno; then 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 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"]) @@ -441,8 +447,7 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) if test x$TARGET_OS != xwindows; then - # All windows code is PIC, forcing it on just adds useless compile warnings - AX_CHECK_COMPILE_FLAG([-fPIE],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fPIE"]) + AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS="-fPIE"]) AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"]) fi @@ -451,11 +456,6 @@ if test x$use_hardening != xno; then AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) ;; esac - - CXXFLAGS="$CXXFLAGS $HARDENED_CXXFLAGS" - CPPFLAGS="$CPPFLAGS $HARDENED_CPPFLAGS" - LDFLAGS="$LDFLAGS $HARDENED_LDFLAGS" - OBJCXXFLAGS="$CXXFLAGS" fi dnl this flag screws up non-darwin gcc even when the check fails. special-case it. @@ -915,6 +915,11 @@ AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) AC_SUBST(RELDFLAGS) +AC_SUBST(HARDENED_CXXFLAGS) +AC_SUBST(HARDENED_CPPFLAGS) +AC_SUBST(HARDENED_LDFLAGS) +AC_SUBST(PIC_FLAGS) +AC_SUBST(PIE_FLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) @@ -953,7 +958,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) AC_OUTPUT diff --git a/contrib/debian/control b/contrib/debian/control index 2fd68583ce..490b2571c3 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -31,14 +31,11 @@ Package: bitcoind Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - daemon - Bitcoin is a free open source peer-to-peer electronic cash system that - is completely decentralized, without the need for a central server or - trusted parties. Users hold the crypto keys to their own money and - transact directly with each other, with the help of a P2P network to - check for double-spending. - . - Full transaction history is stored locally at each client. This - requires 20+ GB of space, slowly growing. + Bitcoin is an experimental new digital currency that enables instant + payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer + technology to operate with no central authority: managing transactions + and issuing money are carried out collectively by the network. Bitcoin Core + is the name of the open source software which enables the use of this currency. . This package provides the daemon, bitcoind, and the CLI tool bitcoin-cli to interact with the daemon. @@ -47,14 +44,11 @@ Package: bitcoin-qt Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - Qt GUI - Bitcoin is a free open source peer-to-peer electronic cash system that - is completely decentralized, without the need for a central server or - trusted parties. Users hold the crypto keys to their own money and - transact directly with each other, with the help of a P2P network to - check for double-spending. - . - Full transaction history is stored locally at each client. This - requires 20+ GB of space, slowly growing. + Bitcoin is an experimental new digital currency that enables instant + payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer + technology to operate with no central authority: managing transactions + and issuing money are carried out collectively by the network. Bitcoin Core + is the name of the open source software which enables the use of this currency. . This package provides Bitcoin-Qt, a GUI for Bitcoin based on Qt. @@ -62,11 +56,11 @@ Package: bitcoin-tx Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer digital currency - standalone transaction tool - Bitcoin is a free open source peer-to-peer electronic cash system that - is completely decentralized, without the need for a central server or - trusted parties. Users hold the crypto keys to their own money and - transact directly with each other, with the help of a P2P network to - check for double-spending. + Bitcoin is an experimental new digital currency that enables instant + payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer + technology to operate with no central authority: managing transactions + and issuing money are carried out collectively by the network. Bitcoin Core + is the name of the open source software which enables the use of this currency. . This package provides bitcoin-tx, a command-line transaction creation tool which can be used without a bitcoin daemon. Some means of diff --git a/contrib/debian/watch b/contrib/debian/watch index c96d2f8e75..4d9e0cfa57 100644 --- a/contrib/debian/watch +++ b/contrib/debian/watch @@ -1,7 +1,5 @@ # Run the "uscan" command to check for upstream updates and more. version=3 # use qa.debian.org redirector; see man uscan -opts=uversionmangle=s/(\d)(alpha|beta|rc)/$1~$2/;s/\-src//,dversionmangle=s/~dfsg\d*// \ - http://sf.net/bitcoin/bitcoin-(\d.*)-linux\.tar\.gz debian opts=uversionmangle=s/(\d)(alpha|beta|rc)/$1~$2/,dversionmangle=s/~dfsg\d*// \ http://githubredir.debian.net/github/bitcoin/bitcoin v(.*).tar.gz diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 34f1ed2d17..93acfcdda4 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -49,7 +49,24 @@ IGNORE_EXPORTS = { READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') # Allowed NEEDED libraries -ALLOWED_LIBRARIES = {'librt.so.1','libpthread.so.0','libanl.so.1','libm.so.6','libgcc_s.so.1','libc.so.6','ld-linux-x86-64.so.2'} +ALLOWED_LIBRARIES = { +# bitcoind and bitcoin-qt +'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) +'ld-linux-x86-64.so.2', # 64-bit dynamic linker +'ld-linux.so.2', # 32-bit dynamic linker +# bitcoin-qt only +'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 +} class CPPFilt(object): ''' diff --git a/contrib/gitian-descriptors/README.md b/contrib/gitian-descriptors/README.md index 061b897d2a..07c2ba98b1 100644 --- a/contrib/gitian-descriptors/README.md +++ b/contrib/gitian-descriptors/README.md @@ -27,7 +27,7 @@ Once you've got the right hardware and software: # Create base images cd gitian-builder - bin/make-base-vm --suite precise --arch amd64 + bin/make-base-vm --suite trusty --arch amd64 cd .. # Get inputs (see doc/release-process.md for exact inputs needed and where to get them) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index a98a71e2f9..0c3c439dd9 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -2,20 +2,19 @@ name: "bitcoin-linux-0.12" enable_cache: true suites: -- "precise" +- "trusty" architectures: - "amd64" packages: - "g++-multilib" - "git-core" - "pkg-config" -- "autoconf2.13" +- "autoconf" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "binutils-gold" -- "libstdc++6-4.6-pic" reference_datetime: "2015-06-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" @@ -44,7 +43,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/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/faketime/libfaketime.so.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} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -55,7 +54,7 @@ script: | 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/faketime/libfaketime.so.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=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} @@ -70,14 +69,6 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done - # Ubuntu precise hack: Not an issue in later versions. - # Precise's libstdc++.a is non-pic. There's an optional libstdc++6-4.6-pic - # package which provides libstdc++_pic.a, but the linker can't find it. - # Symlink it to a path that will be included in our link-line so that the - # linker picks it up before the default libstdc++.a. - # This is only necessary for 64bit. - ln -s /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++_pic.a ${BASEPREFIX}/x86_64-unknown-linux-gnu/lib/libstdc++.a - # Create the release tarball using (arbitrarily) the first host ./autogen.sh ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index 36d7b01264..aa9494b7ed 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -1,7 +1,7 @@ --- name: "bitcoin-dmg-signer" suites: -- "precise" +- "trusty" architectures: - "amd64" packages: @@ -23,7 +23,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/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/faketime/libfaketime.so.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} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index eeeb408ded..9ac774c8a0 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -2,14 +2,14 @@ name: "bitcoin-osx-0.12" enable_cache: true suites: -- "precise" +- "trusty" architectures: - "amd64" packages: - "g++" - "git-core" - "pkg-config" -- "autoconf2.13" +- "autoconf" - "libtool" - "automake" - "faketime" @@ -49,7 +49,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/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/faketime/libfaketime.so.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} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -60,7 +60,7 @@ script: | 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/faketime/libfaketime.so.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=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 2a73050e0e..a29d7ab472 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -1,7 +1,7 @@ --- name: "bitcoin-win-signer" suites: -- "precise" +- "trusty" architectures: - "amd64" packages: diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 5fa0db6784..6bb482d45f 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -2,14 +2,14 @@ name: "bitcoin-win-0.12" enable_cache: true suites: -- "precise" +- "trusty" architectures: - "amd64" packages: - "g++" - "git-core" - "pkg-config" -- "autoconf2.13" +- "autoconf" - "libtool" - "automake" - "faketime" @@ -46,7 +46,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/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/faketime/libfaketime.so.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} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -57,12 +57,36 @@ script: | 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/faketime/libfaketime.so.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=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + + # Create per-host linker wrapper + # This is only needed for trusty, as the mingw linker leaks a few bytes of + # heap, causing non-determinism. See discussion in https://github.com/bitcoin/bitcoin/pull/6900 + for i in $HOSTS; do + mkdir -p ${WRAP_DIR}/${i} + for prog in collect2; do + echo '#!/bin/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 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} + chmod +x ${WRAP_DIR}/${i}-${prog} + done + done + export PATH=${WRAP_DIR}:${PATH} cd bitcoin diff --git a/contrib/gitian-downloader/jonasschnelli-key.pgp b/contrib/gitian-downloader/jonasschnelli-key.pgp Binary files differindex fe44c0fbd4..3831eaea11 100644 --- a/contrib/gitian-downloader/jonasschnelli-key.pgp +++ b/contrib/gitian-downloader/jonasschnelli-key.pgp diff --git a/contrib/test-patches/README.md b/contrib/test-patches/README.md deleted file mode 100644 index def40b0d6c..0000000000 --- a/contrib/test-patches/README.md +++ /dev/null @@ -1,7 +0,0 @@ -### Test Patches ### - -These patches are applied when the automated pull-tester -tests each pull and when master is tested using jenkins. -You can find more information about the tests run at -[http://jenkins.bluematt.me/pull-tester/files/ -](http://jenkins.bluematt.me/pull-tester/files/)
\ No newline at end of file diff --git a/contrib/test-patches/temp-revert-2.patch b/contrib/test-patches/temp-revert-2.patch deleted file mode 100644 index 1cd043d0d7..0000000000 --- a/contrib/test-patches/temp-revert-2.patch +++ /dev/null @@ -1,20 +0,0 @@ -commit cfae26916dba311f6f75d444301c1f9362267c3e -Author: Matt Corallo <git@bluematt.me> -Date: Sun Mar 24 20:45:50 2013 -0400 - - Revert "Checkpoint at first block in 11 March chain fork" - - This reverts commit f817c496a1482d05b22c8e539de67f07db1c09d9. - -diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp -index 62234b9..9b11f0b 100644 ---- a/src/checkpoints.cpp -+++ b/src/checkpoints.cpp -@@ -44,7 +44,6 @@ namespace Checkpoints - (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")) - (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")) - (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")) -- (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")) - ; - static const CCheckpointData data = { - &mapCheckpoints, diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys index fcf2b98e77..a0d0f82db3 100644 --- a/contrib/verify-commits/trusted-keys +++ b/contrib/verify-commits/trusted-keys @@ -4,3 +4,4 @@ AF8BE07C7049F3A26B239D5325B3083201782B2F 81291FA67D2C379A006A053FEAB5AF94D9E9ABE7 3F1888C6DCA92A6499C4911FDBA1A67379A1A931 +32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh index 3eb4693883..847c507553 100755 --- a/contrib/verifysfbinaries/verify.sh +++ b/contrib/verifysfbinaries/verify.sh @@ -17,15 +17,15 @@ function clean_up { WORKINGDIR="/tmp/bitcoin" TMPFILE="hashes.tmp" -#this URL is used if a version number is not specified as an argument to the script -SIGNATUREFILE="https://bitcoin.org/bin/0.9.2.1/SHA256SUMS.asc" - SIGNATUREFILENAME="SHA256SUMS.asc" RCSUBDIR="test/" BASEDIR="https://bitcoin.org/bin/" -VERSIONPREFIX="bitcoin-" +VERSIONPREFIX="bitcoin-core-" RCVERSIONSTRING="rc" +#this URL is used if a version number is not specified as an argument to the script +SIGNATUREFILE="$BASEDIR""$VERSIONPREFIX""0.10.4/""$RCSUBDIR""$SIGNATUREFILENAME" + if [ ! -d "$WORKINGDIR" ]; then mkdir "$WORKINGDIR" fi @@ -62,7 +62,7 @@ WGETOUT=$(wget -N "$BASEDIR$SIGNATUREFILENAME" 2>&1) #and then see if wget completed successfully if [ $? -ne 0 ]; then echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?" - echo "[bitcoin-]<version>-[rc[0-9]] (example: bitcoin-0.9.2-rc1)" + echo "[$VERSIONPREFIX]<version>-[$RCVERSIONSTRING[0-9]] (example: "$VERSIONPREFIX"0.10.4-"$RCVERSIONSTRING"1)" echo "wget output:" echo "$WGETOUT"|sed 's/^/\t/g' exit 2 @@ -82,7 +82,7 @@ if [ $RET -ne 0 ]; then echo "Bad signature." elif [ $RET -eq 2 ]; then #or if a gpg error has occurred - echo "gpg error. Do you have Gavin's code signing key installed?" + echo "gpg error. Do you have the Bitcoin Core binary release signing key installed?" fi echo "gpg output:" @@ -116,4 +116,6 @@ fi #everything matches! clean up the mess clean_up $FILES $SIGNATUREFILENAME $TMPFILE +echo -e "Verified hashes of \n$FILES" + exit 0 diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 687aae6682..c6452820a2 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -17,6 +17,7 @@ $(package)_config_opts_arm_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_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/qt.mk b/depends/packages/qt.mk index cba2fbd151..901b761fde 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -8,7 +8,7 @@ $(package)_dependencies=openssl $(package)_linux_dependencies=freetype fontconfig dbus libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib -$(package)_patches=mac-qmake.conf fix-xcb-include-order.patch mingw-uuidof.patch +$(package)_patches=mac-qmake.conf fix-xcb-include-order.patch mingw-uuidof.patch pidlist_absolute.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=c4bd6db6e426965c6f8824c54e81f68bbd61e2bae1bcadc328c6e81c45902a0d @@ -122,9 +122,6 @@ endef define $(package)_preprocess_cmds sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" 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/PIDLIST_ABSOLUTE/ITEMIDLIST */" qtbase/src/plugins/platforms/windows/qwindowscontext.h &&\ - sed -i.old "s/PIDLIST_ABSOLUTE/ITEMIDLIST */" qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp &&\ - sed -i.old "s/PCIDLIST_ABSOLUTE/const ITEMIDLIST */" qtbase/src/plugins/platforms/windows/qwindowscontext.h &&\ 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 && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ @@ -134,6 +131,7 @@ define $(package)_preprocess_cmds cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ patch -p1 < $($(package)_patch_dir)/fix-xcb-include-order.patch && \ patch -p1 < $($(package)_patch_dir)/mingw-uuidof.patch && \ + patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ echo "QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ diff --git a/depends/patches/qt/pidlist_absolute.patch b/depends/patches/qt/pidlist_absolute.patch new file mode 100644 index 0000000000..0b49c050dc --- /dev/null +++ b/depends/patches/qt/pidlist_absolute.patch @@ -0,0 +1,37 @@ +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 2015-06-29 22:04:40.000000000 +0200 ++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-11-01 12:55:59.751234846 +0100 +@@ -124,10 +124,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 2015-06-29 22:04:40.000000000 +0200 ++++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-11-01 13:41:09.503149772 +0100 +@@ -1008,7 +1008,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/doc/README.md b/doc/README.md index 0594d20dd4..f6df28a89b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -28,7 +28,7 @@ Unpack the files into a directory, and then run bitcoin-qt.exe. ### OS X -Drag Bitcoin-Qt to your applications folder, and then run Bitcoin-Qt. +Drag Bitcoin-Core to your applications folder, and then run Bitcoin-Core. ### Need Help? diff --git a/doc/build-unix.md b/doc/build-unix.md index 57853a9c9d..159a140608 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -61,15 +61,15 @@ 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 bsdmainutils -On Ubuntu 15.10+ there are generic names for the individual boost development -packages, so the following can be used to only install necessary parts of -boost: +On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the +individual boost development packages, so the following can be used to only +install necessary parts of boost: - apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libboost-base-dev + sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev -For Ubuntu before 15.10, or Debian 7 and later libboost-all-dev has to be installed: +If that doesn't work, you can install all boost development packages with: sudo apt-get install libboost-all-dev @@ -135,14 +135,6 @@ turned off by default. See the configure options for upnp behavior desired: --disable-upnp-default (the default) UPnP support turned off by default at runtime --enable-upnp-default UPnP support turned on by default at runtime -To build: - - tar -xzvf miniupnpc-1.6.tar.gz - cd miniupnpc-1.6 - make - sudo su - make install - Berkeley DB ----------- diff --git a/doc/files.md b/doc/files.md index c083bcb038..f7eca57dcb 100644 --- a/doc/files.md +++ b/doc/files.md @@ -12,6 +12,8 @@ * fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0 * peers.dat: peer IP address database (custom format); since 0.7.0 * wallet.dat: personal wallet (BDB) with keys and transactions +* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0 +* onion_private_key: cached Tor hidden service private key for `-listenonion`: since 0.12.0 Only used in pre-0.8.0 --------------------- diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 00fdce82e8..019e851696 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -289,11 +289,11 @@ The rest of the steps in this guide will be performed as that user. There is no `python-vm-builder` package in Debian, so we need to install it from source ourselves, ```bash -wget http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr489.orig.tar.gz -echo "ec12e0070a007989561bfee5862c89a32c301992dd2771c4d5078ef1b3014f03 vm-builder_0.12.4+bzr489.orig.tar.gz" | sha256sum -c +wget http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr494.orig.tar.gz +echo "76cbf8c52c391160b2641e7120dbade5afded713afaa6032f733a261f13e6a8e vm-builder_0.12.4+bzr494.orig.tar.gz" | sha256sum -c # (verification -- must return OK) -tar -zxvf vm-builder_0.12.4+bzr489.orig.tar.gz -cd vm-builder-0.12.4+bzr489 +tar -zxvf vm-builder_0.12.4+bzr494.orig.tar.gz +cd vm-builder-0.12.4+bzr494 sudo python setup.py install cd .. ``` @@ -320,7 +320,7 @@ Execute the following as user `debian`: ```bash cd gitian-builder -bin/make-base-vm --lxc --arch amd64 --suite precise +bin/make-base-vm --lxc --arch amd64 --suite trusty ``` There will be a lot of warnings printed during the build of the image. These can be ignored. diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md new file mode 100644 index 0000000000..2d86588eb2 --- /dev/null +++ b/doc/reduce-traffic.md @@ -0,0 +1,38 @@ +Reduce Traffic +============== + +Some node operators need to deal with bandwidth caps imposed by their ISPs. + +By default, bitcoin-core allows up to 125 connections to different peers, 8 of +which are outbound. You can therefore, have at most 117 inbound connections. + +The default settings can result in relatively significant traffic consumption. + +Ways to reduce traffic: + +## 1. Use `-maxuploadtarget=<MiB per day>` + +A major component of the traffic is caused by serving historic blocks to other nodes +during the initial blocks download phase (syncing up a new node). +This option can be specified in MiB per day and is turned off by default. +This is *not* a hard limit; only a threshold to minimize the outbound +traffic. When the limit is about to be reached, the uploaded data is cut by no +longer serving historic blocks (blocks older than one week). +Keep in mind that new nodes require other nodes that are willing to serve +historic blocks. **The recommended minimum is 144 blocks per day (max. 144MB +per day)** + +Whitelisted peers will never be disconnected, although their traffic counts for +calculating the target. + +## 2. Disable "listening" (`-listen=0`) + +Disabling listening will result in fewer nodes connected (remember the maximum of 8 +outbound peers). Fewer nodes will result in less traffic usage as you are relaying +blocks and transactions to fewer nodes. + +## 3. Reduce maximum connections (`-maxconnections=<num>`) + +Reducing the maximum connected nodes to a minimum could be desirable if traffic +limits are tiny. Keep in mind that bitcoin's trustless model works best if you are +connected to a handful of nodes. diff --git a/doc/release-notes.md b/doc/release-notes.md index fd034743e6..7db27f9fac 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -143,7 +143,7 @@ higher, it becomes mandatory for all blocks and blocks with versions less than Bitcoin Core's block templates are now for version 4 blocks only, and any mining software relying on its `getblocktemplate` must be updated in parallel -to use either libblkmaker version FIXME or any version from 0.5.1 onward. If +to use either libblkmaker version 0.4.3 or any version from 0.5.2 onward. If you are solo mining, this will affect you the moment you upgrade Bitcoin Core, which must be done prior to BIP65 achieving its 951/1001 status. If you are mining with the stratum mining protocol: this does not affect you. If you are @@ -151,6 +151,60 @@ mining with the getblocktemplate protocol to a pool: this will affect you at the pool operator's discretion, which must be no later than BIP65 achieving its 951/1001 status. +Automatically listen on Tor +---------------------------- + +Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket +API, to create and destroy 'ephemeral' hidden services programmatically. +Bitcoin Core has been updated to make use of this. + +This means that if Tor is running (and proper authorization is available), +Bitcoin Core automatically creates a hidden service to listen on, without +manual configuration. This will positively affect the number of available +.onion nodes. + +This new feature is enabled by default if Bitcoin Core is listening, and +a connection to Tor can be made. It can be configured with the `-listenonion`, +`-torcontrol` and `-torpassword` settings. To show verbose debugging +information, pass `-debug=tor`. + +Reduce upload traffic +--------------------- + +A major part of the outbound traffic is caused by serving historic blocks to +other nodes in initial block download state. + +It is now possible to reduce the total upload traffic via the `-maxuploadtarget` +parameter. This is *not* a hard limit but a threshold to minimize the outbound +traffic. When the limit is about to be reached, the uploaded data is cut by not +serving historic blocks (blocks older than one week). +Moreover, any SPV peer is disconnected when they request a filtered block. + +This option can be specified in MiB per day and is turned off by default +(`-maxuploadtarget=0`). +The recommended minimum is 144 * MAX_BLOCK_SIZE (currently 144MB) per day. + +Whitelisted peers will never be disconnected, although their traffic counts for +calculating the target. + +A more detailed documentation about keeping traffic low can be found in +[/doc/reducetraffic.md](/doc/reducetraffic.md). + +Signature validation using libsecp256k1 +--------------------------------------- + +ECDSA signatures inside Bitcoin transactions now use validation using +[https://github.com/bitcoin/secp256k1](libsecp256k1) instead of OpenSSL. + +Depending on the platform, this means a significant speedup for raw signature +validation speed. The advantage is largest on x86_64, where validation is over +five times faster. In practice, this translates to a raw reindexing and new +block validation times that are less than half of what it was before. + +Libsecp256k1 has undergone very extensive testing and validation. + +A side effect of this change is that libconsensus no longer depends on OpenSSL. + 0.12.0 Change log ================= diff --git a/doc/tor.md b/doc/tor.md index 594897f896..1d35a658bc 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -87,3 +87,20 @@ If you only want to use Tor to reach onion addresses, but not use it as a proxy for normal IPv4/IPv6 communication, use: ./bitcoin -onion=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover + +3. Automatically listen on Tor +-------------------------------- + +Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket +API, to create and destroy 'ephemeral' hidden services programmatically. +Bitcoin Core has been updated to make use of this. + +This means that if Tor is running (and proper authorization is available), +Bitcoin Core automatically creates a hidden service to listen on, without +manual configuration. This will positively affect the number of available +.onion nodes. + +This new feature is enabled by default if Bitcoin Core is listening, and +a connection to Tor can be made. It can be configured with the `-listenonion`, +`-torcontrol` and `-torpassword` settings. To show verbose debugging +information, pass `-debug=tor`. diff --git a/qa/README.md b/qa/README.md new file mode 100644 index 0000000000..758d1f47e5 --- /dev/null +++ b/qa/README.md @@ -0,0 +1,57 @@ +The [pull-tester](/qa/pull-tester/) folder contains a script to call +multiple tests from the [rpc-tests](/qa/rpc-tests/) folder. + +Every pull request to the bitcoin repository is built and run through +the regression test suite. You can also run all or only individual +tests locally. + +Running tests +============= + +You can run any single test by calling `qa/pull-tester/rpc-tests.py <testname>`. + +Or you can run any combination of tests by calling `qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ...` + +Run the regression test suite with `qa/pull-tester/rpc-tests.py` + +Run all possible tests with `qa/pull-tester/rpc-tests.py -extended` + +Possible options: + +``` + -h, --help show this help message and exit + --nocleanup Leave bitcoinds and test.* datadir on exit or error + --noshutdown Don't stop bitcoinds after the test execution + --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli + (default: ../../src) + --tmpdir=TMPDIR Root directory for datadirs + --tracerpc Print out all RPC calls as they are made + --coveragedir=COVERAGEDIR + Write tested RPC commands into this directory +``` + +If you set the environment variable `PYTHON_DEBUG=1` you will get some debug +output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`). + +A 200-block -regtest blockchain and wallets for four nodes +is created the first time a regression test is run and +is stored in the cache/ directory. Each node has 25 mature +blocks (25*50=1250 BTC) in its wallet. + +After the first run, the cache/ blockchain and wallets are +copied into a temporary directory and used as the initial +test state. + +If you get into a bad state, you should be able +to recover with: + +```bash +rm -rf cache +killall bitcoind +``` + +Writing tests +============= +You are encouraged to write tests for new or existing features. +Further information about the test framework and individual rpc +tests is found in [qa/rpc-tests](/qa/rpc-tests). diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 86a416edc4..3d156a2e7b 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -3,16 +3,32 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -# -# Run Regression Test Suite -# +""" +Run Regression Test Suite + +This module calls down into individual test cases via subprocess. It will +forward all unrecognized arguments onto the individual test scripts, other +than: + + - `-extended`: run the "extended" test suite in addition to the basic one. + - `-win`: signal that this is running in a Windows environment, and we + should run the tests. + - `--coverage`: this generates a basic coverage report for the RPC + interface. + +For a description of arguments recognized by test scripts, see +`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`. + +""" import os +import shutil import sys import subprocess +import tempfile import re + from tests_config import * -from sets import Set #If imported values are not defined then set to zero (or disabled) if not vars().has_key('ENABLE_WALLET'): @@ -24,15 +40,20 @@ if not vars().has_key('ENABLE_UTILS'): if not vars().has_key('ENABLE_ZMQ'): ENABLE_ZMQ=0 +ENABLE_COVERAGE=0 + #Create a set to store arguments and create the passOn string -opts = Set() +opts = set() passOn = "" p = re.compile("^--") -for i in range(1,len(sys.argv)): - if (p.match(sys.argv[i]) or sys.argv[i] == "-h"): - passOn += " " + sys.argv[i] + +for arg in sys.argv[1:]: + if arg == '--coverage': + ENABLE_COVERAGE = 1 + elif (p.match(arg) or arg == "-h"): + passOn += " " + arg else: - opts.add(sys.argv[i]) + opts.add(arg) #Set env vars buildDir = BUILDDIR @@ -48,6 +69,7 @@ if EXEEXT == ".exe" and "-win" not in opts: testScripts = [ 'wallet.py', 'listtransactions.py', + 'receivedby.py', 'mempool_resurrect_test.py', 'txn_doublespend.py --mineblock', 'txn_clone.py', @@ -83,9 +105,7 @@ testScriptsExt = [ 'forknotify.py', 'invalidateblock.py', 'keypool.py', - 'receivedby.py', # 'rpcbind_test.py', #temporary, bug in libevent, see #6655 -# 'script_test.py', #used for manual comparison of 2 binaries 'smartfees.py', 'maxblocksinflight.py', 'invalidblockrequest.py', @@ -99,24 +119,125 @@ testScriptsExt = [ if ENABLE_ZMQ == 1: testScripts.append('zmq_test.py') -if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): - rpcTestDir = buildDir + '/qa/rpc-tests/' - #Run Tests - for i in range(len(testScripts)): - if (len(opts) == 0 or (len(opts) == 1 and "-win" in opts ) or '-extended' in opts - or testScripts[i] in opts or re.sub(".py$", "", testScripts[i]) in opts ): - print "Running testscript " + testScripts[i] + "..." - subprocess.check_call(rpcTestDir + testScripts[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True) - #exit if help is called so we print just one set of instructions - p = re.compile(" -h| --help") - if p.match(passOn): - sys.exit(0) - - #Run Extended Tests - for i in range(len(testScriptsExt)): - if ('-extended' in opts or testScriptsExt[i] in opts - or re.sub(".py$", "", testScriptsExt[i]) in opts): - print "Running 2nd level testscript " + testScriptsExt[i] + "..." - subprocess.check_call(rpcTestDir + testScriptsExt[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True) -else: - print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" + +def runtests(): + coverage = None + + if ENABLE_COVERAGE: + coverage = RPCCoverage() + print("Initializing coverage directory at %s" % coverage.dir) + + if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): + rpcTestDir = buildDir + '/qa/rpc-tests/' + run_extended = '-extended' in opts + cov_flag = coverage.flag if coverage else '' + flags = " --srcdir %s/src %s %s" % (buildDir, cov_flag, passOn) + + #Run Tests + for i in range(len(testScripts)): + if (len(opts) == 0 + or (len(opts) == 1 and "-win" in opts ) + or run_extended + or testScripts[i] in opts + or re.sub(".py$", "", testScripts[i]) in opts ): + print("Running testscript " + testScripts[i] + "...") + + subprocess.check_call( + rpcTestDir + testScripts[i] + flags, shell=True) + + # exit if help is called so we print just one set of + # instructions + p = re.compile(" -h| --help") + if p.match(passOn): + sys.exit(0) + + # Run Extended Tests + for i in range(len(testScriptsExt)): + if (run_extended or testScriptsExt[i] in opts + or re.sub(".py$", "", testScriptsExt[i]) in opts): + print( + "Running 2nd level testscript " + + testScriptsExt[i] + "...") + + subprocess.check_call( + rpcTestDir + testScriptsExt[i] + flags, shell=True) + + if coverage: + coverage.report_rpc_coverage() + + print("Cleaning up coverage data") + coverage.cleanup() + + else: + print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" + + +class RPCCoverage(object): + """ + Coverage reporting utilities for pull-tester. + + Coverage calculation works by having each test script subprocess write + coverage files into a particular directory. These files contain the RPC + commands invoked during testing, as well as a complete listing of RPC + commands per `bitcoin-cli help` (`rpc_interface.txt`). + + After all tests complete, the commands run are combined and diff'd against + the complete list to calculate uncovered RPC commands. + + See also: qa/rpc-tests/test_framework/coverage.py + + """ + def __init__(self): + self.dir = tempfile.mkdtemp(prefix="coverage") + self.flag = '--coveragedir %s' % self.dir + + def report_rpc_coverage(self): + """ + Print out RPC commands that were unexercised by tests. + + """ + uncovered = self._get_uncovered_rpc_commands() + + if uncovered: + print("Uncovered RPC commands:") + print("".join((" - %s\n" % i) for i in sorted(uncovered))) + else: + print("All RPC commands covered.") + + def cleanup(self): + return shutil.rmtree(self.dir) + + def _get_uncovered_rpc_commands(self): + """ + Return a set of currently untested RPC commands. + + """ + # This is shared from `qa/rpc-tests/test-framework/coverage.py` + REFERENCE_FILENAME = 'rpc_interface.txt' + COVERAGE_FILE_PREFIX = 'coverage.' + + coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME) + coverage_filenames = set() + all_cmds = set() + covered_cmds = set() + + if not os.path.isfile(coverage_ref_filename): + raise RuntimeError("No coverage reference found") + + with open(coverage_ref_filename, 'r') as f: + all_cmds.update([i.strip() for i in f.readlines()]) + + for root, dirs, files in os.walk(self.dir): + for filename in files: + if filename.startswith(COVERAGE_FILE_PREFIX): + coverage_filenames.add(os.path.join(root, filename)) + + for filename in coverage_filenames: + with open(filename, 'r') as f: + covered_cmds.update([i.strip() for i in f.readlines()]) + + return all_cmds - covered_cmds + + +if __name__ == '__main__': + runtests() diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md index d2db00362f..898931936b 100644 --- a/qa/rpc-tests/README.md +++ b/qa/rpc-tests/README.md @@ -1,10 +1,8 @@ Regression tests ================ -### [python-bitcoinrpc](https://github.com/jgarzik/python-bitcoinrpc) -Git subtree of [https://github.com/jgarzik/python-bitcoinrpc](https://github.com/jgarzik/python-bitcoinrpc). -Changes to python-bitcoinrpc should be made upstream, and then -pulled here using git subtree. +### [test_framework/authproxy.py](test_framework/authproxy.py) +Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc). ### [test_framework/test_framework.py](test_framework/test_framework.py) Base class for new regression tests. @@ -33,49 +31,6 @@ Helpers for script.py ### [test_framework/blocktools.py](test_framework/blocktools.py) Helper functions for creating blocks and transactions. - -Notes -===== - -You can run any single test by calling `qa/pull-tester/rpc-tests.py <testname>`. - -Or you can run any combination of tests by calling `qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ...` - -Run the regression test suite with `qa/pull-tester/rpc-tests.py` - -Run all possible tests with `qa/pull-tester/rpc-tests.py -extended` - -Possible options: - -``` --h, --help show this help message and exit - --nocleanup Leave bitcoinds and test.* datadir on exit or error - --noshutdown Don't stop bitcoinds after the test execution - --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli (default: - ../../src) - --tmpdir=TMPDIR Root directory for datadirs - --tracerpc Print out all RPC calls as they are made -``` - -If you set the environment variable `PYTHON_DEBUG=1` you will get some debug output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`). - -A 200-block -regtest blockchain and wallets for four nodes -is created the first time a regression test is run and -is stored in the cache/ directory. Each node has 25 mature -blocks (25*50=1250 BTC) in its wallet. - -After the first run, the cache/ blockchain and wallets are -copied into a temporary directory and used as the initial -test state. - -If you get into a bad state, you should be able -to recover with: - -```bash -rm -rf cache -killall bitcoind -``` - P2P test design notes --------------------- diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py index aab4562422..1ddff8a298 100755 --- a/qa/rpc-tests/getblocktemplate_longpoll.py +++ b/qa/rpc-tests/getblocktemplate_longpoll.py @@ -38,7 +38,7 @@ class LongpollThread(threading.Thread): self.longpollid = templat['longpollid'] # create a new connection to the node, we can't use the same # connection from two threads - self.node = AuthServiceProxy(node.url, timeout=600) + self.node = get_rpc_proxy(node.url, 1, timeout=600) def run(self): self.node.getblocktemplate({'longpollid':self.longpollid}) diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py index 67c4a50985..e714465db1 100755 --- a/qa/rpc-tests/maxuploadtarget.py +++ b/qa/rpc-tests/maxuploadtarget.py @@ -192,9 +192,10 @@ class MaxUploadTest(BitcoinTestFramework): getdata_request.inv.append(CInv(2, big_old_block)) max_bytes_per_day = 200*1024*1024 - max_bytes_available = max_bytes_per_day - 144*1000000 + daily_buffer = 144 * 1000000 + max_bytes_available = max_bytes_per_day - daily_buffer success_count = max_bytes_available / old_block_size - + # 144MB will be reserved for relaying new blocks, so expect this to # succeed for ~70 tries. for i in xrange(success_count): @@ -227,7 +228,7 @@ class MaxUploadTest(BitcoinTestFramework): test_nodes[1].send_message(getdata_request) test_nodes[1].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 1) - + print "Peer 1 disconnected after trying to download old block" print "Advancing system time on node to clear counters..." @@ -244,5 +245,38 @@ class MaxUploadTest(BitcoinTestFramework): [c.disconnect_node() for c in connections] + #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1 + print "Restarting nodes with -whitelist=127.0.0.1" + stop_node(self.nodes[0], 0) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) + + #recreate/reconnect 3 test nodes + test_nodes = [] + connections = [] + + for i in xrange(3): + test_nodes.append(TestNode()) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i])) + test_nodes[i].add_connection(connections[i]) + + NetworkThread().start() # Start up network handling in another thread + [x.wait_for_verack() for x in test_nodes] + + #retrieve 20 blocks which should be enough to break the 1MB limit + getdata_request.inv = [CInv(2, big_new_block)] + for i in xrange(20): + test_nodes[1].send_message(getdata_request) + test_nodes[1].sync_with_ping() + assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1) + + getdata_request.inv = [CInv(2, big_old_block)] + test_nodes[1].send_message(getdata_request) + test_nodes[1].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist + + print "Peer 1 still connected after trying to download old block (whitelisted)" + + [c.disconnect_node() for c in connections] + if __name__ == '__main__': MaxUploadTest().main() diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py index 6bc6e43f0b..746c26ff5e 100755 --- a/qa/rpc-tests/mempool_packages.py +++ b/qa/rpc-tests/mempool_packages.py @@ -11,6 +11,9 @@ from test_framework.util import * def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) +MAX_ANCESTORS = 25 +MAX_DESCENDANTS = 25 + class MempoolPackagesTest(BitcoinTestFramework): def setup_network(self): @@ -45,17 +48,17 @@ class MempoolPackagesTest(BitcoinTestFramework): value = utxo[0]['amount'] fee = Decimal("0.0001") - # 100 transactions off a confirmed tx should be fine + # MAX_ANCESTORS transactions off a confirmed tx should be fine chain = [] - for i in xrange(100): + for i in xrange(MAX_ANCESTORS): (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1) value = sent_value chain.append(txid) - # Check mempool has 100 transactions in it, and descendant + # Check mempool has MAX_ANCESTORS transactions in it, and descendant # count and fees should look correct mempool = self.nodes[0].getrawmempool(True) - assert_equal(len(mempool), 100) + assert_equal(len(mempool), MAX_ANCESTORS) descendant_count = 1 descendant_fees = 0 descendant_size = 0 @@ -91,18 +94,18 @@ class MempoolPackagesTest(BitcoinTestFramework): for i in xrange(10): transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value}) - for i in xrange(1000): + for i in xrange(MAX_DESCENDANTS): utxo = transaction_package.pop(0) try: (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) for j in xrange(10): transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) - if i == 998: + if i == MAX_DESCENDANTS - 2: mempool = self.nodes[0].getrawmempool(True) - assert_equal(mempool[parent_transaction]['descendantcount'], 1000) + assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS) except JSONRPCException as e: print e.error['message'] - assert_equal(i, 999) + assert_equal(i, MAX_DESCENDANTS - 1) print "tx that would create too large descendant package successfully rejected" # TODO: check that node1's mempool is as expected diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py index 04110c2831..7a9da66787 100755 --- a/qa/rpc-tests/rpcbind_test.py +++ b/qa/rpc-tests/rpcbind_test.py @@ -47,7 +47,7 @@ def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport): try: # connect to node through non-loopback interface url = "http://rt:rt@%s:%d" % (rpchost, rpcport,) - node = AuthServiceProxy(url) + node = get_rpc_proxy(url, 1) node.getinfo() finally: node = None # make sure connection will be garbage collected and closed diff --git a/qa/rpc-tests/script_test.py b/qa/rpc-tests/script_test.py deleted file mode 100755 index afc44b51b5..0000000000 --- a/qa/rpc-tests/script_test.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python2 -# -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -# - -''' -Test notes: -This test uses the script_valid and script_invalid tests from the unittest -framework to do end-to-end testing where we compare that two nodes agree on -whether blocks containing a given test script are valid. - -We generally ignore the script flags associated with each test (since we lack -the precision to test each script using those flags in this framework), but -for tests with SCRIPT_VERIFY_P2SH, we can use a block time after the BIP16 -switchover date to try to test with that flag enabled (and for tests without -that flag, we use a block time before the switchover date). - -NOTE: This test is very slow and may take more than 40 minutes to run. -''' - -from test_framework.test_framework import ComparisonTestFramework -from test_framework.util import * -from test_framework.comptool import TestInstance, TestManager -from test_framework.mininode import * -from test_framework.blocktools import * -from test_framework.script import * -import logging -import copy -import json - -script_valid_file = "../../src/test/data/script_valid.json" -script_invalid_file = "../../src/test/data/script_invalid.json" - -# Pass in a set of json files to open. -class ScriptTestFile(object): - - def __init__(self, files): - self.files = files - self.index = -1 - self.data = [] - - def load_files(self): - for f in self.files: - self.data.extend(json.loads(open(os.path.dirname(os.path.abspath(__file__))+"/"+f).read())) - - # Skip over records that are not long enough to be tests - def get_records(self): - while (self.index < len(self.data)): - if len(self.data[self.index]) >= 3: - yield self.data[self.index] - self.index += 1 - - -# Helper for parsing the flags specified in the .json files -SCRIPT_VERIFY_NONE = 0 -SCRIPT_VERIFY_P2SH = 1 -SCRIPT_VERIFY_STRICTENC = 1 << 1 -SCRIPT_VERIFY_DERSIG = 1 << 2 -SCRIPT_VERIFY_LOW_S = 1 << 3 -SCRIPT_VERIFY_NULLDUMMY = 1 << 4 -SCRIPT_VERIFY_SIGPUSHONLY = 1 << 5 -SCRIPT_VERIFY_MINIMALDATA = 1 << 6 -SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = 1 << 7 -SCRIPT_VERIFY_CLEANSTACK = 1 << 8 - -flag_map = { - "": SCRIPT_VERIFY_NONE, - "NONE": SCRIPT_VERIFY_NONE, - "P2SH": SCRIPT_VERIFY_P2SH, - "STRICTENC": SCRIPT_VERIFY_STRICTENC, - "DERSIG": SCRIPT_VERIFY_DERSIG, - "LOW_S": SCRIPT_VERIFY_LOW_S, - "NULLDUMMY": SCRIPT_VERIFY_NULLDUMMY, - "SIGPUSHONLY": SCRIPT_VERIFY_SIGPUSHONLY, - "MINIMALDATA": SCRIPT_VERIFY_MINIMALDATA, - "DISCOURAGE_UPGRADABLE_NOPS": SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, - "CLEANSTACK": SCRIPT_VERIFY_CLEANSTACK, -} - -def ParseScriptFlags(flag_string): - flags = 0 - for x in flag_string.split(","): - if x in flag_map: - flags |= flag_map[x] - else: - print "Error: unrecognized script flag: ", x - return flags - -''' -Given a string that is a scriptsig or scriptpubkey from the .json files above, -convert it to a CScript() -''' -# Replicates behavior from core_read.cpp -def ParseScript(json_script): - script = json_script.split(" ") - parsed_script = CScript() - for x in script: - if len(x) == 0: - # Empty string, ignore. - pass - elif x.isdigit() or (len(x) >= 1 and x[0] == "-" and x[1:].isdigit()): - # Number - n = int(x, 0) - if (n == -1) or (n >= 1 and n <= 16): - parsed_script = CScript(bytes(parsed_script) + bytes(CScript([n]))) - else: - parsed_script += CScriptNum(int(x, 0)) - elif x.startswith("0x"): - # Raw hex data, inserted NOT pushed onto stack: - for i in xrange(2, len(x), 2): - parsed_script = CScript(bytes(parsed_script) + bytes(chr(int(x[i:i+2],16)))) - elif x.startswith("'") and x.endswith("'") and len(x) >= 2: - # Single-quoted string, pushed as data. - parsed_script += CScript([x[1:-1]]) - else: - # opcode, e.g. OP_ADD or ADD: - tryopname = "OP_" + x - if tryopname in OPCODES_BY_NAME: - parsed_script += CScriptOp(OPCODES_BY_NAME["OP_" + x]) - else: - print "ParseScript: error parsing '%s'" % x - return "" - return parsed_script - -class TestBuilder(object): - def create_credit_tx(self, scriptPubKey, height): - # self.tx1 is a coinbase transaction, modeled after the one created by script_tests.cpp - # This allows us to reuse signatures created in the unit test framework. - self.tx1 = create_coinbase(height) # this has a bip34 scriptsig, - self.tx1.vin[0].scriptSig = CScript([0, 0]) # but this matches the unit tests - self.tx1.vout[0].nValue = 0 - self.tx1.vout[0].scriptPubKey = scriptPubKey - self.tx1.rehash() - def create_spend_tx(self, scriptSig): - self.tx2 = create_transaction(self.tx1, 0, CScript(), 0) - self.tx2.vin[0].scriptSig = scriptSig - self.tx2.vout[0].scriptPubKey = CScript() - self.tx2.rehash() - def rehash(self): - self.tx1.rehash() - self.tx2.rehash() - -# This test uses the (default) two nodes provided by ComparisonTestFramework, -# specified on the command line with --testbinary and --refbinary. -# See comptool.py -class ScriptTest(ComparisonTestFramework): - - def run_test(self): - # Set up the comparison tool TestManager - test = TestManager(self, self.options.tmpdir) - test.add_all_connections(self.nodes) - - # Load scripts - self.scripts = ScriptTestFile([script_valid_file, script_invalid_file]) - self.scripts.load_files() - - # Some variables we re-use between test instances (to build blocks) - self.tip = None - self.block_time = None - - NetworkThread().start() # Start up network handling in another thread - test.run() - - def generate_test_instance(self, pubkeystring, scriptsigstring): - scriptpubkey = ParseScript(pubkeystring) - scriptsig = ParseScript(scriptsigstring) - - test = TestInstance(sync_every_block=False) - test_build = TestBuilder() - test_build.create_credit_tx(scriptpubkey, self.height) - test_build.create_spend_tx(scriptsig) - test_build.rehash() - - block = create_block(self.tip, test_build.tx1, self.block_time) - self.block_time += 1 - block.solve() - self.tip = block.sha256 - self.height += 1 - test.blocks_and_transactions = [[block, True]] - - for i in xrange(100): - block = create_block(self.tip, create_coinbase(self.height), self.block_time) - self.block_time += 1 - block.solve() - self.tip = block.sha256 - self.height += 1 - test.blocks_and_transactions.append([block, True]) - - block = create_block(self.tip, create_coinbase(self.height), self.block_time) - self.block_time += 1 - block.vtx.append(test_build.tx2) - block.hashMerkleRoot = block.calc_merkle_root() - block.rehash() - block.solve() - test.blocks_and_transactions.append([block, None]) - return test - - # This generates the tests for TestManager. - def get_tests(self): - self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) - self.block_time = 1333230000 # before the BIP16 switchover - self.height = 1 - - ''' - Create a new block with an anyone-can-spend coinbase - ''' - block = create_block(self.tip, create_coinbase(self.height), self.block_time) - self.block_time += 1 - block.solve() - self.tip = block.sha256 - self.height += 1 - yield TestInstance(objects=[[block, True]]) - - ''' - Build out to 100 blocks total, maturing the coinbase. - ''' - test = TestInstance(objects=[], sync_every_block=False, sync_every_tx=False) - for i in xrange(100): - b = create_block(self.tip, create_coinbase(self.height), self.block_time) - b.solve() - test.blocks_and_transactions.append([b, True]) - self.tip = b.sha256 - self.block_time += 1 - self.height += 1 - yield test - - ''' Iterate through script tests. ''' - counter = 0 - for script_test in self.scripts.get_records(): - ''' Reset the blockchain to genesis block + 100 blocks. ''' - if self.nodes[0].getblockcount() > 101: - self.nodes[0].invalidateblock(self.nodes[0].getblockhash(102)) - self.nodes[1].invalidateblock(self.nodes[1].getblockhash(102)) - - self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) - self.height = 102 - - [scriptsig, scriptpubkey, flags] = script_test[0:3] - flags = ParseScriptFlags(flags) - - # We can use block time to determine whether the nodes should be - # enforcing BIP16. - # - # We intentionally let the block time grow by 1 each time. - # This forces the block hashes to differ between tests, so that - # a call to invalidateblock doesn't interfere with a later test. - if (flags & SCRIPT_VERIFY_P2SH): - self.block_time = 1333238400 + counter # Advance to enforcing BIP16 - else: - self.block_time = 1333230000 + counter # Before the BIP16 switchover - - print "Script test: [%s]" % script_test - - yield self.generate_test_instance(scriptpubkey, scriptsig) - counter += 1 - -if __name__ == '__main__': - ScriptTest().main() diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py index c15c5fda09..ecfffc1b45 100755 --- a/qa/rpc-tests/smartfees.py +++ b/qa/rpc-tests/smartfees.py @@ -120,15 +120,26 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): last_e = e valid_estimate = False invalid_estimates = 0 - for e in all_estimates: + for i,e in enumerate(all_estimates): # estimate is for i+1 if e >= 0: valid_estimate = True + # estimatesmartfee should return the same result + assert_equal(node.estimatesmartfee(i+1)["feerate"], e) + else: invalid_estimates += 1 - # Once we're at a high enough confirmation count that we can give an estimate - # We should have estimates for all higher confirmation counts - if valid_estimate and e < 0: - raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate") + + # estimatesmartfee should still be valid + approx_estimate = node.estimatesmartfee(i+1)["feerate"] + answer_found = node.estimatesmartfee(i+1)["blocks"] + assert(approx_estimate > 0) + assert(answer_found > i+1) + + # Once we're at a high enough confirmation count that we can give an estimate + # We should have estimates for all higher confirmation counts + if valid_estimate: + raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate") + # Check on the expected number of different confirmation counts # that we might not have valid estimates for if invalid_estimates > max_invalid: @@ -184,13 +195,13 @@ class EstimateFeeTest(BitcoinTestFramework): # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # (17k is room enough for 110 or so transactions) self.nodes.append(start_node(1, self.options.tmpdir, - ["-blockprioritysize=1500", "-blockmaxsize=18000", + ["-blockprioritysize=1500", "-blockmaxsize=17000", "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"])) connect_nodes(self.nodes[1], 0) # Node2 is a stingy miner, that - # produces too small blocks (room for only 70 or so transactions) - node2args = ["-blockprioritysize=0", "-blockmaxsize=12000", "-maxorphantx=1000", "-relaypriority=0"] + # produces too small blocks (room for only 55 or so transactions) + node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"] self.nodes.append(start_node(2, self.options.tmpdir, node2args)) connect_nodes(self.nodes[0], 2) @@ -229,22 +240,19 @@ class EstimateFeeTest(BitcoinTestFramework): self.fees_per_kb = [] self.memutxo = [] self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting - print("Checking estimates for 1/2/3/6/15/25 blocks") - print("Creating transactions and mining them with a huge block size") - # Create transactions and mine 20 big blocks with node 0 such that the mempool is always emptied - self.transact_and_mine(30, self.nodes[0]) - check_estimates(self.nodes[1], self.fees_per_kb, 1) + print("Will output estimates for 1/2/3/6/15/25 blocks") - print("Creating transactions and mining them with a block size that can't keep up") - # Create transactions and mine 30 small blocks with node 2, but create txs faster than we can mine - self.transact_and_mine(20, self.nodes[2]) - check_estimates(self.nodes[1], self.fees_per_kb, 3) + for i in xrange(2): + print("Creating transactions and mining them with a block size that can't keep up") + # Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine + self.transact_and_mine(10, self.nodes[2]) + check_estimates(self.nodes[1], self.fees_per_kb, 14) - print("Creating transactions and mining them at a block size that is just big enough") - # Generate transactions while mining 40 more blocks, this time with node1 - # which mines blocks with capacity just above the rate that transactions are being created - self.transact_and_mine(40, self.nodes[1]) - check_estimates(self.nodes[1], self.fees_per_kb, 2) + print("Creating transactions and mining them at a block size that is just big enough") + # Generate transactions while mining 10 more blocks, this time with node1 + # which mines blocks with capacity just above the rate that transactions are being created + self.transact_and_mine(10, self.nodes[1]) + check_estimates(self.nodes[1], self.fees_per_kb, 2) # Finish by mining a normal-sized block: while len(self.nodes[1].getrawmempool()) > 0: diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py index 33014dc139..fba469a0dd 100644 --- a/qa/rpc-tests/test_framework/authproxy.py +++ b/qa/rpc-tests/test_framework/authproxy.py @@ -69,7 +69,7 @@ class AuthServiceProxy(object): def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None): self.__service_url = service_url - self.__service_name = service_name + self._service_name = service_name self.__url = urlparse.urlparse(service_url) if self.__url.port is None: port = 80 @@ -102,8 +102,8 @@ class AuthServiceProxy(object): if name.startswith('__') and name.endswith('__'): # Python internal stuff raise AttributeError - if self.__service_name is not None: - name = "%s.%s" % (self.__service_name, name) + if self._service_name is not None: + name = "%s.%s" % (self._service_name, name) return AuthServiceProxy(self.__service_url, name, connection=self.__conn) def _request(self, method, path, postdata): @@ -129,10 +129,10 @@ class AuthServiceProxy(object): def __call__(self, *args): AuthServiceProxy.__id_count += 1 - log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self.__service_name, + log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name, json.dumps(args, default=EncodeDecimal))) postdata = json.dumps({'version': '1.1', - 'method': self.__service_name, + 'method': self._service_name, 'params': args, 'id': AuthServiceProxy.__id_count}, default=EncodeDecimal) response = self._request('POST', self.__url.path, postdata) diff --git a/qa/rpc-tests/test_framework/coverage.py b/qa/rpc-tests/test_framework/coverage.py new file mode 100644 index 0000000000..50f066a850 --- /dev/null +++ b/qa/rpc-tests/test_framework/coverage.py @@ -0,0 +1,101 @@ +""" +This module contains utilities for doing coverage analysis on the RPC +interface. + +It provides a way to track which RPC commands are exercised during +testing. + +""" +import os + + +REFERENCE_FILENAME = 'rpc_interface.txt' + + +class AuthServiceProxyWrapper(object): + """ + An object that wraps AuthServiceProxy to record specific RPC calls. + + """ + def __init__(self, auth_service_proxy_instance, coverage_logfile=None): + """ + Kwargs: + auth_service_proxy_instance (AuthServiceProxy): the instance + being wrapped. + coverage_logfile (str): if specified, write each service_name + out to a file when called. + + """ + self.auth_service_proxy_instance = auth_service_proxy_instance + self.coverage_logfile = coverage_logfile + + def __getattr__(self, *args, **kwargs): + return_val = self.auth_service_proxy_instance.__getattr__( + *args, **kwargs) + + return AuthServiceProxyWrapper(return_val, self.coverage_logfile) + + def __call__(self, *args, **kwargs): + """ + Delegates to AuthServiceProxy, then writes the particular RPC method + called to a file. + + """ + return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) + rpc_method = self.auth_service_proxy_instance._service_name + + if self.coverage_logfile: + with open(self.coverage_logfile, 'a+') as f: + f.write("%s\n" % rpc_method) + + return return_val + + @property + def url(self): + return self.auth_service_proxy_instance.url + + +def get_filename(dirname, n_node): + """ + Get a filename unique to the test process ID and node. + + This file will contain a list of RPC commands covered. + """ + pid = str(os.getpid()) + return os.path.join( + dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node))) + + +def write_all_rpc_commands(dirname, node): + """ + Write out a list of all RPC functions available in `bitcoin-cli` for + coverage comparison. This will only happen once per coverage + directory. + + Args: + dirname (str): temporary test dir + node (AuthServiceProxy): client + + Returns: + bool. if the RPC interface file was written. + + """ + filename = os.path.join(dirname, REFERENCE_FILENAME) + + if os.path.isfile(filename): + return False + + help_output = node.help().split('\n') + commands = set() + + for line in help_output: + line = line.strip() + + # Ignore blanks and headers + if line and not line.startswith('='): + commands.add("%s\n" % line.split()[0]) + + with open(filename, 'w') as f: + f.writelines(list(commands)) + + return True diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index 5671431f6e..ae2d91ab60 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -13,8 +13,20 @@ import shutil import tempfile import traceback +from .util import ( + initialize_chain, + assert_equal, + start_nodes, + connect_nodes_bi, + sync_blocks, + sync_mempools, + stop_nodes, + wait_bitcoinds, + enable_coverage, + check_json_precision, + initialize_chain_clean, +) from authproxy import AuthServiceProxy, JSONRPCException -from util import * class BitcoinTestFramework(object): @@ -96,6 +108,8 @@ class BitcoinTestFramework(object): help="Root directory for datadirs") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", help="Print out all RPC calls as they are made") + parser.add_option("--coveragedir", dest="coveragedir", + help="Write tested RPC commands into this directory") self.add_options(parser) (self.options, self.args) = parser.parse_args() @@ -103,6 +117,9 @@ class BitcoinTestFramework(object): import logging logging.basicConfig(level=logging.DEBUG) + if self.options.coveragedir: + enable_coverage(self.options.coveragedir) + os.environ['PATH'] = self.options.srcdir+":"+os.environ['PATH'] check_json_precision() @@ -173,7 +190,8 @@ class ComparisonTestFramework(BitcoinTestFramework): initialize_chain_clean(self.options.tmpdir, self.num_nodes) def setup_network(self): - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, - binary=[self.options.testbinary] + - [self.options.refbinary]*(self.num_nodes-1)) + self.nodes = start_nodes( + self.num_nodes, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, + binary=[self.options.testbinary] + + [self.options.refbinary]*(self.num_nodes-1)) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 3759cc8162..30dd5de585 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -17,8 +17,43 @@ import subprocess import time import re -from authproxy import AuthServiceProxy, JSONRPCException -from util import * +from . import coverage +from .authproxy import AuthServiceProxy, JSONRPCException + +COVERAGE_DIR = None + + +def enable_coverage(dirname): + """Maintain a log of which RPC calls are made during testing.""" + global COVERAGE_DIR + COVERAGE_DIR = dirname + + +def get_rpc_proxy(url, node_number, timeout=None): + """ + Args: + url (str): URL of the RPC server to call + node_number (int): the node number (or id) that this calls to + + Kwargs: + timeout (int): HTTP timeout in seconds + + Returns: + AuthServiceProxy. convenience object for making RPC calls. + + """ + proxy_kwargs = {} + if timeout is not None: + proxy_kwargs['timeout'] = timeout + + proxy = AuthServiceProxy(url, **proxy_kwargs) + proxy.url = url # store URL on proxy for info + + coverage_logfile = coverage.get_filename( + COVERAGE_DIR, node_number) if COVERAGE_DIR else None + + return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile) + def p2p_port(n): return 11000 + n + os.getpid()%999 @@ -79,13 +114,13 @@ def initialize_chain(test_dir): """ if (not os.path.isdir(os.path.join("cache","node0")) - or not os.path.isdir(os.path.join("cache","node1")) - or not os.path.isdir(os.path.join("cache","node2")) + or not os.path.isdir(os.path.join("cache","node1")) + or not os.path.isdir(os.path.join("cache","node2")) or not os.path.isdir(os.path.join("cache","node3"))): #find and delete old cache directories if any exist for i in range(4): - if os.path.isdir(os.path.join("cache","node"+str(i))): + if os.path.isdir(os.path.join("cache","node"+str(i))): shutil.rmtree(os.path.join("cache","node"+str(i))) devnull = open(os.devnull, "w") @@ -103,11 +138,13 @@ def initialize_chain(test_dir): if os.getenv("PYTHON_DEBUG", ""): print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed" devnull.close() + rpcs = [] + for i in range(4): try: - url = "http://rt:rt@127.0.0.1:%d"%(rpc_port(i),) - rpcs.append(AuthServiceProxy(url)) + url = "http://rt:rt@127.0.0.1:%d" % (rpc_port(i),) + rpcs.append(get_rpc_proxy(url, i)) except: sys.stderr.write("Error connecting to "+url+"\n") sys.exit(1) @@ -190,11 +227,12 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= print "start_node: calling bitcoin-cli -rpcwait getblockcount returned" devnull.close() url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i)) - if timewait is not None: - proxy = AuthServiceProxy(url, timeout=timewait) - else: - proxy = AuthServiceProxy(url) - proxy.url = url # store URL on proxy for info + + proxy = get_rpc_proxy(url, i, timeout=timewait) + + if COVERAGE_DIR: + coverage.write_all_rpc_commands(COVERAGE_DIR, proxy) + return proxy def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None): diff --git a/src/Makefile.am b/src/Makefile.am index f35b9dc898..f1e98dabde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,8 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) +AM_CXXFLAGS = $(HARDENED_CXXFLAGS) +AM_CPPFLAGS = $(HARDENED_CPPFLAGS) if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include @@ -14,7 +16,7 @@ $(LIBLEVELDB): $(LIBMEMENV) $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" + OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config @@ -102,8 +104,6 @@ BITCOIN_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ - eccryptoverify.h \ - ecwrapper.h \ hash.h \ httprpc.h \ httpserver.h \ @@ -149,6 +149,7 @@ BITCOIN_CORE_H = \ threadsafety.h \ timedata.h \ tinyformat.h \ + torcontrol.h \ txdb.h \ txmempool.h \ ui_interface.h \ @@ -178,7 +179,8 @@ obj/build.h: FORCE libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt -libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ alert.cpp \ @@ -206,6 +208,7 @@ libbitcoin_server_a_SOURCES = \ rpcserver.cpp \ script/sigcache.cpp \ timedata.cpp \ + torcontrol.cpp \ txdb.cpp \ txmempool.cpp \ validationinterface.cpp \ @@ -215,6 +218,7 @@ if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) +libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ zmq/zmqabstractnotifier.cpp \ zmq/zmqnotificationinterface.cpp \ @@ -224,7 +228,8 @@ endif # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled -libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ wallet/crypter.cpp \ wallet/db.cpp \ @@ -236,7 +241,8 @@ libbitcoin_wallet_a_SOURCES = \ $(BITCOIN_CORE_H) # crypto primitives library -crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/common.h \ crypto/hmac_sha256.cpp \ @@ -253,7 +259,8 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha512.h # common: shared between bitcoind, and bitcoin-qt and non-server tools -libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ amount.cpp \ arith_uint256.cpp \ @@ -263,8 +270,6 @@ libbitcoin_common_a_SOURCES = \ compressor.cpp \ core_read.cpp \ core_write.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ hash.cpp \ key.cpp \ keystore.cpp \ @@ -284,7 +289,8 @@ libbitcoin_common_a_SOURCES = \ # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. -libbitcoin_util_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/pagelocker.cpp \ chainparamsbase.cpp \ @@ -308,7 +314,8 @@ libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp endif # cli: shared between bitcoin-cli and bitcoin-qt -libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ rpcclient.cpp \ $(BITCOIN_CORE_H) @@ -318,7 +325,8 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # bitcoind binary # bitcoind_SOURCES = bitcoind.cpp -bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) +bitcoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +bitcoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -347,7 +355,8 @@ bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPN # bitcoin-cli binary # bitcoin_cli_SOURCES = bitcoin-cli.cpp -bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -364,7 +373,8 @@ bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # bitcoin-tx binary # bitcoin_tx_SOURCES = bitcoin-tx.cpp -bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES) +bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -390,8 +400,6 @@ libbitcoinconsensus_la_SOURCES = \ crypto/sha1.cpp \ crypto/sha256.cpp \ crypto/sha512.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ hash.cpp \ primitives/transaction.cpp \ pubkey.cpp \ @@ -405,9 +413,10 @@ if GLIBC_BACK_COMPAT libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp endif -libbitcoinconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) -libbitcoinconsensus_la_LIBADD = $(CRYPTO_LIBS) -libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) +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 # @@ -443,7 +452,7 @@ clean-local: .mm.o: $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $< + $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $< %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 61fe9e287d..d660a3a747 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -9,7 +9,8 @@ bench_bench_bitcoin_SOURCES = \ bench/bench.h \ bench/Examples.cpp -bench_bench_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ +bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ +bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_bitcoin_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ @@ -31,7 +32,6 @@ endif bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) - CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno CLEANFILES += $(CLEAN_BITCOIN_BENCH) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 67fd7c1076..e62003a513 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -327,8 +327,9 @@ BITCOIN_RC = qt/res/bitcoin-qt-res.rc BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \ -I$(builddir)/qt/forms -DQT_NO_KEYWORDS -qt_libbitcoinqt_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ +qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) +qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) @@ -350,8 +351,9 @@ $(QT_MOC): $(PROTOBUF_H) $(QT_MOC_CPP): $(PROTOBUF_H) # bitcoin-qt binary # -qt_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ +qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) +qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp if TARGET_DARWIN diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index b8725c872d..ede3fac4c3 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -12,7 +12,7 @@ TEST_QT_H = \ qt/test/paymentrequestdata.h \ qt/test/paymentservertests.h -qt_test_test_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ +qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ @@ -38,6 +38,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBIT $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno diff --git a/src/Makefile.test.include b/src/Makefile.test.include index f23a8f41fc..2328d0b4cc 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -93,9 +93,10 @@ BITCOIN_TESTS += \ endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) -test_test_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) +test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) +test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 48033cd8ad..9f8b2b98af 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -477,9 +477,15 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) class Secp256k1Init { + ECCVerifyHandle globalVerifyHandle; + public: - Secp256k1Init() { ECC_Start(); } - ~Secp256k1Init() { ECC_Stop(); } + Secp256k1Init() { + ECC_Start(); + } + ~Secp256k1Init() { + ECC_Stop(); + } }; static void MutateTx(CMutableTransaction& tx, const string& command, diff --git a/src/chainparams.cpp b/src/chainparams.cpp index dd26c3b31a..5d6d1ef9d8 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -73,6 +73,8 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.BIP34Height = 227931; + consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -153,6 +155,8 @@ public: consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 100; + consensus.BIP34Height = 21111; + consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -216,6 +220,8 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest + consensus.BIP34Hash = uint256(); consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; diff --git a/src/coins.cpp b/src/coins.cpp index f02949de53..f0ea5c0459 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -117,6 +117,15 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { return CCoinsModifier(*this, ret.first, cachedCoinUsage); } +CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) { + assert(!hasModifier); + std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); + ret.first->second.coins.Clear(); + ret.first->second.flags = CCoinsCacheEntry::FRESH; + ret.first->second.flags |= CCoinsCacheEntry::DIRTY; + return CCoinsModifier(*this, ret.first, 0); +} + const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const { CCoinsMap::const_iterator it = FetchCoins(txid); if (it == cacheCoins.end()) { @@ -151,18 +160,23 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). CCoinsMap::iterator itUs = cacheCoins.find(it->first); if (itUs == cacheCoins.end()) { - if (!it->second.coins.IsPruned()) { - // The parent cache does not have an entry, while the child - // cache does have (a non-pruned) one. Move the data up, and - // mark it as fresh (if the grandparent did have it, we - // would have pulled it in at first GetCoins). - assert(it->second.flags & CCoinsCacheEntry::FRESH); + // The parent cache does not have an entry, while the child does + // We can ignore it if it's both FRESH and pruned in the child + if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coins.IsPruned())) { + // Otherwise we will need to create it in the parent + // and move the data up and mark it as dirty CCoinsCacheEntry& entry = cacheCoins[it->first]; entry.coins.swap(it->second.coins); cachedCoinsUsage += entry.coins.DynamicMemoryUsage(); - entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH; + entry.flags = CCoinsCacheEntry::DIRTY; + // We can mark it FRESH in the parent if it was FRESH in the child + // Otherwise it might have just been flushed from the parent's cache + // and already exist in the grandparent + if (it->second.flags & CCoinsCacheEntry::FRESH) + entry.flags |= CCoinsCacheEntry::FRESH; } } else { + // Found the entry in the parent cache if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) { // The grandparent does not have an entry, and the child is // modified and being pruned. This means we can just delete diff --git a/src/coins.h b/src/coins.h index bf4a777b8a..3b45cb0a34 100644 --- a/src/coins.h +++ b/src/coins.h @@ -420,6 +420,17 @@ public: CCoinsModifier ModifyCoins(const uint256 &txid); /** + * Return a modifiable reference to a CCoins. Assumes that no entry with the given + * txid exists and creates a new one. This saves a database access in the case where + * the coins were to be wiped out by FromTx anyway. This should not be called with + * the 2 historical coinbase duplicate pairs because the new coins are marked fresh, and + * in the event the duplicate coinbase was spent before a flush, the now pruned coins + * would not properly overwrite the first coinbase of the pair. Simultaneous modifications + * are not allowed. + */ + CCoinsModifier ModifyNewCoins(const uint256 &txid); + + /** * Push the modifications applied to this cache to its base. * Failure to call this method before destruction will cause the changes to be forgotten. * If false is returned, the state of this cache (and its backing view) will be undefined. diff --git a/src/consensus/params.h b/src/consensus/params.h index efbbbed352..5ebc48a8df 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -19,6 +19,9 @@ struct Params { int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; int nMajorityWindow; + /** Block height and hash at which BIP34 becomes active */ + int BIP34Height; + uint256 BIP34Hash; /** Proof of work parameters */ uint256 powLimit; bool fPowAllowMinDifficultyBlocks; diff --git a/src/eccryptoverify.cpp b/src/eccryptoverify.cpp deleted file mode 100644 index e894e1122c..0000000000 --- a/src/eccryptoverify.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// 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. - -#include "eccryptoverify.h" - -namespace { - -int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) { - while (c1len > c2len) { - if (*c1) - return 1; - c1++; - c1len--; - } - while (c2len > c1len) { - if (*c2) - return -1; - c2++; - c2len--; - } - while (c1len > 0) { - if (*c1 > *c2) - return 1; - if (*c2 > *c1) - return -1; - c1++; - c2++; - c1len--; - } - return 0; -} - -/** Order of secp256k1's generator minus 1. */ -const unsigned char vchMaxModOrder[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 -}; - -/** Half of the order of secp256k1's generator minus 1. */ -const unsigned char vchMaxModHalfOrder[32] = { - 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D, - 0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0 -}; - -const unsigned char vchZero[1] = {0}; -} // anon namespace - -namespace eccrypto { - -bool Check(const unsigned char *vch) { - return vch && - CompareBigEndian(vch, 32, vchZero, 0) > 0 && - CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0; -} - -bool CheckSignatureElement(const unsigned char *vch, int len, bool half) { - return vch && - CompareBigEndian(vch, len, vchZero, 0) > 0 && - CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0; -} - -} // namespace eccrypto diff --git a/src/eccryptoverify.h b/src/eccryptoverify.h deleted file mode 100644 index c67c1e44fc..0000000000 --- a/src/eccryptoverify.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// 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. - -#ifndef BITCOIN_ECCRYPTOVERIFY_H -#define BITCOIN_ECCRYPTOVERIFY_H - -#include <vector> -#include <cstdlib> - -class uint256; - -namespace eccrypto { - -bool Check(const unsigned char *vch); -bool CheckSignatureElement(const unsigned char *vch, int len, bool half); - -} // eccrypto namespace - -#endif // BITCOIN_ECCRYPTOVERIFY_H diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp deleted file mode 100644 index f94bc954fd..0000000000 --- a/src/ecwrapper.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// 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. - -#include "ecwrapper.h" - -#include "serialize.h" -#include "uint256.h" - -#include <openssl/bn.h> -#include <openssl/ecdsa.h> -#include <openssl/obj_mac.h> - -namespace { - -class ecgroup_order -{ -public: - static const EC_GROUP* get() - { - static const ecgroup_order wrapper; - return wrapper.pgroup; - } - -private: - ecgroup_order() - : pgroup(EC_GROUP_new_by_curve_name(NID_secp256k1)) - { - } - - ~ecgroup_order() - { - EC_GROUP_free(pgroup); - } - - EC_GROUP* pgroup; -}; - -/** - * Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields - * recid selects which key is recovered - * if check is non-zero, additional checks are performed - */ -int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) -{ - if (!eckey) return 0; - - int ret = 0; - BN_CTX *ctx = NULL; - - BIGNUM *x = NULL; - BIGNUM *e = NULL; - BIGNUM *order = NULL; - BIGNUM *sor = NULL; - BIGNUM *eor = NULL; - BIGNUM *field = NULL; - EC_POINT *R = NULL; - EC_POINT *O = NULL; - EC_POINT *Q = NULL; - BIGNUM *rr = NULL; - BIGNUM *zero = NULL; - int n = 0; - int i = recid / 2; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } - BN_CTX_start(ctx); - order = BN_CTX_get(ctx); - if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } - x = BN_CTX_get(ctx); - if (!BN_copy(x, order)) { ret=-1; goto err; } - if (!BN_mul_word(x, i)) { ret=-1; goto err; } - if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } - field = BN_CTX_get(ctx); - if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } - if (BN_cmp(x, field) >= 0) { ret=0; goto err; } - if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } - if (check) - { - if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } - if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } - } - if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - n = EC_GROUP_get_degree(group); - e = BN_CTX_get(ctx); - if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } - if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); - zero = BN_CTX_get(ctx); - if (!BN_zero(zero)) { ret=-1; goto err; } - if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } - rr = BN_CTX_get(ctx); - if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } - sor = BN_CTX_get(ctx); - if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } - eor = BN_CTX_get(ctx); - if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } - if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } - if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } - - ret = 1; - -err: - if (ctx) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } - if (R != NULL) EC_POINT_free(R); - if (O != NULL) EC_POINT_free(O); - if (Q != NULL) EC_POINT_free(Q); - return ret; -} - -} // anon namespace - -CECKey::CECKey() { - pkey = EC_KEY_new(); - assert(pkey != NULL); - int result = EC_KEY_set_group(pkey, ecgroup_order::get()); - assert(result); -} - -CECKey::~CECKey() { - EC_KEY_free(pkey); -} - -void CECKey::GetPubKey(std::vector<unsigned char> &pubkey, bool fCompressed) { - EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); - int nSize = i2o_ECPublicKey(pkey, NULL); - assert(nSize); - assert(nSize <= 65); - pubkey.clear(); - pubkey.resize(nSize); - unsigned char *pbegin(begin_ptr(pubkey)); - int nSize2 = i2o_ECPublicKey(pkey, &pbegin); - assert(nSize == nSize2); -} - -bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) { - return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL; -} - -bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) { - if (vchSig.empty()) - return false; - - // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. - unsigned char *norm_der = NULL; - ECDSA_SIG *norm_sig = ECDSA_SIG_new(); - const unsigned char* sigptr = &vchSig[0]; - assert(norm_sig); - if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) - { - /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on - * error. But OpenSSL's own use of this function redundantly frees the - * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a - * clear contract for the function behaving the same way is more - * conservative. - */ - ECDSA_SIG_free(norm_sig); - return false; - } - int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); - ECDSA_SIG_free(norm_sig); - if (derlen <= 0) - return false; - - // -1 = error, 0 = bad sig, 1 = good - bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; - OPENSSL_free(norm_der); - return ret; -} - -bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec) -{ - if (rec<0 || rec>=3) - return false; - ECDSA_SIG *sig = ECDSA_SIG_new(); - BN_bin2bn(&p64[0], 32, sig->r); - BN_bin2bn(&p64[32], 32, sig->s); - bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1; - ECDSA_SIG_free(sig); - return ret; -} - -bool CECKey::TweakPublic(const unsigned char vchTweak[32]) { - bool ret = true; - BN_CTX *ctx = BN_CTX_new(); - BN_CTX_start(ctx); - BIGNUM *bnTweak = BN_CTX_get(ctx); - BIGNUM *bnOrder = BN_CTX_get(ctx); - BIGNUM *bnOne = BN_CTX_get(ctx); - const EC_GROUP *group = EC_KEY_get0_group(pkey); - EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order... - BN_bin2bn(vchTweak, 32, bnTweak); - if (BN_cmp(bnTweak, bnOrder) >= 0) - ret = false; // extremely unlikely - EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group); - BN_one(bnOne); - EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx); - if (EC_POINT_is_at_infinity(group, point)) - ret = false; // ridiculously unlikely - EC_KEY_set_public_key(pkey, point); - EC_POINT_free(point); - BN_CTX_end(ctx); - BN_CTX_free(ctx); - return ret; -} - -bool CECKey::SanityCheck() -{ - const EC_GROUP *pgroup = ecgroup_order::get(); - if(pgroup == NULL) - return false; - // TODO Is there more EC functionality that could be missing? - return true; -} diff --git a/src/ecwrapper.h b/src/ecwrapper.h deleted file mode 100644 index efb6cd18a7..0000000000 --- a/src/ecwrapper.h +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -#ifndef BITCOIN_ECWRAPPER_H -#define BITCOIN_ECWRAPPER_H - -#include <cstddef> -#include <vector> - -#include <openssl/ec.h> - -class uint256; - -/** RAII Wrapper around OpenSSL's EC_KEY */ -class CECKey { -private: - EC_KEY *pkey; - -public: - CECKey(); - ~CECKey(); - - void GetPubKey(std::vector<unsigned char>& pubkey, bool fCompressed); - bool SetPubKey(const unsigned char* pubkey, size_t size); - bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig); - - /** - * reconstruct public key from a compact signature - * This is only slightly more CPU intensive than just verifying it. - * If this function succeeds, the recovered public key is guaranteed to be valid - * (the signature is a valid signature of the given data for that key) - */ - bool Recover(const uint256 &hash, const unsigned char *p64, int rec); - - bool TweakPublic(const unsigned char vchTweak[32]); - static bool SanityCheck(); -}; - -#endif // BITCOIN_ECWRAPPER_H diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 8698abb900..91518d7c5f 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -365,6 +365,10 @@ static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue) /** libevent event log callback */ static void libevent_log_cb(int severity, const char *msg) { +#ifndef EVENT_LOG_WARN +// EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed. +# define EVENT_LOG_WARN _EVENT_LOG_WARN +#endif if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category LogPrintf("libevent: %s\n", msg); else @@ -438,15 +442,17 @@ bool InitHTTPServer() return true; } -bool StartHTTPServer(boost::thread_group& threadGroup) +boost::thread threadHTTP; + +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); - threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); + threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); for (int i = 0; i < rpcThreads; i++) - threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); return true; } @@ -461,13 +467,6 @@ void InterruptHTTPServer() // Reject requests on current connections evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL); } - if (eventBase) { - // Force-exit event loop after predefined time - struct timeval tv; - tv.tv_sec = 10; - tv.tv_usec = 0; - event_base_loopexit(eventBase, &tv); - } if (workQueue) workQueue->Interrupt(); } @@ -480,6 +479,24 @@ void StopHTTPServer() workQueue->WaitExit(); delete workQueue; } + if (eventBase) { + LogPrint("http", "Waiting for HTTP event thread to exit\n"); + // Give event loop a few seconds to exit (to send back last RPC responses), then break it + // Before this was solved with event_base_loopexit, but that didn't work as expected in + // at least libevent 2.0.21 and always introduced a delay. In libevent + // 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 + LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n"); + event_base_loopbreak(eventBase); + threadHTTP.join(); + } + } if (eventHTTP) { evhttp_free(eventHTTP); eventHTTP = 0; @@ -488,6 +505,7 @@ void StopHTTPServer() event_base_free(eventBase); eventBase = 0; } + LogPrint("http", "Stopped HTTP server\n"); } struct event_base* EventBase() diff --git a/src/httpserver.h b/src/httpserver.h index b377dc19fc..20a119cc5c 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -28,7 +28,7 @@ bool InitHTTPServer(); * This is separate from InitHTTPServer to give users race-condition-free time * to register their handlers between InitHTTPServer and StartHTTPServer. */ -bool StartHTTPServer(boost::thread_group& threadGroup); +bool StartHTTPServer(); /** Interrupt HTTP server threads */ void InterruptHTTPServer(); /** Stop HTTP server */ diff --git a/src/init.cpp b/src/init.cpp index 5f2dc8bf2f..3028802b93 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -25,9 +25,11 @@ #include "policy/policy.h" #include "rpcserver.h" #include "script/standard.h" +#include "script/sigcache.h" #include "scheduler.h" #include "txdb.h" #include "txmempool.h" +#include "torcontrol.h" #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" @@ -152,6 +154,7 @@ public: static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; +static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) { @@ -159,6 +162,7 @@ void Interrupt(boost::thread_group& threadGroup) InterruptHTTPRPC(); InterruptRPC(); InterruptREST(); + InterruptTorControl(); threadGroup.interrupt_all(); } @@ -187,6 +191,7 @@ void Shutdown() #endif GenerateBitcoins(false, 0, Params()); StopNode(); + StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); if (fFeeEstimatesInitialized) @@ -239,6 +244,7 @@ void Shutdown() delete pwalletMain; pwalletMain = NULL; #endif + globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); } @@ -306,6 +312,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); + if (showDebug) + strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY)); strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS)); strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL)); strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf")); @@ -347,17 +355,23 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address")); strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0)); strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); + strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), 5000)); strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), 1000)); strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)")); strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); + strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), 1)); + if (showDebug) + strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of bloom filters (default: %u)", 0)); strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), 8333, 18333)); strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); + strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); + strUsage += HelpMessageOpt("-torpassword=<pass>", _("Tor control port password (default: empty)")); #ifdef USE_UPNP #if USE_UPNP strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)")); @@ -368,7 +382,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-whitelist=<netmask>", _("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")); - strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), 0)); + strUsage += HelpMessageOpt("-whitelistalwaysrelay", strprintf(_("Always relay transactions received from whitelisted peers (default: %d)"), DEFAULT_WHITELISTALWAYSRELAY)); + strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET strUsage += HelpMessageGroup(_("Wallet options:")); @@ -397,9 +412,9 @@ std::string HelpMessage(HelpMessageMode mode) #if ENABLE_ZMQ strUsage += HelpMessageGroup(_("ZeroMQ notification options:")); strUsage += HelpMessageOpt("-zmqpubhashblock=<address>", _("Enable publish hash block in <address>")); - strUsage += HelpMessageOpt("-zmqpubhashtransaction=<address>", _("Enable publish hash transaction in <address>")); + strUsage += HelpMessageOpt("-zmqpubhashtx=<address>", _("Enable publish hash transaction in <address>")); strUsage += HelpMessageOpt("-zmqpubrawblock=<address>", _("Enable publish raw block in <address>")); - strUsage += HelpMessageOpt("-zmqpubrawtransaction=<address>", _("Enable publish raw transaction in <address>")); + strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", _("Enable publish raw transaction in <address>")); #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); @@ -422,7 +437,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " + @@ -437,7 +452,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15)); strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1)); - strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000)); + strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); } strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE))); @@ -489,6 +504,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-min", _("Start minimized")); strUsage += HelpMessageOpt("-rootcertificates=<file>", _("Set SSL root certificates for payment request (default: -system-)")); strUsage += HelpMessageOpt("-splash", _("Show splash screen on startup (default: 1)")); + strUsage += HelpMessageOpt("-resetguisettings", _("Reset all settings changes made over the GUI")); if (showDebug) { strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)"); } @@ -639,8 +655,7 @@ void ThreadImport(std::vector<boost::filesystem::path> 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()) @@ -661,7 +676,7 @@ bool AppInitServers(boost::thread_group& threadGroup) return false; if (GetBoolArg("-rest", false) && !StartREST()) return false; - if (!StartHTTPServer(threadGroup)) + if (!StartHTTPServer()) return false; return true; } @@ -777,6 +792,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); if (SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); + if (SoftSetBoolArg("-listenonion", false)) + LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } if (mapArgs.count("-externalip")) { @@ -807,7 +824,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif } - + + // disable walletbroadcast and whitelistalwaysrelay in blocksonly mode + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { + if (SoftSetBoolArg("-whitelistalwaysrelay", false)) + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistalwaysrelay=0\n", __func__); +#ifdef ENABLE_WALLET + if (SoftSetBoolArg("-walletbroadcast", false)) + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); +#endif + } + // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); @@ -852,11 +879,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = GetBoolArg("-checkpoints", true); - // -mempoollimit limits - int64_t nMempoolSizeLimit = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; - int64_t nMempoolDescendantSizeLimit = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000; - if (nMempoolSizeLimit < 0 || nMempoolSizeLimit < nMempoolDescendantSizeLimit * 40) - return InitError(strprintf(_("-maxmempool must be at least %d MB"), GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25)); + // mempool limits + int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; + if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) + return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000.0))); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); @@ -969,6 +996,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Initialize elliptic curve code ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); // Sanity check if (!InitSanityCheck()) @@ -1184,7 +1212,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif if (mapArgs.count("-maxuploadtarget")) { - CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", 0)*1024*1024); + CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); } // ********************************************************* Step 7: load block chain @@ -1567,6 +1595,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); #endif + if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) + StartTorControl(threadGroup, scheduler); + StartNode(threadGroup, scheduler); // Monitor the chain, and alert if we get blocks much quicker or slower than expected @@ -1576,7 +1607,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) scheduler.scheduleEvery(f, nPowTargetSpacing); // Generate coins in the background - GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), Params()); + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams); // ********************************************************* Step 12: finished diff --git a/src/key.cpp b/src/key.cpp index b772dff333..a24fa8a4ba 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -7,17 +7,120 @@ #include "arith_uint256.h" #include "crypto/common.h" #include "crypto/hmac_sha512.h" -#include "eccryptoverify.h" #include "pubkey.h" #include "random.h" #include <secp256k1.h> -#include "ecwrapper.h" +#include <secp256k1_recovery.h> -static secp256k1_context_t* secp256k1_context = NULL; +static secp256k1_context* secp256k1_context_sign = NULL; + +/** These functions are taken from the libsecp256k1 distribution and are very ugly. */ +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; + 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; +} + +static 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; +} 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) { @@ -30,7 +133,7 @@ void CKey::MakeNewKey(bool fCompressedIn) { } bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { - if (!secp256k1_ec_privkey_import(secp256k1_context, (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; @@ -40,10 +143,11 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; - int privkeylen, ret; + int ret; + size_t privkeylen; privkey.resize(279); privkeylen = 279; - ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); + 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; @@ -51,11 +155,13 @@ CPrivKey CKey::GetPrivKey() const { CPubKey CKey::GetPubKey() const { assert(fValid); + secp256k1_pubkey pubkey; + size_t clen = 65; CPubKey result; - int clen = 65; - int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed); - assert((int)result.size() == clen); + 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; } @@ -64,11 +170,13 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_ if (!fValid) return false; vchSig.resize(72); - int nSigLen = 72; + size_t nSigLen = 72; unsigned char extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); - int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); + secp256k1_ecdsa_signature sig; + int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); assert(ret); + secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig); vchSig.resize(nSigLen); return true; } @@ -92,7 +200,10 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) return false; vchSig.resize(65); int rec = -1; - int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); + secp256k1_ecdsa_recoverable_signature sig; + int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL); + 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); @@ -100,7 +211,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) } bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { - if (!secp256k1_ec_privkey_import(secp256k1_context, (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 = vchPubKey.IsCompressed(); fValid = true; @@ -126,7 +237,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const } memcpy(ccChild.begin(), out+32, 32); memcpy((unsigned char*)keyChild.begin(), begin(), 32); - bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out); + bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out); UnlockObject(out); keyChild.fCompressed = true; keyChild.fValid = ret; @@ -184,20 +295,16 @@ void CExtKey::Decode(const unsigned char code[74]) { } bool ECC_InitSanityCheck() { - if (!CECKey::SanityCheck()) { - return false; - } CKey key; key.MakeNewKey(true); CPubKey pubkey = key.GetPubKey(); return key.VerifyPubKey(pubkey); } - void ECC_Start() { - assert(secp256k1_context == NULL); + assert(secp256k1_context_sign == NULL); - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); assert(ctx != NULL); { @@ -210,12 +317,12 @@ void ECC_Start() { UnlockObject(seed); } - secp256k1_context = ctx; + secp256k1_context_sign = ctx; } void ECC_Stop() { - secp256k1_context_t *ctx = secp256k1_context; - secp256k1_context = NULL; + secp256k1_context *ctx = secp256k1_context_sign; + secp256k1_context_sign = NULL; if (ctx) { secp256k1_context_destroy(ctx); diff --git a/src/main.cpp b/src/main.cpp index e3527a83d1..e48d0a6d43 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -670,10 +670,11 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // IsFinalTx() with one more than chainActive.Height(). const int nBlockHeight = chainActive.Height() + 1; - // Timestamps on the other hand don't get any special treatment, - // because we can't know what timestamp the next block will have, - // and there aren't timestamp applications where it matters. - // However this changes once median past time-locks are enforced: + // BIP113 will require that time-locked transactions have nLockTime set to + // less than the median time of the previous block they're contained in. + // When the next block is created its previous block will be the current + // chain tip, so we use that to calculate the median time passed to + // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) ? chainActive.Tip()->GetMedianTimePast() : GetAdjustedTime(); @@ -1502,10 +1503,17 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach undo.nVersion = coins->nVersion; } } + // add outputs + inputs.ModifyNewCoins(tx.GetHash())->FromTx(tx, nHeight); + } + else { + // add outputs for coinbase tx + // In this case call the full ModifyCoins which will do a database + // lookup to be sure the coins do not already exist otherwise we do not + // know whether to mark them fresh or not. We want the duplicate coinbases + // before BIP30 to still be properly overwritten. + inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); } - - // add outputs - inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); } void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) @@ -1961,6 +1969,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash. !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); + + // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting + // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the + // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first + // before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further + // duplicate transactions descending from the known pairs either. + // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check. + CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); + //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond. + fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); + if (fEnforceBIP30) { BOOST_FOREACH(const CTransaction& tx, block.vtx) { const CCoins* coins = view.AccessCoins(tx.GetHash()); @@ -2032,7 +2051,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector<CScriptCheck> vChecks; - if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) + bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ + if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetHash().ToString(), FormatStateMessage(state)); control.Add(vChecks); @@ -2757,9 +2777,9 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd pos.nPos = vinfoBlockFile[nFile].nSize; } - if (nFile != nLastBlockFile) { + if ((int)nFile != nLastBlockFile) { if (!fKnown) { - LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); + LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString()); } FlushBlockFile(!fKnown); nLastBlockFile = nFile; @@ -2983,9 +3003,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return true; } -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) +static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); @@ -3038,7 +3057,7 @@ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppi CBlockIndex *&pindex = *ppindex; - if (!AcceptBlockHeader(block, state, &pindex)) + if (!AcceptBlockHeader(block, state, chainparams, &pindex)) return false; // Try to process all requested blocks that we don't have, but only @@ -3108,9 +3127,8 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp) { - const CChainParams& chainparams = Params(); // Preliminary checks bool checked = CheckBlock(*pblock, state); @@ -3139,9 +3157,8 @@ bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* return true; } -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); assert(pindexPrev && pindexPrev == chainActive.Tip()); if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash())) @@ -3681,7 +3698,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { CValidationState state; - if (ProcessNewBlock(state, NULL, &block, true, dbp)) + if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp)) nLoaded++; if (state.IsError()) break; @@ -3703,7 +3720,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); CValidationState dummy; - if (ProcessNewBlock(dummy, NULL, &block, true, &it->second)) + if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -4048,8 +4065,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } // disconnect node in case we have reached the outbound limit for serving historical blocks + // never disconnect whitelisted nodes static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) ) + if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) { LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -4163,6 +4181,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } + if (!(nLocalServices & NODE_BLOOM) && + (strCommand == "filterload" || + strCommand == "filteradd" || + strCommand == "filterclear")) + { + if (pfrom->nVersion >= NO_BLOOM_VERSION) { + Misbehaving(pfrom->GetId(), 100); + return false; + } else if (GetBoolArg("-enforcenodebloom", false)) { + pfrom->fDisconnect = true; + return false; + } + } if (strCommand == "version") @@ -4240,9 +4271,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) { + LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString()); pfrom->PushAddress(addr); } else if (IsPeerAddrLocalGood(pfrom)) { addr.SetIP(pfrom->addrLocal); + LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString()); pfrom->PushAddress(addr); } } @@ -4383,6 +4416,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return error("message inv size() = %u", vInv.size()); } + bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + + // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistalwaysrelay is true + if (pfrom->fWhitelisted && GetBoolArg("-whitelistalwaysrelay", DEFAULT_WHITELISTALWAYSRELAY)) + fBlocksOnly = false; + LOCK(cs_main); std::vector<CInv> vToFetch; @@ -4397,9 +4436,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool fAlreadyHave = AlreadyHave(inv); LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id); - if (!fAlreadyHave && !fImporting && !fReindex && inv.type != MSG_BLOCK) - pfrom->AskFor(inv); - if (inv.type == MSG_BLOCK) { UpdateBlockAvailability(pfrom->GetId(), inv.hash); if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { @@ -4423,6 +4459,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } + else + { + if (fBlocksOnly) + LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id); + else if (!fAlreadyHave && !fImporting && !fReindex) + pfrom->AskFor(inv); + } // Track requests for our stuff GetMainSignals().Inventory(inv.hash); @@ -4510,10 +4553,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> locator >> hashStop; LOCK(cs_main); - - if (IsInitialBlockDownload()) + if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { + LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id); return true; - + } CBlockIndex* pindex = NULL; if (locator.IsNull()) { @@ -4547,6 +4590,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == "tx") { + // Stop processing the transaction early if + // We are in blocks only mode and peer is either not whitelisted or whitelistalwaysrelay is off + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistalwaysrelay", DEFAULT_WHITELISTALWAYSRELAY))) + { + LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id); + return true; + } + vector<uint256> vWorkQueue; vector<uint256> vEraseQueue; CTransaction tx; @@ -4644,7 +4695,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, assert(recentRejects); recentRejects->insert(tx.GetHash()); - if (pfrom->fWhitelisted) { + if (pfrom->fWhitelisted && GetBoolArg("-whitelistalwaysrelay", DEFAULT_WHITELISTALWAYSRELAY)) { // Always relay transactions received from whitelisted peers, even // if they were rejected from the mempool, allowing the node to // function as a gateway for nodes hidden behind it. @@ -4700,7 +4751,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } - if (!AcceptBlockHeader(header, state, &pindexLast)) { + if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { if (nDoS > 0) @@ -4740,7 +4791,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes @@ -4904,21 +4955,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (!(nLocalServices & NODE_BLOOM) && - (strCommand == "filterload" || - strCommand == "filteradd" || - strCommand == "filterclear") && - //TODO: Remove this line after reasonable network upgrade - pfrom->nVersion >= NO_BLOOM_VERSION) - { - if (pfrom->nVersion >= NO_BLOOM_VERSION) - Misbehaving(pfrom->GetId(), 100); - //TODO: Enable this after reasonable network upgrade - //else - // pfrom->fDisconnect = true; - } - - else if (strCommand == "filterload") { CBloomFilter filter; diff --git a/src/main.h b/src/main.h index a82e3faa45..347624c520 100644 --- a/src/main.h +++ b/src/main.h @@ -31,6 +31,7 @@ class CBlockIndex; class CBlockTreeDB; class CBloomFilter; +class CChainParams; class CInv; class CScriptCheck; class CTxMemPool; @@ -41,20 +42,20 @@ struct CNodeStateStats; /** Default for accepting alerts from the P2P network. */ static const bool DEFAULT_ALERTS = true; +/** Default for DEFAULT_WHITELISTALWAYSRELAY. */ +static const bool DEFAULT_WHITELISTALWAYSRELAY = true; /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** Default for -limitancestorcount, max number of in-mempool ancestors */ -static const unsigned int DEFAULT_ANCESTOR_LIMIT = 100; +static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25; /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ -static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 900; +static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101; /** Default for -limitdescendantcount, max number of in-mempool descendants */ -static const unsigned int DEFAULT_DESCENDANT_LIMIT = 1000; +static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25; /** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ -static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 2500; -/** Default for -maxmempool, maximum megabytes of mempool memory usage */ -static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300; +static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101; /** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72; /** The maximum size of a blk?????.dat file (since 0.8) */ @@ -159,7 +160,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -378,11 +379,10 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex **ppindex= NULL); class CBlockFileInfo diff --git a/src/miner.cpp b/src/miner.cpp index 053d9cdbc4..bb6b513372 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -99,9 +99,8 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam return nNewTime - nOldTime; } -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) { - const CChainParams& chainparams = Params(); // Create new block auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) @@ -110,7 +109,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios - if (Params().MineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); // Create coinbase tx @@ -345,13 +344,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; - if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) + if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); } @@ -432,7 +431,7 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) return error("BitcoinMiner: ProcessNewBlock, block not accepted"); return true; @@ -478,7 +477,7 @@ void static BitcoinMiner(const CChainParams& chainparams) unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); diff --git a/src/miner.h b/src/miner.h index ad13204818..7b544303e0 100644 --- a/src/miner.h +++ b/src/miner.h @@ -29,7 +29,7 @@ struct CBlockTemplate /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); /** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); diff --git a/src/net.cpp b/src/net.cpp index e18e8d0e29..cff4c54505 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -216,6 +216,7 @@ void AdvertizeLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { + LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } @@ -262,6 +263,14 @@ bool AddLocal(const CNetAddr &addr, int nScore) return AddLocal(CService(addr, GetListenPort()), nScore); } +bool RemoveLocal(const CService& addr) +{ + LOCK(cs_mapLocalHost); + LogPrintf("RemoveLocal(%s)\n", addr.ToString()); + mapLocalHost.erase(addr); + return true; +} + /** Make a particular network entirely off-limits (no automatic connects to it) */ void SetLimited(enum Network net, bool fLimited) { @@ -451,7 +460,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("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, true); + nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); } @@ -608,6 +617,7 @@ void CNode::copyStats(CNodeStats &stats) { stats.nodeid = this->GetId(); X(nServices); + X(fRelayTxes); X(nLastSend); X(nLastRecv); X(nTimeConnected); @@ -2108,8 +2118,8 @@ void CNode::SetMaxOutboundTarget(uint64_t limit) uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE; nMaxOutboundLimit = limit; - if (limit < recommendedMinimum) - LogPrintf("Max outbound target is very small (%s) and will be overshot. Recommended minimum is %s\n.", nMaxOutboundLimit, recommendedMinimum); + if (limit > 0 && limit < recommendedMinimum) + LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum); } uint64_t CNode::GetMaxOutboundTarget() @@ -60,6 +60,10 @@ static const bool DEFAULT_UPNP = false; static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; +/** The default for -maxuploadtarget. 0 = Unlimited */ +static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; +/** Default for blocks only*/ +static const bool DEFAULT_BLOCKSONLY = false; unsigned int ReceiveFloodSize(); unsigned int SendBufferSize(); @@ -128,6 +132,7 @@ bool IsLimited(enum Network net); bool IsLimited(const CNetAddr& addr); bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); +bool RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); @@ -175,6 +180,7 @@ class CNodeStats public: NodeId nodeid; uint64_t nServices; + bool fRelayTxes; int64_t nLastSend; int64_t nLastRecv; int64_t nTimeConnected; @@ -339,7 +345,7 @@ public: // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs - // until it has initialized its bloom filter. + // unless it loads a bloom filter. bool fRelayTxes; CSemaphoreGrant grantOutbound; CCriticalSection cs_filter; diff --git a/src/netbase.cpp b/src/netbase.cpp index f5316965ce..83cedfb620 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -227,10 +227,7 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault) return Lookup(pszName, addr, portDefault, false); } -/** - * Convert milliseconds to a struct timeval for select. - */ -struct timeval static MillisToTimeval(int64_t nTimeout) +struct timeval MillisToTimeval(int64_t nTimeout) { struct timeval timeout; timeout.tv_sec = nTimeout / 1000; diff --git a/src/netbase.h b/src/netbase.h index 6f8882b852..2a79f82d72 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -215,5 +215,9 @@ std::string NetworkErrorString(int err); bool CloseSocket(SOCKET& hSocket); /** Disable or enable blocking-mode for a socket */ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking); +/** + * Convert milliseconds to a struct timeval for e.g. select. + */ +struct timeval MillisToTimeval(int64_t nTimeout); #endif // BITCOIN_NETBASE_H diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index ffe31d1942..980ecf10df 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "policy/fees.h" +#include "policy/policy.h" #include "amount.h" #include "primitives/transaction.h" @@ -504,6 +505,33 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) return CFeeRate(median); } +CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) +{ + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget; + // Return failure if trying to analyze a target we're not tracking + if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) + return CFeeRate(0); + + double median = -1; + while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) { + median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); + } + + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget - 1; + + // If mempool is limiting txs , return at least the min fee from the mempool + CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); + if (minPoolFee > 0 && minPoolFee > median) + return CFeeRate(minPoolFee); + + if (median < 0) + return CFeeRate(0); + + return CFeeRate(median); +} + double CBlockPolicyEstimator::estimatePriority(int confTarget) { // Return failure if trying to analyze a target we're not tracking @@ -513,6 +541,30 @@ double CBlockPolicyEstimator::estimatePriority(int confTarget) return priStats.EstimateMedianVal(confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); } +double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) +{ + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget; + // Return failure if trying to analyze a target we're not tracking + if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms()) + return -1; + + // If mempool is limiting txs, no priority txs are allowed + CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); + if (minPoolFee > 0) + return INF_PRIORITY; + + double median = -1; + while (median < 0 && (unsigned int)confTarget <= priStats.GetMaxConfirms()) { + median = priStats.EstimateMedianVal(confTarget++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); + } + + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget - 1; + + return median; +} + void CBlockPolicyEstimator::Write(CAutoFile& fileout) { fileout << nBestSeenHeight; diff --git a/src/policy/fees.h b/src/policy/fees.h index 15577d128a..7a293267d4 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -15,6 +15,7 @@ class CAutoFile; class CFeeRate; class CTxMemPoolEntry; +class CTxMemPool; /** \class CBlockPolicyEstimator * The BlockPolicyEstimator is used for estimating the fee or priority needed @@ -182,8 +183,8 @@ static const unsigned int MAX_BLOCK_CONFIRMS = 25; /** Decay of .998 is a half-life of 346 blocks or about 2.4 days */ static const double DEFAULT_DECAY = .998; -/** Require greater than 85% of X fee transactions to be confirmed within Y blocks for X to be big enough */ -static const double MIN_SUCCESS_PCT = .85; +/** Require greater than 95% of X fee transactions to be confirmed within Y blocks for X to be big enough */ +static const double MIN_SUCCESS_PCT = .95; static const double UNLIKELY_PCT = .5; /** Require an avg of 1 tx in the combined fee bucket per block to have stat significance */ @@ -242,9 +243,21 @@ public: /** Return a fee estimate */ CFeeRate estimateFee(int confTarget); + /** Estimate fee rate needed to get be included in a block within + * confTarget blocks. If no answer can be given at confTarget, return an + * estimate at the lowest target where one can be given. + */ + CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool); + /** Return a priority estimate */ double estimatePriority(int confTarget); + /** Estimate priority needed to get be included in a block within + * confTarget blocks. If no answer can be given at confTarget, return an + * estimate at the lowest target where one can be given. + */ + double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool); + /** Write estimation data to a file */ void Write(CAutoFile& fileout); diff --git a/src/policy/policy.h b/src/policy/policy.h index f269e8d476..c8d2c1a924 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -25,6 +25,8 @@ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; static const unsigned int MAX_P2SH_SIGOPS = 15; /** The maximum number of sigops we're willing to relay/mine in a single tx */ static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; +/** Default for -maxmempool, maximum megabytes of mempool memory usage */ +static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300; /** * Standard script verification flags that standard transactions will comply * with. However scripts violating these flags may still be present in valid diff --git a/src/pubkey.cpp b/src/pubkey.cpp index bdab137600..6ebb152c75 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -4,19 +4,184 @@ #include "pubkey.h" -#include "eccryptoverify.h" +#include <secp256k1.h> +#include <secp256k1_recovery.h> -#include "ecwrapper.h" +namespace +{ +/* Global secp256k1_context object used for verification. */ +secp256k1_context* secp256k1_context_verify = NULL; +} + +/** 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 (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) { + /* 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<unsigned char>& vchSig) const { if (!IsValid()) return false; - 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 (vchSig.size() == 0) { return false; - return true; + } + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { + return false; + } + /* 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<unsigned char>& vchSig) { @@ -24,33 +189,39 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha return false; int recid = (vchSig[0] - 27) & 3; bool fComp = ((vchSig[0] - 27) & 4) != 0; - CECKey key; - if (!key.Recover(hash, &vchSig[1], 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; - std::vector<unsigned char> pubkey; - key.GetPubKey(pubkey, fComp); - Set(pubkey.begin(), pubkey.end()); + } + if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) { + return false; + } + unsigned char pub[65]; + size_t publen = 65; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } bool CPubKey::IsFullyValid() const { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) - return false; - return true; + secp256k1_pubkey pubkey; + return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size()); } bool CPubKey::Decompress() { if (!IsValid()) return false; - 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<unsigned char> pubkey; - key.GetPubKey(pubkey, false); - Set(pubkey.begin(), pubkey.end()); + } + unsigned char pub[65]; + size_t publen = 65; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } @@ -61,13 +232,18 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi unsigned char out[64]; BIP32Hash(cc, nChild, *begin(), begin()+1, out); memcpy(ccChild.begin(), out+32, 32); - CECKey key; - bool ret = key.SetPubKey(begin(), size()); - ret &= key.TweakPublic(out); - std::vector<unsigned char> pubkey; - key.GetPubKey(pubkey, true); - pubkeyChild.Set(pubkey.begin(), pubkey.end()); - return ret; + 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[33]; + size_t publen = 33; + 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[74]) const { @@ -95,3 +271,33 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { out.nChild = nChild; return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode); } + +/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) { + secp256k1_ecdsa_signature sig; + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { + return false; + } + return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig)); +} + +/* static */ int ECCVerifyHandle::refcount = 0; + +ECCVerifyHandle::ECCVerifyHandle() +{ + if (refcount == 0) { + assert(secp256k1_context_verify == NULL); + secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + assert(secp256k1_context_verify != NULL); + } + refcount++; +} + +ECCVerifyHandle::~ECCVerifyHandle() +{ + refcount--; + if (refcount == 0) { + assert(secp256k1_context_verify != NULL); + secp256k1_context_destroy(secp256k1_context_verify); + secp256k1_context_verify = NULL; + } +} diff --git a/src/pubkey.h b/src/pubkey.h index cce9c826e5..a1d437e706 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -177,6 +177,11 @@ public: */ bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const; + /** + * Check whether a signature is normalized (lower-S). + */ + static bool CheckLowS(const std::vector<unsigned char>& vchSig); + //! Recover a public key from a compact signature. bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig); @@ -205,4 +210,15 @@ struct CExtPubKey { bool Derive(CExtPubKey& out, unsigned int nChild) const; }; +/** 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 diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index bda8acff15..06a6c239ef 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -202,7 +202,7 @@ public: void createPaymentServer(); #endif /// Create options model - void createOptionsModel(); + void createOptionsModel(bool resetSettings); /// Create main window void createWindow(const NetworkStyle *networkStyle); /// Create splash screen @@ -352,9 +352,9 @@ void BitcoinApplication::createPaymentServer() } #endif -void BitcoinApplication::createOptionsModel() +void BitcoinApplication::createOptionsModel(bool resetSettings) { - optionsModel = new OptionsModel(); + optionsModel = new OptionsModel(NULL, resetSettings); } void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) @@ -645,7 +645,7 @@ int main(int argc, char *argv[]) qInstallMessageHandler(DebugMessageHandler); #endif // Load GUI settings from QSettings - app.createOptionsModel(); + app.createOptionsModel(mapArgs.count("-resetguisettings") != 0); // Subscribe to global signals from core uiInterface.InitMessage.connect(InitMessage); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index d930d15953..6f9f6e90d6 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -44,6 +44,7 @@ #include <QProgressBar> #include <QProgressDialog> #include <QSettings> +#include <QShortcut> #include <QStackedWidget> #include <QStatusBar> #include <QStyle> @@ -364,6 +365,9 @@ void BitcoinGUI::createActions() connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); } #endif // ENABLE_WALLET + + new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this, SLOT(showDebugWindowActivateConsole())); + new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this, SLOT(showDebugWindow())); } void BitcoinGUI::createMenuBar() @@ -597,6 +601,12 @@ void BitcoinGUI::showDebugWindow() rpcConsole->activateWindow(); } +void BitcoinGUI::showDebugWindowActivateConsole() +{ + rpcConsole->setTabFocus(RPCConsole::TAB_CONSOLE); + showDebugWindow(); +} + void BitcoinGUI::showHelpMessageClicked() { helpMessageDialog->show(); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 717f2bd12d..2b98dabc56 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -198,6 +198,8 @@ private Q_SLOTS: void aboutClicked(); /** Show debug window */ void showDebugWindow(); + /** Show debug window and set focus to the console */ + void showDebugWindowActivateConsole(); /** Show help message dialog */ void showHelpMessageClicked(); #ifndef Q_OS_MAC diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 01e93d786a..2449046538 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -188,7 +188,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Activating best chain..."), QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), QT_TRANSLATE_NOOP("bitcoin-core", "Always query for peer addresses via DNS lookup (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Always relay transactions received from whitelisted peers (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat on startup"), +QT_TRANSLATE_NOOP("bitcoin-core", "Automatically create Tor hidden service (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"), @@ -295,6 +297,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay th QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."), QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port password (default: empty)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port to use if onion listening enabled (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must be positive"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"), @@ -317,6 +321,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoi QT_TRANSLATE_NOOP("bitcoin-core", "Wallet options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete; upgrade required!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Whether to operate in a blocks only mode (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"), QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."), QT_TRANSLATE_NOOP("bitcoin-core", "ZeroMQ notification options:"), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 0900a35cc4..566e8fa62d 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -13,6 +13,7 @@ #include "checkpoints.h" #include "clientversion.h" #include "net.h" +#include "txmempool.h" #include "ui_interface.h" #include "util.h" @@ -88,6 +89,16 @@ QDateTime ClientModel::getLastBlockDate() const return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network } +long ClientModel::getMempoolSize() const +{ + return mempool.size(); +} + +size_t ClientModel::getMempoolDynamicUsage() const +{ + return mempool.DynamicMemoryUsage(); +} + double ClientModel::getVerificationProgress() const { LOCK(cs_main); @@ -122,6 +133,7 @@ void ClientModel::updateTimer() Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate); } + Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage()); Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 627bdf862d..493a759331 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -51,6 +51,11 @@ public: int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; + //! Return number of transactions in the mempool + long getMempoolSize() const; + //! Return the dynamic memory usage of the mempool + size_t getMempoolDynamicUsage() const; + quint64 getTotalBytesRecv() const; quint64 getTotalBytesSent() const; @@ -89,6 +94,7 @@ private: Q_SIGNALS: void numConnectionsChanged(int count); void numBlocksChanged(int count, const QDateTime& blockDate); + void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 81b2597c3b..cbc41f3416 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -538,7 +538,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here // Priority - double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); + double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority) sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority); @@ -550,10 +550,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // Fee nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); - // Allow free? - double dPriorityNeeded = mempoolEstimatePriority; - if (dPriorityNeeded <= 0) - dPriorityNeeded = AllowFreeThreshold(); // not enough data, back to hard-coded + // Allow free? (require at least hard-coded threshold and default to that if no estimate) + double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold()); fAllowFree = (dPriority >= dPriorityNeeded); if (fSendFreeTransactions) @@ -649,8 +647,9 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) double dFeeVary; if (payTxFee.GetFeePerK() > 0) dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000; - else - dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateFee(nTxConfirmTarget).GetFeePerK()) / 1000; + else { + dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateSmartFee(nTxConfirmTarget).GetFeePerK()) / 1000; + } QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary); l3->setToolTip(toolTip4); @@ -686,7 +685,7 @@ void CoinControlDialog::updateView() QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); - double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); + double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); std::map<QString, std::vector<COutput> > mapCoins; model->listCoins(mapCoins); diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index eb02dd80ff..2471470363 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -23,7 +23,7 @@ <attribute name="title"> <string>&Information</string> </attribute> - <layout class="QGridLayout" name="gridLayout" columnstretch="0,1"> + <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0"> <property name="horizontalSpacing"> <number>12</number> </property> @@ -47,7 +47,7 @@ </property> </widget> </item> - <item row="1" column="1"> + <item row="1" column="1" colspan="2"> <widget class="QLabel" name="clientName"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -70,7 +70,7 @@ </property> </widget> </item> - <item row="2" column="1"> + <item row="2" column="1" colspan="2"> <widget class="QLabel" name="clientVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -96,7 +96,7 @@ </property> </widget> </item> - <item row="3" column="1"> + <item row="3" column="1" colspan="2"> <widget class="QLabel" name="clientUserAgent"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -122,7 +122,7 @@ </property> </widget> </item> - <item row="4" column="1"> + <item row="4" column="1" colspan="2"> <widget class="QLabel" name="openSSLVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -148,7 +148,7 @@ </property> </widget> </item> - <item row="5" column="1"> + <item row="5" column="1" colspan="2"> <widget class="QLabel" name="berkeleyDBVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -171,7 +171,7 @@ </property> </widget> </item> - <item row="6" column="1"> + <item row="6" column="1" colspan="2"> <widget class="QLabel" name="buildDate"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -194,7 +194,7 @@ </property> </widget> </item> - <item row="7" column="1"> + <item row="7" column="1" colspan="2"> <widget class="QLabel" name="startupTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -210,19 +210,6 @@ </property> </widget> </item> - <item row="8" column="0"> - <widget class="QLabel" name="label_11"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Network</string> - </property> - </widget> - </item> <item row="9" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> @@ -230,7 +217,7 @@ </property> </widget> </item> - <item row="9" column="1"> + <item row="9" column="1" colspan="2"> <widget class="QLabel" name="networkName"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -253,7 +240,7 @@ </property> </widget> </item> - <item row="10" column="1"> + <item row="10" column="1" colspan="2"> <widget class="QLabel" name="numberOfConnections"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -289,7 +276,7 @@ </property> </widget> </item> - <item row="12" column="1"> + <item row="12" column="1" colspan="2"> <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -306,13 +293,13 @@ </widget> </item> <item row="13" column="0"> - <widget class="QLabel" name="label_2"> + <widget class="QLabel" name="labelLastBlockTime"> <property name="text"> <string>Last block time</string> </property> </widget> </item> - <item row="13" column="1"> + <item row="13" column="1" colspan="2"> <widget class="QLabel" name="lastBlockTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -329,20 +316,43 @@ </widget> </item> <item row="14" column="0"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <widget class="QLabel" name="labelMempoolTitle"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> + <property name="text"> + <string>Memory Pool</string> </property> - </spacer> + </widget> </item> <item row="15" column="0"> - <widget class="QLabel" name="labelDebugLogfile"> + <widget class="QLabel" name="labelNumberOfTransactions"> + <property name="text"> + <string>Current number of transactions</string> + </property> + </widget> + </item> + <item row="15" column="1"> + <widget class="QLabel" name="mempoolNumberTxs"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="labelNetwork"> <property name="font"> <font> <weight>75</weight> @@ -350,24 +360,74 @@ </font> </property> <property name="text"> - <string>Debug log file</string> + <string>Network</string> </property> </widget> </item> <item row="16" column="0"> - <widget class="QPushButton" name="openDebugLogfileButton"> - <property name="toolTip"> - <string>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</string> + <widget class="QLabel" name="labelMemoryUsage"> + <property name="text"> + <string>Memory usage</string> + </property> + </widget> + </item> + <item row="16" column="1"> + <widget class="QLabel" name="mempoolSize"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> </property> <property name="text"> - <string>&Open</string> + <string>N/A</string> </property> - <property name="autoDefault"> - <bool>false</bool> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> </property> </widget> </item> - <item row="17" column="0"> + <item row="14" column="2" rowspan="3"> + <layout class="QVBoxLayout" name="verticalLayoutDebugButton"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>5</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="labelDebugLogfile"> + <property name="text"> + <string>Debug log file</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="openDebugLogfileButton"> + <property name="toolTip"> + <string>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</string> + </property> + <property name="text"> + <string>&Open</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + <item row="18" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 845459b76a..6dce9370d7 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -681,7 +681,10 @@ boost::filesystem::path static GetAutostartDir() boost::filesystem::path static GetAutostartFilePath() { - return GetAutostartDir() / "bitcoin.desktop"; + std::string chain = ChainNameFromCommandLine(); + if (chain == CBaseChainParams::MAIN) + return GetAutostartDir() / "bitcoin.desktop"; + return GetAutostartDir() / strprintf("bitcoin-%s.lnk", chain); } bool GetStartOnSystemStartup() diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index f70196140c..8a54f15791 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -1690,10 +1690,6 @@ <translation>تحذير</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>تحديث المحفظة للنسخة الاخيرة</translation> - </message> - <message> <source>This help message</source> <translation>رسالة المساعدة هذه</translation> </message> diff --git a/src/qt/locale/bitcoin_be_BY.ts b/src/qt/locale/bitcoin_be_BY.ts index 57dd9c3611..c1efc822ec 100644 --- a/src/qt/locale/bitcoin_be_BY.ts +++ b/src/qt/locale/bitcoin_be_BY.ts @@ -1424,10 +1424,6 @@ <translation>Опцыі гаманца:</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Імпартаванне блокаў з вонкавага blk000??.dat файла</translation> - </message> - <message> <source>Activating best chain...</source> <translation>Актывацыя лепшага ланцуга...</translation> </message> @@ -1480,14 +1476,6 @@ <translation>Выканаць каманду калі лепшы блок зменіцца (%s замяняецца на хэш блока)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Абнавіць гаманец на новы фармат</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Перасканаваць ланцуг блокаў дзеля пошуку адсутных транзакцый</translation> - </message> - <message> <source>Loading addresses...</source> <translation>Загружаем адрасы...</translation> </message> diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index d2db8a196c..8496a33481 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -168,6 +168,10 @@ <translation>Наистина ли желаете да шифрирате портфейла си?</translation> </message> <message> + <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Биткоин сега ще се затоври за да завърши процеса на криптиране. Запомнете, че криптирането на вашия портефейл не може напълно да предпази вашите монети от кражба чрез зловреден софтуер, инфектирал вашия компютър</translation> + </message> + <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> <translation>ВАЖНО: Всички стари запазвания, които сте направили на Вашият портфейл трябва да замените с запазване на новополучения, шифриран портфейл. От съображения за сигурност, предишните запазвания на нешифрирани портфейли ще станат неизползваеми веднага, щом започнете да използвате новият, шифриран портфейл.</translation> </message> @@ -414,6 +418,10 @@ <translation>%1 зад</translation> </message> <message> + <source>Last received block was generated %1 ago.</source> + <translation>Последния получен блок е генериран преди %1.</translation> + </message> + <message> <source>Transactions after this will not yet be visible.</source> <translation>Транзакции след това няма все още да бъдат видими.</translation> </message> @@ -636,6 +644,10 @@ <translation>нищо</translation> </message> <message> + <source>This label turns red if the transaction size is greater than 1000 bytes.</source> + <translation>Този етикет става червен, когато размера на транзакцията е по-голяма от 1000 бита.</translation> + </message> + <message> <source>yes</source> <translation>да</translation> </message> @@ -850,6 +862,10 @@ <translation>&Мрежа</translation> </message> <message> + <source>Automatically start Bitcoin Core after logging in to the system.</source> + <translation>Автоматично стартиране на Bitcoin Core след влизане в системата.</translation> + </message> + <message> <source>W&allet</source> <translation>По&ртфейл</translation> </message> @@ -1048,10 +1064,22 @@ <translation>Файл за справяне със заявки</translation> </message> <message> + <source>Payment request expired.</source> + <translation>Заявката за плащане е изтекла.</translation> + </message> + <message> + <source>Invalid payment request.</source> + <translation>Невалидна заявка за плащане.</translation> + </message> + <message> <source>Refund from %1</source> <translation>Възстановяване на сума от %1</translation> </message> <message> + <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source> + <translation>Заявката за плащане %1 е твърде голям (%2 байта, позволени %3 байта).</translation> + </message> + <message> <source>Error communicating with %1: %2</source> <translation>Грешка при комуникацията с %1: %2</translation> </message> @@ -1236,14 +1264,6 @@ <translation>Получени за последно</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Изпратени байтове</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Получени байтове</translation> - </message> - <message> <source>Ping Time</source> <translation>Време за отговор</translation> </message> @@ -1332,6 +1352,14 @@ <translation>Изходящи</translation> </message> <message> + <source>Yes</source> + <translation>Да</translation> + </message> + <message> + <source>No</source> + <translation>Не</translation> + </message> + <message> <source>Unknown</source> <translation>Неизвестен</translation> </message> @@ -1536,6 +1564,10 @@ <translation>за килобайт</translation> </message> <message> + <source>Hide</source> + <translation>Скрий</translation> + </message> + <message> <source>total at least</source> <translation>Крайна сума поне</translation> </message> @@ -1644,8 +1676,8 @@ <translation>Грешка при създаването на транзакция!</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Платете минималната такса от %1</translation> + <source>Payment request expired.</source> + <translation>Заявката за плащане е изтекла.</translation> </message> <message> <source>Warning: Invalid Bitcoin address</source> @@ -1926,6 +1958,10 @@ <translation>собствен адрес</translation> </message> <message> + <source>watch-only</source> + <translation>само гледане</translation> + </message> + <message> <source>label</source> <translation>име</translation> </message> @@ -2088,6 +2124,10 @@ <translation>Емитирани</translation> </message> <message> + <source>watch-only</source> + <translation>само гледане</translation> + </message> + <message> <source>(n/a)</source> <translation>(n/a)</translation> </message> @@ -2430,22 +2470,10 @@ <translation>Предупреждение</translation> </message> <message> - <source>on startup</source> - <translation>по време на стартирането</translation> - </message> - <message> <source>Password for JSON-RPC connections</source> <translation>Парола за JSON-RPC връзките</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Обновяване на портфейла до най-новия формат</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Повторно сканиране на блок-връзка за липсващи портфейлни транзакции</translation> - </message> - <message> <source>This help message</source> <translation>Това помощно съобщение</translation> </message> diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index b9aa40a7e3..dcbe4dc4cb 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -1494,14 +1494,6 @@ <translation>Darrera recepció</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes enviats</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes rebuts</translation> - </message> - <message> <source>Ping Time</source> <translation>Temps de ping</translation> </message> @@ -2010,10 +2002,6 @@ <translation><numerusform>Estimat per començar la confirmació en %n bloc.</numerusform><numerusform>Estimat per començar la confirmació en %n blocs.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Paga només la comissió mínima de %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>L'adreça de destinatari no és vàlida. Torneu-la a comprovar.</translation> </message> @@ -2860,10 +2848,6 @@ <translation><category> pot ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Intenta recuperar les claus privades d'un fitxer wallet.dat corrupte</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opcions de la creació de blocs:</translation> </message> @@ -2984,10 +2968,6 @@ <translation>Cal que reconstruïu la base de dades fent servir -reindex per canviar -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa blocs de un fitxer blk000??.dat extern</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permet les connexions JSON-RPC d'una font específica. Vàlid per a <ip> són una IP individual (p. ex., 1.2.3.4), una xarxa / màscara de xarxa (p. ex., 1.2.3.4/255.255.255.0) o una xarxa/CIDR (p. ex., 1.2.3.4/24). Es pot especificar aquesta opció moltes vegades</translation> </message> @@ -3236,10 +3216,6 @@ <translation>Se suprimeixen totes les transaccions del moneder...</translation> </message> <message> - <source>on startup</source> - <translation>a l'inici de l'aplicació</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>El fitxer wallet.data és corrupte. El rescat de les dades ha fallat</translation> </message> @@ -3252,14 +3228,6 @@ <translation>Executa l'ordre quan el millor bloc canviï (%s en cmd es reemplaça per un resum de bloc)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualitza el moneder a l'últim format</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Reescaneja la cadena de blocs en les transaccions de moneder perdudes</translation> - </message> - <message> <source>This help message</source> <translation>Aquest misatge d'ajuda</translation> </message> diff --git a/src/qt/locale/bitcoin_ca@valencia.ts b/src/qt/locale/bitcoin_ca@valencia.ts index edb14dedba..e717f53d47 100644 --- a/src/qt/locale/bitcoin_ca@valencia.ts +++ b/src/qt/locale/bitcoin_ca@valencia.ts @@ -1490,14 +1490,6 @@ <translation>Darrera recepció</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes enviats</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes rebuts</translation> - </message> - <message> <source>Ping Time</source> <translation>Temps de ping</translation> </message> @@ -2006,10 +1998,6 @@ <translation><numerusform>Estimat per començar la confirmació en %n bloc.</numerusform><numerusform>Estimat per començar la confirmació en %n blocs.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Paga només la comissió mínima de %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>L'adreça de destinatari no és vàlida. Torneu-la a comprovar.</translation> </message> @@ -2856,10 +2844,6 @@ <translation><category> pot ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Intenta recuperar les claus privades d'un fitxer wallet.dat corrupte</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opcions de la creació de blocs:</translation> </message> @@ -2980,10 +2964,6 @@ <translation>Cal que reconstruïu la base de dades fent servir -reindex per canviar -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa blocs d'un fitxer blk000??.dat extern</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permet les connexions JSON-RPC d'una font específica. Vàlid per a <ip> són una IP individual (p. ex., 1.2.3.4), una xarxa / màscara de xarxa (p. ex., 1.2.3.4/255.255.255.0) o una xarxa/CIDR (p. ex., 1.2.3.4/24). Es pot especificar esta opció moltes vegades</translation> </message> @@ -3232,10 +3212,6 @@ <translation>Se suprimeixen totes les transaccions del moneder...</translation> </message> <message> - <source>on startup</source> - <translation>a l'inici de l'aplicació</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>El fitxer wallet.data és corrupte. El rescat de les dades ha fallat</translation> </message> @@ -3248,14 +3224,6 @@ <translation>Executa l'orde quan el millor bloc canvie (%s en cmd es reemplaça per un resum de bloc)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualitza el moneder a l'últim format</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Reescaneja la cadena de blocs en les transaccions de moneder perdudes</translation> - </message> - <message> <source>This help message</source> <translation>Este misatge d'ajuda</translation> </message> diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index f10a41163e..331ad835f6 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -1494,14 +1494,6 @@ <translation>Darrera recepció</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes enviats</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes rebuts</translation> - </message> - <message> <source>Ping Time</source> <translation>Temps de ping</translation> </message> @@ -2010,10 +2002,6 @@ <translation><numerusform>Estimat per començar la confirmació en %n bloc.</numerusform><numerusform>Estimat per començar la confirmació en %n blocs.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Paga només la comissió mínima de %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>L'adreça de destinatari no és vàlida. Torneu-la a comprovar.</translation> </message> @@ -2860,10 +2848,6 @@ <translation><category> pot ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Intenta recuperar les claus privades d'un fitxer wallet.dat corrupte</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opcions de la creació de blocs:</translation> </message> @@ -2984,10 +2968,6 @@ <translation>Cal que reconstruïu la base de dades fent servir -reindex per canviar -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa blocs de un fitxer blk000??.dat extern</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permet les connexions JSON-RPC d'una font específica. Vàlid per a <ip> són una IP individual (p. ex., 1.2.3.4), una xarxa / màscara de xarxa (p. ex., 1.2.3.4/255.255.255.0) o una xarxa/CIDR (p. ex., 1.2.3.4/24). Es pot especificar aquesta opció moltes vegades</translation> </message> @@ -3236,10 +3216,6 @@ <translation>Se suprimeixen totes les transaccions del moneder...</translation> </message> <message> - <source>on startup</source> - <translation>a l'inici de l'aplicació</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>El fitxer wallet.data és corrupte. El rescat de les dades ha fallat</translation> </message> @@ -3252,14 +3228,6 @@ <translation>Executa l'ordre quan el millor bloc canviï (%s en cmd es reemplaça per un resum de bloc)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualitza el moneder a l'últim format</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Reescaneja la cadena de blocs en les transaccions de moneder perdudes</translation> - </message> - <message> <source>This help message</source> <translation>Aquest misatge d'ajuda</translation> </message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index c8c3368543..a2232dbe8e 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -1494,14 +1494,6 @@ <translation>Poslední příjem</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bajtů odesláno</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bajtů přijato</translation> - </message> - <message> <source>Ping Time</source> <translation>Odezva</translation> </message> @@ -2010,10 +2002,6 @@ <translation><numerusform>Potvrzování by podle odhadu mělo začít během %n bloku.</numerusform><numerusform>Potvrzování by podle odhadu mělo začít během %n bloků.</numerusform><numerusform>Potvrzování by podle odhadu mělo začít během %n bloků.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Zaplatit pouze minimální poplatek %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Adresa příjemce je neplatná – překontroluj ji prosím.</translation> </message> @@ -2860,10 +2848,6 @@ <translation><category> může být:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Pokusit se zachránit soukromé klíče z poškozeného souboru wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Možnosti vytváření bloku:</translation> </message> @@ -2984,10 +2968,6 @@ <translation>Je třeba přestavět databázi použitím -reindex, aby bylo možné změnit -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importovat bloky z externího souboru blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Povolit JSON-RPC spojení ze specifikovaného zdroje. Platnou hodnotou <ip> je jednotlivá IP adresa (např. 1.2.3.4), síť/maska (např. 1.2.3.4/255.255.255.0) nebo síť/CIDR (např. 1.2.3.4/24). Tuto volbu lze použít i vícekrát</translation> </message> @@ -3236,10 +3216,6 @@ <translation>Vymazat všechny transakce z peněženky...</translation> </message> <message> - <source>on startup</source> - <translation>při startu</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>Soubor wallet.dat je poškozen, jeho záchrana se nezdařila</translation> </message> @@ -3252,14 +3228,6 @@ <translation>Spustit příkaz, když se změní nejlepší blok (%s se v příkazu nahradí hashem bloku)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Převést peněženku na nejnovější formát</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Přeskenovat řetězec bloků na chybějící transakce tvé pěněženky</translation> - </message> - <message> <source>This help message</source> <translation>Tato nápověda</translation> </message> diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 46d9826045..93594dcb05 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -1129,7 +1129,7 @@ </message> <message> <source>&Unit to show amounts in:</source> - <translation>&Enhed at vise beløb i:</translation> + <translation>&Enhed, som beløb vises i:</translation> </message> <message> <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> @@ -1141,7 +1141,7 @@ </message> <message> <source>&OK</source> - <translation>&O.k.</translation> + <translation>&Ok</translation> </message> <message> <source>&Cancel</source> @@ -1200,7 +1200,7 @@ </message> <message> <source>Pending:</source> - <translation>Uafgjort:</translation> + <translation>Afventende:</translation> </message> <message> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> @@ -1546,14 +1546,6 @@ <translation>Seneste modtagelse</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Byte sendt</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Byte modtaget</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping-tid</translation> </message> @@ -2066,6 +2058,10 @@ <translation>Kopiér byttepenge</translation> </message> <message> + <source>Total Amount %1</source> + <translation>Totalbeløb %1</translation> + </message> + <message> <source>or</source> <translation>eller</translation> </message> @@ -2097,19 +2093,15 @@ <source>Payment request expired.</source> <translation>Betalingsanmodning er udløbet.</translation> </message> + <message> + <source>Pay only the required fee of %1</source> + <translation>Betal kun det påkrævede gebyr på %1</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation><numerusform>Bekræftelse estimeres til at begynde inden for %n blok.</numerusform><numerusform>Bekræftelse estimeres til at begynde inden for %n blokke.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Betal kun det minimale gebyr på %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Totalbeløb %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Modtageradressen er ikke gyldig. Tjek venligst igen.</translation> </message> @@ -2888,10 +2880,6 @@ <translation>Acceptér kommandolinje- og JSON-RPC-kommandoer</translation> </message> <message> - <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)</source> - <translation>Gebyrer (i %s/kB) mindre end dette opfattes som nul-gebyr under videresendelse (standard: %s)</translation> - </message> - <message> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation>Hvis <category> ikke angives eller hvis <category> = 1, udskriv al fejlretningsinformation.</translation> </message> @@ -3016,10 +3004,6 @@ <translation><kategori> kan være:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Forsøg at genskabe private nøgler fra ødelagt wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Blokoprettelsestilvalg:</translation> </message> @@ -3176,10 +3160,6 @@ <translation>Du er nødt til at genopbygge databasen ved hjælp af -reindex for at ændre -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importerer blokke fra ekstern blk000??.dat fil</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Tillad JSON-RPC-forbindelser fra angivet kilde. Gyldig for <ip> er en enkelt IP (fx 1.2.3.4), et netværk/netmaske (fx 1.2.3.4/255.255.255.0) eller et netværk/CIDR (fx 1.2.3.4/24). Dette tilvalg kan angives flere gange</translation> </message> @@ -3212,6 +3192,10 @@ <translation>Udfør kommando, når en relevant alarm modtages eller vi ser en virkelig lang udsplitning (%s i cmd erstattes af besked)</translation> </message> <message> + <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source> + <translation>Gebyrer (i %s/kB) mindre end dette opfattes som intet gebyr for videresendelse, mining og oprettelse af transaktioner (standard: %s)</translation> + </message> + <message> <source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source> <translation>Hvis paytxfee ikke er sat, inkluderes nok gebyr til at transaktioner begynder at blive bekræftet ingen for gennemsnitligt n blokke (standard: %u)</translation> </message> @@ -3268,6 +3252,10 @@ <translation>Aktiverer bedste kæde…</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet.dat on startup</source> + <translation>Forsøg at genskabe private nøgler fra en ødelagt wallet.dat under opstart</translation> + </message> + <message> <source>Cannot resolve -whitebind address: '%s'</source> <translation>Kan ikke løse -whitebind adresse: "%s"</translation> </message> @@ -3292,6 +3280,10 @@ <translation>Fejl under læsning fra database; lukker ned.</translation> </message> <message> + <source>Imports blocks from external blk000??.dat file on startup</source> + <translation>Importerer blokeringer fra ekstern blk000??.dat-fil under opstart</translation> + </message> + <message> <source>Information</source> <translation>Information</translation> </message> @@ -3348,6 +3340,10 @@ <translation>Reducerer -maxconnections fra %d til %d på grund af systembegrænsninger.</translation> </message> <message> + <source>Rescan the block chain for missing wallet transactions on startup</source> + <translation>Genindlæs blokkæden efter manglende tegnebogstransaktioner under opstart</translation> + </message> + <message> <source>Send trace/debug info to console instead of debug.log file</source> <translation>Send sporings-/fejlsøgningsinformation til konsollen i stedet for debug.log filen</translation> </message> @@ -3416,6 +3412,10 @@ <translation>Ikke i stand til at tildele til %s på denne computer (bind returnerede fejl %s)</translation> </message> <message> + <source>Upgrade wallet to latest format on startup</source> + <translation>Opgradér tegnebog til seneste format under opstart</translation> + </message> + <message> <source>Username for JSON-RPC connections</source> <translation>Brugernavn til JSON-RPC-forbindelser</translation> </message> @@ -3436,10 +3436,6 @@ <translation>ZeroMQ-notifikationsindstillinger:</translation> </message> <message> - <source>on startup</source> - <translation>under opstart</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat ødelagt, redning af data mislykkedes</translation> </message> @@ -3452,14 +3448,6 @@ <translation>Udfør kommando, når den bedste blok ændres (%s i kommandoen erstattes med blokhash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Opgrader tegnebog til seneste format</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Gennemsøg blokkæden for manglende tegnebogstransaktioner</translation> - </message> - <message> <source>This help message</source> <translation>Denne hjælpebesked</translation> </message> diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index a25fb7458d..42776f2c8b 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -1518,14 +1518,6 @@ <translation>Letzter Empfang</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Übertragene Byte</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Empfangene Byte</translation> - </message> - <message> <source>Ping Time</source> <translation>Pingzeit</translation> </message> @@ -2022,6 +2014,10 @@ <translation>Wechselgeld kopieren</translation> </message> <message> + <source>Total Amount %1</source> + <translation>Gesamtbetrag %1</translation> + </message> + <message> <source>or</source> <translation>oder</translation> </message> @@ -2058,14 +2054,6 @@ <translation><numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Block.</numerusform><numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Nur die minimale Gebühr in Höhe von %1 zahlen</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Gesamtbetrag %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen.</translation> </message> @@ -2924,10 +2912,6 @@ <translation><category> kann sein:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Versuchen, private Schlüssel aus einer beschädigten wallet.dat wiederherzustellen</translation> - </message> - <message> <source>Block creation options:</source> <translation>Blockerzeugungsoptionen:</translation> </message> @@ -3048,10 +3032,6 @@ <translation>Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um -txindex zu verändern</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Blöcke aus externer Datei blk000??.dat importieren</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>JSON-RPC-Verbindungen von der angegeben Quelle erlauben. Gültig für <ip> ist eine einzelne IP-Adresse (z.B. 1.2.3.4), ein Netzwerk bzw. eine Netzmaske (z.B. 1.2.3.4/255.255.255.0), oder die CIDR-Notation (z.B. 1.2.3.4/24). Kann mehrmals angegeben werden.</translation> </message> @@ -3304,10 +3284,6 @@ <translation>ZeroMQ-Benachrichtigungsoptionen:</translation> </message> <message> - <source>on startup</source> - <translation>beim Starten</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat beschädigt, Datenrettung fehlgeschlagen</translation> </message> @@ -3320,14 +3296,6 @@ <translation>Befehl ausführen wenn der beste Block wechselt (%s im Befehl wird durch den Hash des Blocks ersetzt)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Wallet auf das neueste Format aktualisieren</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Blockkette erneut nach fehlenden Wallet-Transaktionen durchsuchen</translation> - </message> - <message> <source>This help message</source> <translation>Dieser Hilfetext</translation> </message> diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 1f33a497ee..d9f8dee5ef 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -1389,14 +1389,6 @@ <translation>Τελευταία λήψη</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Σταλθέντα bytes</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Ληφθέντα bytes</translation> - </message> - <message> <source>Ping Time</source> <translation>Χρόνος καθυστέρησης</translation> </message> @@ -2555,10 +2547,6 @@ <translation>(προεπιλογή: 1)</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Προσπάθεια για ανακτησει ιδιωτικων κλειδιων από ενα διεφθαρμένο αρχειο wallet.dat </translation> - </message> - <message> <source>Block creation options:</source> <translation>Αποκλεισμός επιλογων δημιουργίας: </translation> </message> @@ -2639,10 +2627,6 @@ <translation>Επιλογές πορτοφολιού:</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Εισαγωγή μπλοκ από εξωτερικό αρχείο blk000?.dat</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> <translation>Αδυναμία κλειδώματος του φακέλου δεδομένων %s. Πιθανώς το Bitcoin να είναι ήδη ενεργό.</translation> </message> @@ -2747,10 +2731,6 @@ <translation>Μεταφορά όλων των συναλλαγών απο το πορτοφόλι</translation> </message> <message> - <source>on startup</source> - <translation>κατά την εκκίνηση</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>Το αρχειο wallet.dat ειναι διεφθαρμένο, η διάσωση απέτυχε</translation> </message> @@ -2763,14 +2743,6 @@ <translation>Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Αναβάθμισε το πορτοφόλι στην τελευταία έκδοση</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Επανέλεγχος της αλυσίδας μπλοκ για απούσες συναλλαγές</translation> - </message> - <message> <source>This help message</source> <translation>Αυτό το κείμενο βοήθειας</translation> </message> diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 1a607a2233..21df732520 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -299,17 +299,17 @@ <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+324"/> + <location filename="../bitcoingui.cpp" line="+325"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+353"/> + <location line="+362"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-429"/> + <location line="-438"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -389,12 +389,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+180"/> + <location line="+183"/> <source>Bitcoin Core client</source> <translation type="unfinished"></translation> </message> <message> - <location line="+163"/> + <location line="+169"/> <source>Importing blocks from disk...</source> <translation>Importing blocks from disk...</translation> </message> @@ -404,7 +404,7 @@ <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="-427"/> + <location line="-436"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -434,12 +434,12 @@ <translation>&Verify message...</translation> </message> <message> - <location line="+450"/> + <location line="+459"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-660"/> + <location line="-669"/> <source>Wallet</source> <translation>Wallet</translation> </message> @@ -484,7 +484,7 @@ <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> </message> <message> - <location line="+53"/> + <location line="+56"/> <source>&File</source> <translation>&File</translation> </message> @@ -504,7 +504,7 @@ <translation>Tabs toolbar</translation> </message> <message> - <location line="-311"/> + <location line="-314"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -549,7 +549,7 @@ <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+320"/> + <location line="+329"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -3316,7 +3316,7 @@ <context> <name>TransactionTableModel</name> <message> - <location filename="../transactiontablemodel.cpp" line="+233"/> + <location filename="../transactiontablemodel.cpp" line="+246"/> <source>Date</source> <translation>Date</translation> </message> @@ -3419,7 +3419,7 @@ <translation>(n/a)</translation> </message> <message> - <location line="+215"/> + <location line="+217"/> <source>Transaction status. Hover over this field to show number of confirmations.</source> <translation>Transaction status. Hover over this field to show number of confirmations.</translation> </message> @@ -3544,6 +3544,11 @@ </message> <message> <location line="+1"/> + <source>Copy raw transaction</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Edit label</source> <translation>Edit label</translation> </message> @@ -3553,7 +3558,7 @@ <translation>Show transaction details</translation> </message> <message> - <location line="+179"/> + <location line="+181"/> <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> @@ -3618,7 +3623,7 @@ <translation>ID</translation> </message> <message> - <location line="+116"/> + <location line="+121"/> <source>Range:</source> <translation>Range:</translation> </message> @@ -3698,7 +3703,7 @@ <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+258"/> + <location filename="../bitcoinstrings.cpp" line="+260"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -3718,7 +3723,7 @@ <translation>Specify your own public address</translation> </message> <message> - <location line="-107"/> + <location line="-109"/> <source>Accept command line and JSON-RPC commands</source> <translation>Accept command line and JSON-RPC commands</translation> </message> @@ -3758,7 +3763,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+110"/> + <location line="+112"/> <source>Error: A fatal internal error occurred, see debug.log for details</source> <translation type="unfinished"></translation> </message> @@ -3778,12 +3783,12 @@ <translation>Run in the background as a daemon and accept commands</translation> </message> <message> - <location line="+32"/> + <location line="+34"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-119"/> + <location line="-123"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> @@ -3878,7 +3883,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+11"/> <source>Block creation options:</source> <translation>Block creation options:</translation> </message> @@ -4018,7 +4023,7 @@ <translation>Specify wallet file (within data directory)</translation> </message> <message> - <location line="+16"/> + <location line="+18"/> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation type="unfinished"></translation> </message> @@ -4068,12 +4073,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>You need to rebuild the database using -reindex to change -txindex</source> <translation>You need to rebuild the database using -reindex to change -txindex</translation> </message> <message> - <location line="-299"/> + <location line="-304"/> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation type="unfinished"></translation> </message> @@ -4189,10 +4194,20 @@ </message> <message> <location line="+4"/> + <source>Always relay transactions received from whitelisted peers (default: %d)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Attempt to recover private keys from a corrupt wallet.dat on startup</source> <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> + <source>Automatically create Tor hidden service (default: %d)</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+5"/> <source>Cannot resolve -whitebind address: '%s'</source> <translation type="unfinished"></translation> @@ -4359,6 +4374,16 @@ </message> <message> <location line="+2"/> + <source>Tor control port password (default: empty)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Tor control port to use if onion listening enabled (default: %s)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Transaction amount too small</source> <translation>Transaction amount too small</translation> </message> @@ -4408,7 +4433,12 @@ <translation>Warning</translation> </message> <message> - <location line="+3"/> + <location line="+2"/> + <source>Whether to operate in a blocks only mode (default: %u)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Zapping all transactions from wallet...</source> <translation type="unfinished"></translation> </message> @@ -4423,27 +4453,27 @@ <translation>wallet.dat corrupt, salvage failed</translation> </message> <message> - <location line="-64"/> + <location line="-67"/> <source>Password for JSON-RPC connections</source> <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-196"/> + <location line="-198"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+232"/> + <location line="+234"/> <source>This help message</source> <translation>This help message</translation> </message> <message> - <location line="-106"/> + <location line="-108"/> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+58"/> + <location line="+60"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> @@ -4453,7 +4483,7 @@ <translation>Error loading wallet.dat: Wallet corrupted</translation> </message> <message> - <location line="-205"/> + <location line="-207"/> <source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source> <translation type="unfinished"></translation> </message> @@ -4528,7 +4558,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> + <location line="+28"/> <source>Error loading wallet.dat</source> <translation>Error loading wallet.dat</translation> </message> @@ -4638,12 +4668,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+10"/> <source>Unknown network specified in -onlynet: '%s'</source> <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-111"/> + <location line="-113"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -4668,12 +4698,12 @@ <translation>Loading block index...</translation> </message> <message> - <location line="-60"/> + <location line="-62"/> <source>Add a node to connect to and attempt to keep the connection open</source> <translation>Add a node to connect to and attempt to keep the connection open</translation> </message> <message> - <location line="+61"/> + <location line="+63"/> <source>Loading wallet...</source> <translation>Loading wallet...</translation> </message> diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index b969075e0a..4bd64f68d1 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -1124,10 +1124,6 @@ <translation>Aktuala nombro de blokoj</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bajtoj Senditaj:</translation> - </message> - <message> <source>Last block time</source> <translation>Horo de la lasta bloko</translation> </message> @@ -2134,10 +2130,6 @@ <translation><category> povas esti:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Provo ripari privatajn ŝlosilojn el difektita wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Blok-kreaj agordaĵoj:</translation> </message> @@ -2214,10 +2206,6 @@ <translation>Vi devas rekontrui la datumbazon kun -reindex por ŝanĝi -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importas blokojn el ekstera dosiero blk000??.dat</translation> - </message> - <message> <source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source> <translation>Plenumi komandon kiam rilata alerto riceviĝas, aŭ kiam ni vidas tre longan forkon (%s en cms anstataŭiĝas per mesaĝo)</translation> </message> @@ -2298,14 +2286,6 @@ <translation>Plenumi komandon kiam plej bona bloko ŝanĝiĝas (%s en cmd anstataŭiĝas per bloka haketaĵo)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Ĝisdatigi monujon al plej lasta formato</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Reskani la blokĉenon por mankantaj monujaj transakcioj</translation> - </message> - <message> <source>This help message</source> <translation>Tiu ĉi helpmesaĝo</translation> </message> diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 91b0d79e30..ec8261173b 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -218,7 +218,15 @@ </context> <context> <name>BanTableModel</name> - </context> + <message> + <source>IP/Netmask</source> + <translation>IP/Máscara</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Bloqueado Hasta</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -1068,6 +1076,18 @@ <translation>Puerto del servidor proxy (ej. 9050)</translation> </message> <message> + <source>IPv4</source> + <translation>IPv4</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6</translation> + </message> + <message> + <source>Tor</source> + <translation>Tor</translation> + </message> + <message> <source>&Window</source> <translation>&Ventana</translation> </message> @@ -1454,6 +1474,10 @@ <translation>&Pares</translation> </message> <message> + <source>Banned peers</source> + <translation>Peers Bloqueados</translation> + </message> + <message> <source>Select a peer to view detailed information.</source> <translation>Seleccionar un par para ver su información detallada.</translation> </message> @@ -1466,6 +1490,18 @@ <translation>Versión</translation> </message> <message> + <source>Starting Block</source> + <translation>Importando bloques...</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Sincronizar Cabeceras</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Bloques Sincronizados</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1490,14 +1526,6 @@ <translation>Ultima recepción</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes enviados</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes recibidos</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping</translation> </message> @@ -1550,6 +1578,26 @@ <translation>Borrar consola</translation> </message> <message> + <source>&Disconnect Node</source> + <translation>Nodo &Desconectado</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &hora</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &día</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &semana</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &año</translation> + </message> + <message> <source>Welcome to the Bitcoin Core RPC console.</source> <translation>Bienvenido a la consola RPC de Bitcoin Core.</translation> </message> @@ -1578,6 +1626,10 @@ <translation>%1 GB</translation> </message> <message> + <source>(node id: %1)</source> + <translation>(nodo: %1)</translation> + </message> + <message> <source>via %1</source> <translation>via %1</translation> </message> @@ -1997,17 +2049,13 @@ <source>Payment request expired.</source> <translation>Solicitud de pago caducada.</translation> </message> - <message numerus="yes"> - <source>Estimated to begin confirmation within %n block(s).</source> - <translation><numerusform>Estimado para empezar la confirmación dentro de %n bloque.</numerusform><numerusform>Estimado para empezar la confirmación dentro de %n bloques.</numerusform></translation> - </message> <message> - <source>Pay only the minimum fee of %1</source> + <source>Pay only the required fee of %1</source> <translation>Paga sólo la cuota mínima de %1</translation> </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Monto Total %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Estimado para empezar la confirmación dentro de %n bloque.</numerusform><numerusform>Estimado para empezar la confirmación dentro de %n bloques.</numerusform></translation> </message> <message> <source>The recipient address is not valid. Please recheck.</source> @@ -2794,6 +2842,10 @@ <translation>Un error interno fatal ocurrió, ver debug.log para detalles</translation> </message> <message> + <source>Fee (in %s/kB) to add to transactions you send (default: %s)</source> + <translation>Comisión (en %s/KB) para agregar a las transacciones que envíe (por defecto: %s)</translation> + </message> + <message> <source>Pruning blockstore...</source> <translation>Poda blockstore ...</translation> </message> @@ -2867,10 +2919,6 @@ <translation><category> puede ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Intento de recuperar claves privadas de un wallet.dat corrupto</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opciones de creación de bloques:</translation> </message> @@ -2991,10 +3039,6 @@ <translation>Usted necesita reconstruir la base de datos utilizando -reindex para cambiar -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa los bloques desde un archivo blk000??.dat externo</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permitir conexiones JSON-RPC de origen especificado. Válido para son una sola IP (por ejemplo 1.2.3.4), una red/máscara de red (por ejemplo 1.2.3.4/255.255.255.0) o una red/CIDR (e.g. 1.2.3.4/24). Esta opción se puede especificar varias veces</translation> </message> @@ -3079,6 +3123,10 @@ <translation>Activando la mejor cadena...</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet.dat on startup</source> + <translation>Intento de recuperar claves privadas de un wallet.dat corrupto</translation> + </message> + <message> <source>Cannot resolve -whitebind address: '%s'</source> <translation>No se puede resolver -whitebind address: '%s'</translation> </message> @@ -3103,6 +3151,10 @@ <translation>Error al leer la base de datos, cerrando.</translation> </message> <message> + <source>Imports blocks from external blk000??.dat file on startup</source> + <translation>Importa los bloques desde un archivo externo blk000?.dat</translation> + </message> + <message> <source>Information</source> <translation>Información</translation> </message> @@ -3155,6 +3207,10 @@ <translation>Recibir y mostrar alertas de red P2P (default: %u)</translation> </message> <message> + <source>Rescan the block chain for missing wallet transactions on startup</source> + <translation>Rescanea la cadena de bloques para transacciones perdidas de la cartera</translation> + </message> + <message> <source>Send trace/debug info to console instead of debug.log file</source> <translation>Enviar información de trazas/depuración a la consola en lugar de al archivo debug.log</translation> </message> @@ -3223,6 +3279,10 @@ <translation>No es posible conectar con %s en este sistema (bind ha dado el error %s)</translation> </message> <message> + <source>Upgrade wallet to latest format on startup</source> + <translation>Actualizar el monedero al último formato</translation> + </message> + <message> <source>Username for JSON-RPC connections</source> <translation>Nombre de usuario para las conexiones JSON-RPC </translation> @@ -3240,10 +3300,6 @@ <translation>Eliminando todas las transacciones del monedero...</translation> </message> <message> - <source>on startup</source> - <translation>al iniciar</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrupto. Ha fallado la recuperación.</translation> </message> @@ -3257,14 +3313,6 @@ <translation>Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualizar el monedero al último formato</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Volver a examinar la cadena de bloques en busca de transacciones del monedero perdidas</translation> - </message> - <message> <source>This help message</source> <translation>Este mensaje de ayuda </translation> diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index e388b5a0cf..df17411ab5 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -1305,10 +1305,6 @@ <translation>Atención: Poco espacio en el disco duro</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importar bloques desde el archivo externo blk000??.dat </translation> - </message> - <message> <source>Information</source> <translation>Información</translation> </message> @@ -1340,15 +1336,6 @@ </translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualizar billetera al formato actual</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Rescanea la cadena de bloques para transacciones perdidas de la cartera -</translation> - </message> - <message> <source>This help message</source> <translation>Este mensaje de ayuda </translation> @@ -1375,6 +1362,14 @@ <translation>Dirección -proxy invalida: '%s'</translation> </message> <message> + <source>Cannot resolve -bind address: '%s'</source> + <translation>No se pudo resolver la dirección fija: '%s'</translation> + </message> + <message> + <source>Cannot resolve -externalip address: '%s'</source> + <translation>No se pudo resolver la dirección ip: '%s'</translation> + </message> + <message> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Cantidad inválida para -paytxfee=<amount>: '%s'</translation> </message> @@ -1395,6 +1390,14 @@ <translation>Cargando cartera...</translation> </message> <message> + <source>Cannot downgrade wallet</source> + <translation>No es posible desactualizar la billetera</translation> + </message> + <message> + <source>Cannot write default address</source> + <translation>No se pudo escribir la dirección por defecto</translation> + </message> + <message> <source>Rescanning...</source> <translation>Rescaneando...</translation> </message> diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts index 7a7a6e33f5..c67d642de7 100644 --- a/src/qt/locale/bitcoin_es_DO.ts +++ b/src/qt/locale/bitcoin_es_DO.ts @@ -2137,10 +2137,6 @@ <translation><category> puede ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Intento de recuperar claves privadas de un wallet.dat corrupto</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opciones de creación de bloques:</translation> </message> @@ -2217,10 +2213,6 @@ <translation>Usted necesita reconstruir la base de datos utilizando -reindex para cambiar -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa los bloques desde un archivo blk000??.dat externo</translation> - </message> - <message> <source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source> <translation>Ejecutar un comando cuando se reciba una alerta importante o cuando veamos un fork demasiado largo (%s en cmd se reemplazará por el mensaje)</translation> </message> @@ -2298,10 +2290,6 @@ <translation>Aviso</translation> </message> <message> - <source>on startup</source> - <translation>al iniciar</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrupto. Ha fallado la recuperación.</translation> </message> @@ -2315,14 +2303,6 @@ <translation>Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualizar el monedero al último formato</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Volver a examinar la cadena de bloques en busca de transacciones del monedero perdidas</translation> - </message> - <message> <source>This help message</source> <translation>Este mensaje de ayuda </translation> diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index d2f98a9876..9279834af3 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -1680,10 +1680,6 @@ <translation>Hoiatus: toimus wallet.dat faili andmete päästmine! Originaal wallet.dat nimetati kaustas %s ümber wallet.{ajatempel}.bak'iks, jäägi või tehingute ebakõlade puhul tuleks teha backup'ist taastamine.</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Püüa vigasest wallet.dat failist taastada turvavõtmed</translation> - </message> - <message> <source>Block creation options:</source> <translation>Blokeeri loomise valikud:</translation> </message> @@ -1736,10 +1732,6 @@ <translation>Rahakoti valikud:</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Impordi blokid välisest blk000??.dat failist</translation> - </message> - <message> <source>Information</source> <translation>Informatsioon</translation> </message> @@ -1796,10 +1788,6 @@ <translation>Hoiatus</translation> </message> <message> - <source>on startup</source> - <translation>käivitamisel</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat fail on katki, päästmine ebaõnnestus</translation> </message> @@ -1812,14 +1800,6 @@ <translation>Käivita käsklus, kui parim plokk muutub (käskluse %s asendatakse ploki hash'iga)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Uuenda rahakott uusimasse vormingusse</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Otsi ploki jadast rahakoti kadunud tehinguid</translation> - </message> - <message> <source>This help message</source> <translation>Käesolev abitekst</translation> </message> diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 05f8fc6251..fb4e25dfb8 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -1616,10 +1616,18 @@ <translation>تولید شده ولی قبول نشده</translation> </message> <message> + <source>Offline</source> + <translation>آفلاین</translation> + </message> + <message> <source>Label</source> <translation>برچسب</translation> </message> <message> + <source>Unconfirmed</source> + <translation>تایید نشده</translation> + </message> + <message> <source>Received with</source> <translation>دریافتشده با</translation> </message> @@ -1966,14 +1974,6 @@ <translation>زمانی که بهترین بلاک تغییر کرد، دستور را اجرا کن (%s در cmd با block hash جایگزین شده است)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>wallet را به جدیدترین فرمت روزآمد کنید</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>اسکان مجدد زنجیر بلوکها برای گم والت معامله</translation> - </message> - <message> <source>This help message</source> <translation>پیام کمکی</translation> </message> diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index 6c16fc6f1f..fd9de2e049 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -1024,14 +1024,6 @@ <translation>دستور را وقتی بهترین بلاک تغییر کرد اجرا کن (%s در دستور توسط block hash جایگزین شده است)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>wallet را به جدیدترین نسخه روزآمد کنید</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>زنجیره بلاک را برای تراکنش جا افتاده در WALLET دوباره اسکن کنید</translation> - </message> - <message> <source>This help message</source> <translation>این پیام راهنما</translation> </message> diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index 8cf6d01653..7026fff1f5 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -1482,14 +1482,6 @@ <translation>Viimeisin vastaanotettu</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Tavua lähetetty</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Tavua vastaanotettu</translation> - </message> - <message> <source>Ping Time</source> <translation>Vasteaika</translation> </message> @@ -1982,10 +1974,6 @@ <translation>Maksupyyntö on vanhentunut.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Maksa vain vähimmäiskulu %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Vastaanottajan osoite ei ole kelvollinen. Tarkistathan uudelleen.</translation> </message> @@ -2792,10 +2780,6 @@ <translation><category> voi olla:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Yritetään palauttaa privaattiavaimia korruptoituneesta wallet.dat -lompakkotiedostosta</translation> - </message> - <message> <source>Block creation options:</source> <translation>Lohkon luonnin asetukset:</translation> </message> @@ -2912,10 +2896,6 @@ <translation>Sinun tulee uudelleenrakentaa tietokanta käyttäen -reindex vaihtaen -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Tuodaan lohkoja ulkoisesta blk000??.dat tiedostosta</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> <translation>Ei voida lukita data-hakemistoa %s. Bitcoin Core on luultavasti jo käynnissä.</translation> </message> @@ -3060,10 +3040,6 @@ <translation>Tyhjennetään kaikki rahansiirrot lompakosta....</translation> </message> <message> - <source>on startup</source> - <translation>käynnistyksessä</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat -lompakkotiedosto korruptoitunut, korjaaminen epäonnistui</translation> </message> @@ -3076,14 +3052,6 @@ <translation>Suorita käsky kun paras lohko muuttuu (%s cmd on vaihdettu block hashin kanssa)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Päivitä lompakko uusimpaan formaattiin</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Skannaa uudelleen lohkoketju lompakon puuttuvien rahasiirtojen vuoksi</translation> - </message> - <message> <source>This help message</source> <translation>Tämä ohjeviesti</translation> </message> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index a2799f99fc..97dccdac06 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -1486,14 +1486,6 @@ <translation>Dernière réception</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Octets envoyés</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Octets reçus</translation> - </message> - <message> <source>Ping Time</source> <translation>Temps de ping</translation> </message> @@ -2002,14 +1994,6 @@ <translation><numerusform>Il est estimé que la confirmation commencera dans %n bloc.</numerusform><numerusform>Il est estimé que la confirmation commencera dans %n blocs.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Payer seulement les frais minimum de %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Montant total %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>L'adresse du destinataire est invalide. Veuillez la vérifier.</translation> </message> @@ -2860,10 +2844,6 @@ <translation><category> peut être :</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Tenter de récupérer les clefs privées d'un wallet.dat corrompu</translation> - </message> - <message> <source>Block creation options:</source> <translation>Options de création de bloc :</translation> </message> @@ -2984,10 +2964,6 @@ <translation>Vous devez reconstruire la base de données en utilisant -reindex afin de modifier -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importe des blocs depuis un fichier blk000??.dat externe</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permettre les connexions JSON-RPC de sources spécifiques. Valide pour <ip> qui sont une IP simple (p. ex. 1.2.3.4), un réseau/masque réseau (p. ex. 1.2.3.4/255.255.255.0) ou un réseau/CIDR (p. ex. 1.2.3.4/24). Cette option peut être être spécifiée plusieurs fois</translation> </message> @@ -3236,10 +3212,6 @@ <translation>Supprimer toutes les transactions du portefeuille...</translation> </message> <message> - <source>on startup</source> - <translation>au démarrage</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrompu, la récupération a échoué</translation> </message> @@ -3252,14 +3224,6 @@ <translation>Exécuter la commande lorsque le meilleur bloc change (%s dans cmd est remplacé par le hachage du bloc)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Mettre à niveau le portefeuille vers le format le plus récent</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Réanalyser la chaîne de blocs pour les transactions de portefeuille manquantes</translation> - </message> - <message> <source>This help message</source> <translation>Ce message d'aide</translation> </message> diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts index 3edaef7e16..79f0d46d3f 100644 --- a/src/qt/locale/bitcoin_gl.ts +++ b/src/qt/locale/bitcoin_gl.ts @@ -1966,10 +1966,6 @@ <translation><categoría> pode ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Tentar recuperar claves privadas dende un wallet.dat corrupto</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opcións de creación de bloque:</translation> </message> @@ -2042,10 +2038,6 @@ <translation>Precisas reconstruír a base de datos empregando -reindex para cambiar -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa bloques dende arquivos blk000??.dat externos</translation> - </message> - <message> <source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source> <translation>Executar comando cando se recibe unha alerta relevante ou vemos un fork realmente longo (%s no cmd é substituído pola mensaxe)</translation> </message> @@ -2122,14 +2114,6 @@ <translation>Executar comando cando o mellor bloque cambie (%s no comando é sustituído polo hash do bloque)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualizar moedeiro ao formato máis recente</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Rescanear transaccións ausentes na cadea de bloques</translation> - </message> - <message> <source>This help message</source> <translation>Esta mensaxe de axuda</translation> </message> diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 8e985e9f16..048b268200 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -1332,14 +1332,6 @@ <translation>קבלה אחרונה</translation> </message> <message> - <source>Bytes Sent</source> - <translation>בתים שנשלחו</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>בתים שהתקבלו</translation> - </message> - <message> <source>Ping Time</source> <translation>זמן המענה</translation> </message> @@ -2534,10 +2526,6 @@ <translation><קטגוריה> יכולה להיות:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>נסה לשחזר מפתחות פרטיים מקובץ wallet.dat מושחת.</translation> - </message> - <message> <source>Block creation options:</source> <translation>אפשרויות יצירת מקטע:</translation> </message> @@ -2642,10 +2630,6 @@ <translation>עליך לבנות מחדש את מסד הנתונים תוך שימוש ב־-reindex על מנת לשנות את -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>מיובאים מקטעים מקובצי blk000??.dat חיצוניים</translation> - </message> - <message> <source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source> <translation>הרץ פקודה כאשר ההתראה הרלוונטית מתקבלת או כשאנחנו עדים לפיצול ארוך מאוד (%s בשורת הפקודה יוחלף ע"י ההודעה)</translation> </message> @@ -2770,10 +2754,6 @@ <translation>אזהרה</translation> </message> <message> - <source>on startup</source> - <translation>עם ההפעלה</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>קובץ wallet.dat מושחת, החילוץ נכשל</translation> </message> @@ -2786,14 +2766,6 @@ <translation>יש לבצע פקודה זו כשהמקטע הטוב ביותר משתנה (%s בפקודה יוחלף בגיבוב המקטע)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>שדרוג הארנק למבנה העדכני</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>יש לסרוק מחדש את שרשרת המקטעים למציאת העברות חסרות בארנק</translation> - </message> - <message> <source>This help message</source> <translation>הודעת העזרה הזו</translation> </message> diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index 80371dfaf7..aa28ecf24f 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -1058,14 +1058,6 @@ <translation>Trajanje veze</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bajtova poslano</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bajtova primljeno</translation> - </message> - <message> <source>Last block time</source> <translation>Posljednje vrijeme bloka</translation> </message> @@ -1784,10 +1776,6 @@ <translation>Pogreška: Nema dovoljno prostora na disku!</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Uvozi blokove sa vanjske blk000??.dat datoteke</translation> - </message> - <message> <source>Information</source> <translation>Informacija</translation> </message> @@ -1816,14 +1804,6 @@ <translation>Izvršite naredbu kada se najbolji blok promjeni (%s u cmd je zamjenjen sa block hash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Nadogradite novčanik u posljednji format.</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Ponovno pretraži lanac blokova za transakcije koje nedostaju</translation> - </message> - <message> <source>This help message</source> <translation>Ova poruka za pomoć</translation> </message> diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index 6722854589..27cfedc728 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -1318,14 +1318,6 @@ <translation>Legutóbbi fogadás</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Küldött bájtok</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Fogadott bájtok</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping idő</translation> </message> @@ -2468,15 +2460,6 @@ <translation>Parancs, amit akkor hajt végre, amikor a legjobb blokk megváltozik (%s a cmd-ban lecserélődik a blokk hash-re)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>A Tárca frissítése a legfrissebb formátumra</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Blokklánc újraszkennelése hiányzó tárca-tranzakciók után -</translation> - </message> - <message> <source>This help message</source> <translation>Ez a súgó-üzenet </translation> diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts index e2caa6d867..22ce3efecb 100644 --- a/src/qt/locale/bitcoin_id_ID.ts +++ b/src/qt/locale/bitcoin_id_ID.ts @@ -2,6 +2,10 @@ <context> <name>AddressBookPage</name> <message> + <source>Right-click to edit address or label</source> + <translation>Klik-kanan untuk mengubah alamat atau label</translation> + </message> + <message> <source>Create a new address</source> <translation>Buat alamat baru</translation> </message> @@ -454,6 +458,36 @@ <translation>Menyusul...</translation> </message> <message> + <source>Date: %1 +</source> + <translation>Tanggal: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Jumlah: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Tipe: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Label: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Alamat: %1 +</translation> + </message> + <message> <source>Sent transaction</source> <translation>Transaksi terkirim</translation> </message> @@ -480,6 +514,10 @@ <context> <name>CoinControlDialog</name> <message> + <source>Coin Selection</source> + <translation>Pemilihan Koin</translation> + </message> + <message> <source>Quantity:</source> <translation>Kuantitas:</translation> </message> @@ -898,6 +936,18 @@ <translation>Port proxy (cth. 9050)</translation> </message> <message> + <source>IPv4</source> + <translation>IPv4</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6</translation> + </message> + <message> + <source>Tor</source> + <translation>Tor</translation> + </message> + <message> <source>&Window</source> <translation>&Jendela</translation> </message> @@ -958,6 +1008,10 @@ <translation>Restart klien diperlukan untuk mengaktifkan perubahan.</translation> </message> <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Klien akan dimatikan, apakah anda hendak melanjutkan?</translation> + </message> + <message> <source>This change would require a client restart.</source> <translation>Perubahan ini akan memerlukan restart klien</translation> </message> @@ -1001,6 +1055,10 @@ <translation>Saldo ditambang yang masih terlalu muda</translation> </message> <message> + <source>Balances</source> + <translation>Saldo:</translation> + </message> + <message> <source>Total:</source> <translation>Jumlah:</translation> </message> @@ -1020,6 +1078,10 @@ <translation>Alamat pembayaran salah %1</translation> </message> <message> + <source>Payment request rejected</source> + <translation>Permintaan pembayaran ditolak</translation> + </message> + <message> <source>Requested payment amount of %1 is too small (considered dust).</source> <translation>Nilai pembayaran %1 yang diminta oleh Anda terlalu sedikit (dianggap debu).</translation> </message> @@ -1028,6 +1090,10 @@ <translation>Gagalan permintaan pembayaran</translation> </message> <message> + <source>Payment request expired.</source> + <translation>Permintaan pembayaran telah kadaluarsa</translation> + </message> + <message> <source>Refund from %1</source> <translation>Pembayaran kembali dari %1</translation> </message> @@ -1050,6 +1116,10 @@ </context> <context> <name>PeerTableModel</name> + <message> + <source>User Agent</source> + <translation>Agen Pengguna</translation> + </message> </context> <context> <name>QObject</name> @@ -1058,6 +1128,10 @@ <translation>Nilai</translation> </message> <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Masukkan alamat Bitcoin (contoh %1)</translation> + </message> + <message> <source>%1 h</source> <translation>%1 Jam</translation> </message> @@ -1144,6 +1218,24 @@ <translation>Jumlah blok terkini</translation> </message> <message> + <source>Sent</source> + <translation>Terkirim</translation> + </message> + <message> + <source>Version</source> + <translation>Versi</translation> + </message> + <message> + <source>User Agent</source> + <translation>Agen Pengguna + +</translation> + </message> + <message> + <source>Services</source> + <translation>Layanan</translation> + </message> + <message> <source>Last block time</source> <translation>Waktu blok terakhir</translation> </message> @@ -1188,6 +1280,26 @@ <translation>Bersihkan konsol</translation> </message> <message> + <source>1 &hour</source> + <translation>1 &jam</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &hari</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &minggu</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &tahun</translation> + </message> + <message> + <source>Welcome to the Bitcoin Core RPC console.</source> + <translation>Selamat datang di konsol RPC Bitcoin.</translation> + </message> + <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> <translation>Gunakan panah keatas dan kebawah untuk menampilkan sejarah, dan <b>Ctrl-L</b> untuk bersihkan layar.</translation> </message> @@ -1211,7 +1323,19 @@ <source>%1 GB</source> <translation>%1 GB</translation> </message> - </context> + <message> + <source>Yes</source> + <translation>Ya</translation> + </message> + <message> + <source>No</source> + <translation>Tidak</translation> + </message> + <message> + <source>Unknown</source> + <translation>Tidak diketahui</translation> + </message> +</context> <context> <name>ReceiveCoinsDialog</name> <message> @@ -1432,6 +1556,22 @@ <translation>Alamat uang kembali yang kustom</translation> </message> <message> + <source>Recommended:</source> + <translation>Disarankan</translation> + </message> + <message> + <source>Confirmation time:</source> + <translation>Waktu konfirmasi:</translation> + </message> + <message> + <source>normal</source> + <translation>normal</translation> + </message> + <message> + <source>fast</source> + <translation>cepat</translation> + </message> + <message> <source>Send to multiple recipients at once</source> <translation>Kirim ke beberapa penerima sekaligus</translation> </message> @@ -1492,6 +1632,10 @@ <translation>Salin uang kembali</translation> </message> <message> + <source>Total Amount %1</source> + <translation>Jumlah Total %1</translation> + </message> + <message> <source>or</source> <translation>atau</translation> </message> @@ -1516,6 +1660,14 @@ <translation>Gagal: Transaksi ditolak. Ini mungkin terjadi jika beberapa dari koin dalam dompet Anda telah digunakan, seperti ketika Anda menggunakan salinan wallet.dat dan beberapa koin telah dibelanjakan dalam salinan tersebut tetapi disini tidak tertandai sebagai terpakai.</translation> </message> <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>Biaya yang lebih tinggi dari %1 dianggap biaya tak masuk akal.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Permintaan pembayaran telah kadaluarsa</translation> + </message> + <message> <source>Warning: Invalid Bitcoin address</source> <translation>Awas: Alamat Bitcoin tidak sah</translation> </message> @@ -2214,10 +2366,6 @@ <translation>(pengaturan awal: 1)</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Coba memulihkan kunci-kunci pribadi dari wallet.dat yang rusak</translation> - </message> - <message> <source>Block creation options:</source> <translation>Pilihan pembuatan blok:</translation> </message> @@ -2306,14 +2454,14 @@ <translation>Harus membangun ulang database menggunakan -reindex supaya mengubah -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Impor blok dari eksternal berkas blk000???.dat</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> <translation>Tidak bisa mengunci data directory %s. Kemungkinan Bitcoin Core sudah mulai.</translation> </message> <message> + <source>Connect through SOCKS5 proxy</source> + <translation>Hubungkan melalui proxy SOCKS5</translation> + </message> + <message> <source>Information</source> <translation>Informasi</translation> </message> @@ -2390,14 +2538,6 @@ <translation>Menjalankan perintah ketika perubahan blok terbaik (%s dalam cmd digantikan oleh hash blok)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Perbarui dompet ke format terbaru</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Pindai ulang rantai-blok untuk transaksi dompet yang hilang</translation> - </message> - <message> <source>This help message</source> <translation>Pesan bantuan ini</translation> </message> diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index b613bc888e..7a2b7bd843 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -1487,14 +1487,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Ultima Ricezione</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Byte Inviati</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Byte Ricevuti</translation> - </message> - <message> <source>Ping Time</source> <translation>Tempo di Ping</translation> </message> @@ -1999,10 +1991,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Richiesta di pagamento scaduta.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Paga solamente la commissione minima di %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>L'indirizzo del beneficiario non è valido. Si prega di ricontrollare.</translation> </message> @@ -2853,10 +2841,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Valori possibili per <category>:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Tenta di recuperare le chiavi private da un wallet.dat corrotto</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opzioni creazione blocco:</translation> </message> @@ -2977,10 +2961,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>È necessario ricostruire il database usando -reindex per cambiare -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importa blocchi da un file blk000??.dat esterno</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permette connessioni JSON-RPC dall'origine specificata. I valori validi per <ip> sono un singolo IP (ad es. 1.2.3.4), una network/netmask (ad es. 1.2.3.4/255.255.255.0) oppure una network/CIDR (ad es. 1.2.3.4/24). Questa opzione può essere specificata più volte.</translation> </message> @@ -3229,10 +3209,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Eliminazione dal portamonete di tutte le transazioni...</translation> </message> <message> - <source>on startup</source> - <translation>all'avvio</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrotto, recupero fallito</translation> </message> @@ -3245,14 +3221,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Esegue un comando quando il miglior blocco cambia (%s nel cmd è sostituito dall'hash del blocco)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Aggiorna il wallet all'ultimo formato</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Ripete la scansione della block chain per individuare le transazioni che mancano dal portamonete</translation> - </message> - <message> <source>This help message</source> <translation>Questo messaggio di aiuto</translation> </message> diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index 5770fe9a02..140ed2445b 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -1550,14 +1550,6 @@ <translation>最終受信</translation> </message> <message> - <source>Bytes Sent</source> - <translation>送信済バイト数</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>受信済バイト数</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping時間</translation> </message> @@ -2070,6 +2062,10 @@ <translation>釣り銭をコピー</translation> </message> <message> + <source>Total Amount %1</source> + <translation>合計: %1</translation> + </message> + <message> <source>or</source> <translation>または</translation> </message> @@ -2101,19 +2097,15 @@ <source>Payment request expired.</source> <translation>支払いリクエストの期限が切れました。</translation> </message> + <message> + <source>Pay only the required fee of %1</source> + <translation>要求手数料 %1 のみを支払う</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation><numerusform>%n ブロック以内に検証が開始されると予想されます。</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>最小手数料 %1 のみを支払う</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>総額 %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>受取アドレスが不正です。再チェックしてください。</translation> </message> @@ -2892,10 +2884,6 @@ <translation>コマンドラインと JSON-RPC コマンドを許可</translation> </message> <message> - <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)</source> - <translation>中継の際、この値未満の手数料 (%s/kB単位) はゼロであるとみなす (デフォルト: %s)</translation> - </message> - <message> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation><category> が与えられなかった場合や <category> = 1 の場合には、すべてのデバッグ情報が出力されます。</translation> </message> @@ -3020,10 +3008,6 @@ <translation><category>は以下の値を指定できます:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>壊れた wallet.dat から秘密鍵を復旧することを試す</translation> - </message> - <message> <source>Block creation options:</source> <translation>ブロック作成オプション:</translation> </message> @@ -3181,10 +3165,6 @@ <translation>-txindex を変更するには -reindex を使用してデータベースを再構築する必要があります</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>外部の blk000??.dat ファイルからブロックをインポート</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>指定したアクセス元からのJSON-RPC接続を許可する。有効な<ip>は、単一のIP (例 1.2.3.4)、ネットワーク/ネットマスク (1.2.3.4/255.255.255.0)、またはネットワーク/CIDR (1.2.3.4/24)です。このオプションは複数回指定できます。</translation> </message> @@ -3217,6 +3197,10 @@ <translation>関連のアラートをもらってもすごく長いのフォークを見てもコマンドを実行 (コマンドの中にあるの%sはメッセージから置き換えさせる)</translation> </message> <message> + <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source> + <translation>トランザクションの中継、採掘および作成の際には、この値未満の手数料 (%s/kB単位) はゼロであるとみなす (デフォルト: %s)</translation> + </message> + <message> <source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source> <translation>paytxfee が設定されていなかった場合、平均して n ブロック以内にトランザクションが検証され始めるのに十分な手数料を含める (初期値: %u)</translation> </message> @@ -3273,6 +3257,10 @@ <translation>最優良のチェインを有効化しています...</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet.dat on startup</source> + <translation>起動時に壊れた wallet.dat から秘密鍵を復旧することを試す</translation> + </message> + <message> <source>Cannot resolve -whitebind address: '%s'</source> <translation>-whitebind アドレス '%s' を解決できません</translation> </message> @@ -3297,6 +3285,10 @@ <translation>データベースの読み込みエラー。シャットダウンします。</translation> </message> <message> + <source>Imports blocks from external blk000??.dat file on startup</source> + <translation>起動時に外部の blk000??.dat ファイルからブロックをインポート</translation> + </message> + <message> <source>Information</source> <translation>情報</translation> </message> @@ -3353,6 +3345,10 @@ <translation>システム上の制約から、-maxconnections を %d から %d に削減しました。</translation> </message> <message> + <source>Rescan the block chain for missing wallet transactions on startup</source> + <translation>起動時に失ったウォレットの取引のブロック チェーンを再スキャン</translation> + </message> + <message> <source>Send trace/debug info to console instead of debug.log file</source> <translation>トレース/デバッグ情報を debug.log ファイルの代わりにコンソールへ送る</translation> </message> @@ -3421,6 +3417,10 @@ <translation>このコンピュータの %s にバインドすることができません (バインドが返したエラーは %s)</translation> </message> <message> + <source>Upgrade wallet to latest format on startup</source> + <translation>起動時にウォレットを最新のフォーマットにアップグレード</translation> + </message> + <message> <source>Username for JSON-RPC connections</source> <translation>JSON-RPC 接続のユーザー名</translation> </message> @@ -3441,10 +3441,6 @@ <translation>ZeroMQ通知オプション:</translation> </message> <message> - <source>on startup</source> - <translation>起動時</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat が壊れ、復旧に失敗しました</translation> </message> @@ -3457,14 +3453,6 @@ <translation>最良のブロックに変更する際にコマンドを実行 (cmd の %s はブロック ハッシュに置換される)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>ウォレットを最新のフォーマットにアップグレード</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>失ったウォレットの取引のブロック チェーンを再スキャン</translation> - </message> - <message> <source>This help message</source> <translation>このヘルプ メッセージ</translation> </message> diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts index 6e5db78589..e8f5286697 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -2234,10 +2234,6 @@ <translation><category> შეიძლება იყოს:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>პირადი გასაღებების აღდგენის მცდელობა wallet.dat-იდან</translation> - </message> - <message> <source>Block creation options:</source> <translation>ბლოკის შექმნის ოპციები:</translation> </message> @@ -2322,10 +2318,6 @@ <translation>საჭიროა ბაზის ხელახალი აგება, გამოიყენეთ -reindex რათა შეცვალოთ -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>ბლოკების იმპორტი გარე blk000??.dat ფაილიდან</translation> - </message> - <message> <source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source> <translation>ბრძანების შესრულება შესაბამისი უწყების მიღებისას ან როცა შეინიშნება საგრძნობი გახლეჩა (cmd-ში %s შეიცვლება მესიჯით)</translation> </message> @@ -2410,14 +2402,6 @@ <translation>კომანდის შესრულება უკეთესი ბლოკის გამოჩენისას (%s კომანდაში ჩანაცვლდება ბლოკის ჰეშით)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>საფულის ფორმატის განახლება</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>ბლოკების ჯაჭვის გადამოწმება საფულეში გამორჩენილ ტრანსაქციებზე</translation> - </message> - <message> <source>This help message</source> <translation>ეს ტექსტი</translation> </message> diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts index 653ea40882..8243618f11 100644 --- a/src/qt/locale/bitcoin_ko_KR.ts +++ b/src/qt/locale/bitcoin_ko_KR.ts @@ -2304,10 +2304,6 @@ <translation>(기본값: 1)</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>손상된 wallet.dat에서 개인키 복원을 시도합니다</translation> - </message> - <message> <source>Block creation options:</source> <translation>블록 생성 옵션:</translation> </message> @@ -2404,10 +2400,6 @@ <translation>-txindex를 바꾸기 위해서는 -reindex를 사용해서 데이터베이스를 재구성해야 합니다. </translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>외부 blk000??.dat 파일에서 블록을 가져옵니다.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> <translation>데이터 디렉토리 %s에 락을 걸 수 없었습니다. 비트코인 코어가 이미 실행 중인 것으로 보입니다.</translation> </message> @@ -2496,10 +2488,6 @@ <translation>지갑의 모든거래내역 건너뛰기...</translation> </message> <message> - <source>on startup</source> - <translation>구동 중</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat 파일이 손상되었고 복구가 실패하였습니다.</translation> </message> @@ -2512,14 +2500,6 @@ <translation>최고의 블럭이 변하면 명령을 실행(cmd 에 있는 %s 는 블럭 해시에 의해 대체되어 짐)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>지갑을 최근 형식으로 개선하시오</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>누락된 지갑 송금에 대한 블록 체인 다시 검색</translation> - </message> - <message> <source>This help message</source> <translation>도움말 메시지입니다</translation> </message> diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index b1e14fb859..b297a35d4b 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -1410,10 +1410,6 @@ <translation>Monitio: wallet.data corrupta, data salvata! Originalis wallet.dat salvata ut wallet.{timestamp}.bak in %s; si pendendum tuum vel transactiones pravae sunt, oportet ab conservato restituere.</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Conare recipere claves privatas de corrupto wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Optiones creandi frustorum:</translation> </message> @@ -1466,10 +1462,6 @@ <translation>Verificante cassidilem...</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importat frusta ab externa plica blk000??.dat</translation> - </message> - <message> <source>Information</source> <translation>Informatio</translation> </message> @@ -1538,14 +1530,6 @@ <translation>Pelle mandatum quando optissimum frustum mutat (%s in mandato substituitur ab hash frusti)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Progredere cassidile ad formam recentissimam</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Iterum perlege catenam frustorum propter absentes cassidilis transactiones</translation> - </message> - <message> <source>This help message</source> <translation>Hic nuntius auxilii</translation> </message> diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index d91c183884..7820977375 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -872,14 +872,6 @@ <translation>Versija</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Nusiųsti baitai</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Gauti baitai</translation> - </message> - <message> <source>Last block time</source> <translation>Paskutinio bloko laikas</translation> </message> @@ -1662,14 +1654,6 @@ <translation>Slaptažodis JSON-RPC sujungimams</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Atnaujinti piniginę į naujausią formatą</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Ieškoti prarastų piniginės sandorių blokų grandinėje</translation> - </message> - <message> <source>This help message</source> <translation>Pagelbos žinutė</translation> </message> diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index db2eabaf78..fa7abdf2ab 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -2122,10 +2122,6 @@ <translation><category> var būt:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Mēģināt atgūt privātās atslēgas no bojāta wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Bloka izveidošanas iestatījumi:</translation> </message> @@ -2166,10 +2162,6 @@ <translation>Maciņa iespējas:</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importēt blokus no ārējās blk000??.dat datnes</translation> - </message> - <message> <source>Information</source> <translation>Informācija</translation> </message> @@ -2218,10 +2210,6 @@ <translation>Brīdinājums</translation> </message> <message> - <source>on startup</source> - <translation>startēšanas laikā</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat ir bojāts, glābšana neizdevās</translation> </message> @@ -2234,14 +2222,6 @@ <translation>Izpildīt komandu, kad labāk atbilstošais bloks izmainās (%s cmd aizvieto ar bloka hešu)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Atjaunot maciņa formātu uz jaunāko</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Atkārtoti skanēt bloku virkni, meklējot trūkstošās maciņa transakcijas</translation> - </message> - <message> <source>This help message</source> <translation>Šis palīdzības paziņojums</translation> </message> diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts index a44d3b6fb3..d1a5976224 100644 --- a/src/qt/locale/bitcoin_mn.ts +++ b/src/qt/locale/bitcoin_mn.ts @@ -1034,10 +1034,6 @@ <translation>Түрүйвчийн сонголтууд:</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Түрүйвчийг хамгийн сүүлийн үеийн форматруу шинэчлэх</translation> - </message> - <message> <source>Loading addresses...</source> <translation>Хаягуудыг ачааллаж байна...</translation> </message> diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 9f5344ecab..6cded5e135 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -1550,14 +1550,6 @@ <translation>Siste Mottatte</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Byte Sendt</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Byte Mottatt</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping-tid</translation> </message> @@ -2070,6 +2062,10 @@ <translation>Kopier veksel</translation> </message> <message> + <source>Total Amount %1</source> + <translation>Totalt Beløp %1</translation> + </message> + <message> <source>or</source> <translation>eller</translation> </message> @@ -2101,19 +2097,15 @@ <source>Payment request expired.</source> <translation>Betalingsetterspørringen har utløpt.</translation> </message> + <message> + <source>Pay only the required fee of %1</source> + <translation>Betal kun påkrevd gebyr på %1</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation><numerusform>Anslått til å begynne bekreftelse innen %n blokk.</numerusform><numerusform>Anslått til å begynne bekreftelse innen %n blokker.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Betal kun minimumsgebyret på %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Totalt Beløp %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Mottakeradressen er ikke gyldig. Vennligst kontroller på nytt.</translation> </message> @@ -2892,10 +2884,6 @@ <translation>Ta imot kommandolinje- og JSON-RPC-kommandoer</translation> </message> <message> - <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)</source> - <translation>Gebyrer (i %s/kB) mindre enn dette vil anses som gebyrfrie (for videresending) (standard: %s)</translation> - </message> - <message> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation>Hvis <category> ikke er oppgitt eller hvis <category> = 1, ta ut all informasjon for feilsøking.</translation> </message> @@ -3016,10 +3004,6 @@ <translation><category> kan være:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Forsøk å berge private nøkler fra en korrupt wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Valg for opprettelse av blokker:</translation> </message> @@ -3176,10 +3160,6 @@ <translation>Du må gjenoppbygge databasen med å bruke -reindex for å endre -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importerer blokker fra ekstern fil blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Tillat JSON-RPC-tilkoblinger fra angitt kilde. Gyldig for <ip> er en enkelt IP (f. eks. 1.2.3.4), et nettverk/nettmaske (f. eks. 1.2.3.4/255.255.255.0) eller et nettverk/CIDR (f. eks. 1.2.3.4/24). Dette alternativet kan angis flere ganger</translation> </message> @@ -3212,6 +3192,10 @@ <translation>Utfør kommando når et relevant varsel er mottatt eller vi ser en veldig lang gaffel (%s i kommando er erstattet med melding)</translation> </message> <message> + <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source> + <translation>Gebyrer (i %s/kB) mindre enn dette anses som null gebyr for videresending, graving og laging av transaksjoner (standardverdi: %s)</translation> + </message> + <message> <source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source> <translation>Hvis paytxfee ikke er angitt, inkluderer da nok i gebyr til at transaksjoner gjennomsnittligt bekreftes innen n blokker (standardverdi: %u)</translation> </message> @@ -3268,6 +3252,10 @@ <translation>Aktiverer beste kjede...</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet.dat on startup</source> + <translation>Forsøk å berge private nøkler fra en korrupt wallet.dat ved oppstart</translation> + </message> + <message> <source>Cannot resolve -whitebind address: '%s'</source> <translation>Kan ikke løse -whitebind-adresse: '%s'</translation> </message> @@ -3292,6 +3280,10 @@ <translation>Feil ved lesing fra database, stenger ned.</translation> </message> <message> + <source>Imports blocks from external blk000??.dat file on startup</source> + <translation>Importerer blokker fra ekstern fil blk000??.dat ved oppstart</translation> + </message> + <message> <source>Information</source> <translation>Informasjon</translation> </message> @@ -3348,6 +3340,10 @@ <translation>Reduserer -maxconnections fra %d til %d, pga. systembegrensninger.</translation> </message> <message> + <source>Rescan the block chain for missing wallet transactions on startup</source> + <translation>Se gjennom blokkjeden etter manglende lommeboktransaksjoner ved oppstart</translation> + </message> + <message> <source>Send trace/debug info to console instead of debug.log file</source> <translation>Send spor-/feilsøkingsinformasjon til konsollen istedenfor filen debug.log</translation> </message> @@ -3416,6 +3412,10 @@ <translation>Kan ikke binde til %s på denne datamaskinen (binding returnerte feilen %s)</translation> </message> <message> + <source>Upgrade wallet to latest format on startup</source> + <translation>Oppgrader lommebok til nyeste format ved oppstart</translation> + </message> + <message> <source>Username for JSON-RPC connections</source> <translation>Brukernavn for JSON-RPC forbindelser</translation> </message> @@ -3436,10 +3436,6 @@ <translation>Valg for ZeroMQ-meldinger:</translation> </message> <message> - <source>on startup</source> - <translation>ved oppstart</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat korrupt, bergning feilet</translation> </message> @@ -3452,14 +3448,6 @@ <translation>Utfør kommando når beste blokk endrer seg (%s i kommandoen erstattes med blokkens hash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Oppgrader lommebok til nyeste format</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Se gjennom blokkjeden etter manglende lommeboktransaksjoner</translation> - </message> - <message> <source>This help message</source> <translation>Denne hjelpemeldingen</translation> </message> diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index cbb1dc0fe3..c307f0ab6a 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -1490,14 +1490,6 @@ <translation>Laatst ontvangen</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes Verzonden</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes Ontvangen</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping Tijd</translation> </message> @@ -1994,10 +1986,6 @@ <translation>Betalingsverzoek verlopen.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Betaal alleen de minimale transactiekosten van %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Het adres van de ontvanger is niet geldig. Gelieve opnieuw te controleren..</translation> </message> @@ -2840,10 +2828,6 @@ <translation><category> kan zijn:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Poog de geheime sleutels uit een corrupt wallet.dat bestand terug te halen</translation> - </message> - <message> <source>Block creation options:</source> <translation>Blokcreatie-opties:</translation> </message> @@ -2956,10 +2940,6 @@ <translation>Om -txindex te kunnen veranderen dient u de database opnieuw te bouwen met gebruik van -reindex.</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importeert blokken van extern blk000??.dat bestand</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Sta JSON-RPC verbindingen toe vanuit een gespecificeerde bron. Geldig voor <ip> zijn een enkel IP (bijv. 1.2.3.4), een netwerk/netmask (bijv. 1.2.3.4/255.255.255.0) of een netwerk/CIDR (bijv. 1.2.3.4/24). Deze optie kan meerdere keren gespecificeerd worden.</translation> </message> @@ -3189,10 +3169,6 @@ <translation>Bezig met het zappen van alle transacties van de portemonnee...</translation> </message> <message> - <source>on startup</source> - <translation>bij opstarten</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrupt, veiligstellen mislukt</translation> </message> @@ -3205,14 +3181,6 @@ <translation>Voer commando uit zodra het beste blok verandert (%s in cmd wordt vervangen door blockhash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Vernieuw portemonnee naar nieuwste versie</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Doorzoek de blokketen op ontbrekende portemonnee-transacties</translation> - </message> - <message> <source>This help message</source> <translation>Dit helpbericht</translation> </message> diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts index f5e74261f0..893ae43c55 100644 --- a/src/qt/locale/bitcoin_pam.ts +++ b/src/qt/locale/bitcoin_pam.ts @@ -1406,14 +1406,6 @@ <translation>I-execute ing command istung mialilan ya ing best block (%s in cmd is replaced by block hash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>I-upgrade ing wallet king pekabayung porma</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>I-scan pasibayu ing block chain para kareng mauaualang transaksion</translation> - </message> - <message> <source>This help message</source> <translation>Ining saup a mensayi</translation> </message> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index ed828539ee..228e02a5ee 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -1490,14 +1490,6 @@ <translation>Ostatnio odebrano</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bajtów wysłano</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bajtów pobrano</translation> - </message> - <message> <source>Ping Time</source> <translation>Czas odpowiedzi</translation> </message> @@ -1994,14 +1986,6 @@ <translation><numerusform>Przybliżony czas zatwierdzenia: %n bloków.</numerusform><numerusform>Przybliżony czas zatwierdzenia: %n bloków.</numerusform><numerusform>Przybliżony czas zatwierdzenia: %n bloków.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Płac tylko minimalna opłatę %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Całkowita kwota %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Adres odbiorcy jest nieprawidłowy, proszę sprawić ponownie.</translation> </message> @@ -2852,10 +2836,6 @@ <translation><category> mogą być:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Próbuj odzyskać klucze prywatne z uszkodzonego wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opcje tworzenia bloku:</translation> </message> @@ -2976,10 +2956,6 @@ <translation>Musisz przebudować bazę używając parametru -reindex aby zmienić -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importuj bloki z zewnętrznego pliku blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Pozwól na połączenia JSON-RPC z podanego źródła. Jako <ip> prawidłowe jest pojedyncze IP (np. 1.2.3.4), podsieć/maska (np. 1.2.3.4/255.255.255.0) lub sieć/CIDR (np. 1.2.3.4/24). Opcja ta może być użyta wiele razy.</translation> </message> @@ -3216,10 +3192,6 @@ <translation>Usuwam wszystkie transakcje z portfela...</translation> </message> <message> - <source>on startup</source> - <translation>podczas uruchamiania</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat uszkodzony, odtworzenie się nie powiodło</translation> </message> @@ -3232,14 +3204,6 @@ <translation>Wykonaj polecenie kiedy najlepszy blok ulegnie zmianie (%s w komendzie zastanie zastąpione przez hash bloku)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Zaktualizuj portfel do najnowszego formatu.</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Przeskanuj łańcuch bloków w poszukiwaniu zaginionych transakcji portfela</translation> - </message> - <message> <source>This help message</source> <translation>Ta wiadomość pomocy</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index da28365de0..4863591ac4 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -222,7 +222,15 @@ </context> <context> <name>BanTableModel</name> - </context> + <message> + <source>IP/Netmask</source> + <translation>IP/Máscara</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Banido até</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -379,7 +387,7 @@ </message> <message> <source>&Settings</source> - <translation>&Configurações</translation> + <translation>&definições</translation> </message> <message> <source>&Help</source> @@ -1068,6 +1076,30 @@ <translation>Porta do serviço de proxy (ex. 9050)</translation> </message> <message> + <source>Used for reaching peers via:</source> + <translation>Usado para alcançar participantes via:</translation> + </message> + <message> + <source>IPv4</source> + <translation>IPv4</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6</translation> + </message> + <message> + <source>Tor</source> + <translation>Tor</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>Conecte-se à rede Bitcoin através de um proxy SOCKS5 separado para utilizar serviços ocultos Tor.</translation> + </message> + <message> + <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source> + <translation>Use um proxy SOCKS5 separado para alcançar participantes da rede via serviços ocultos Tor:</translation> + </message> + <message> <source>&Window</source> <translation>&Janela</translation> </message> @@ -1454,10 +1486,18 @@ <translation>&Pares</translation> </message> <message> + <source>Banned peers</source> + <translation>Nós banidos</translation> + </message> + <message> <source>Select a peer to view detailed information.</source> <translation>Selecione um cliente para ver informações detalhadas.</translation> </message> <message> + <source>Whitelisted</source> + <translation>Lista branca</translation> + </message> + <message> <source>Direction</source> <translation>Direção</translation> </message> @@ -1466,6 +1506,18 @@ <translation>Versão</translation> </message> <message> + <source>Starting Block</source> + <translation>Bloco inicial</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Cabeçalhos Sincronizados</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Blocos Sincronizados</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1490,18 +1542,14 @@ <translation>Ultimo Recebido</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes Enviados</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes recebidos</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping</translation> </message> <message> + <source>The duration of a currently outstanding ping.</source> + <translation>A duração de um ping excepcional no momento.</translation> + </message> + <message> <source>Last block time</source> <translation>Horário do último bloco</translation> </message> @@ -1546,6 +1594,34 @@ <translation>Limpar console</translation> </message> <message> + <source>&Disconnect Node</source> + <translation>&Desconectar Nó</translation> + </message> + <message> + <source>Ban Node for</source> + <translation>Banir nó por</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &hora</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &dia</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &semana</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &ano</translation> + </message> + <message> + <source>&Unban Node</source> + <translation>&Desbanir nó</translation> + </message> + <message> <source>Welcome to the Bitcoin Core RPC console.</source> <translation>Bem vindo ao console de RPC do Bitcoin.</translation> </message> @@ -1574,6 +1650,10 @@ <translation>%1 GB</translation> </message> <message> + <source>(node id: %1)</source> + <translation>(id do nó: %1)</translation> + </message> + <message> <source>via %1</source> <translation>por %1</translation> </message> @@ -1966,6 +2046,10 @@ <translation>Copia alteração</translation> </message> <message> + <source>Total Amount %1</source> + <translation>Quantia Total %1</translation> + </message> + <message> <source>or</source> <translation>ou</translation> </message> @@ -1997,15 +2081,15 @@ <source>Payment request expired.</source> <translation>Pedido de pagamento expirado.</translation> </message> + <message> + <source>Pay only the required fee of %1</source> + <translation>Pagar somente a taxa requerida de %1</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation><numerusform>Confirmação estimada em %n bloco.</numerusform><numerusform>Confirmação estimada em %n blocos.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Pagar somente a taxa mínima de %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>O endereço do destinatário é inválido. Favor confirmar.</translation> </message> @@ -2780,6 +2864,18 @@ <translation>Aceitar linha de comando e comandos JSON-RPC</translation> </message> <message> + <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> + <translation>Se <category> não for suprida ou se <category> = 1, mostrar toda informação de depuração.</translation> + </message> + <message> + <source>Error: A fatal internal error occurred, see debug.log for details</source> + <translation>Erro: Um erro interno fatal ocorreu, veja debug.log para detalhes</translation> + </message> + <message> + <source>Fee (in %s/kB) to add to transactions you send (default: %s)</source> + <translation>Taxa (em %s/kB) a ser adicionada às transações que você mandar (padrão: %s)</translation> + </message> + <message> <source>Pruning blockstore...</source> <translation>Prunando os blocos existentes...</translation> </message> @@ -2788,6 +2884,10 @@ <translation>Rodar em segundo plano como serviço e aceitar comandos</translation> </message> <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Não foi possível iniciar o servidor HTTP. Veja o log para detaihes.</translation> + </message> + <message> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Aceitar conexões externas (padrão: 1 se opções -proxy ou -connect não estiverem presentes)</translation> </message> @@ -2812,6 +2912,10 @@ <translation>Define o número de threads de verificação de script (%u a %d, 0 = automático, <0 = número de cores deixados livres, padrão: %d)</translation> </message> <message> + <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> + <translation>O banco de dados de blocos contém um bloco que parece ser do futuro. Isso pode ser devido à data e hora do seu computador estarem configuradas incorretamente. Apenas reconstrua o banco de dados de blocos se você estiver certo de que a data e hora de seu computador estão corretas.</translation> + </message> + <message> <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> <translation>Este pode ser um build de teste pré-lançamento - use por sua conta e risco - não use para mineração ou aplicações de comércio.</translation> </message> @@ -2820,6 +2924,14 @@ <translation>Impossível ouvir em %s neste computador. Provavelmente o Bitcoin já está sendo executado.</translation> </message> <message> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Use UPnP para mapear a porta escutada (padrão: 1 quando escutando e sem -proxy)</translation> + </message> + <message> + <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> + <translation>AVISO: números estranhamente altos de blocos gerados, %d blocos recebidos nas últimas %d horas (%d esperados)</translation> + </message> + <message> <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> <translation>ATENÇÃO: verifique sua conexão %d blocos recebidos nas últimas %d horas (%d tempo estimado)</translation> </message> @@ -2844,12 +2956,12 @@ <translation>(padrão: 1)</translation> </message> <message> - <source><category> can be:</source> - <translation><category> pode ser:</translation> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool deve ser pelo menos %d MB</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Tentar recuperar chaves privadas de um arquivo wallet.dat corrompido</translation> + <source><category> can be:</source> + <translation><category> pode ser:</translation> </message> <message> <source>Block creation options:</source> @@ -2916,6 +3028,10 @@ <translation>Endereço -onion inválido: '%s'</translation> </message> <message> + <source>Keep the transaction memory pool below <n> megabytes (default: %u)</source> + <translation>Mantenha a mempool de transações abaixo de <n> megabytes (padrão: %u)</translation> + </message> + <message> <source>Not enough file descriptors available.</source> <translation>Decriptadores de arquivos disponíveis insuficientes.</translation> </message> @@ -2944,10 +3060,26 @@ <translation>Especifique o arquivo da carteira (dentro do diretório de dados)</translation> </message> <message> + <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> + <translation>Argumento não suportado -benchmark ignorado, use -debug=bench.</translation> + </message> + <message> + <source>Unsupported argument -debugnet ignored, use -debug=net.</source> + <translation>Argumento não suportado -debugnet ignorado, use -debug=net</translation> + </message> + <message> + <source>Unsupported argument -tor found, use -onion.</source> + <translation>Argumento não suportador encontrado: -tor. Use -onion.</translation> + </message> + <message> <source>Use UPnP to map the listening port (default: %u)</source> <translation>Use UPnP para mapear a porta de entrada (padrão: %u)</translation> </message> <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>Comentário do Agente de Usuário (%s) contém caracteres inseguros.</translation> + </message> + <message> <source>Verifying blocks...</source> <translation>Verificando blocos...</translation> </message> @@ -2972,10 +3104,6 @@ <translation>Você precisa reconstruir o banco de dados utilizando -reindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importar blocos de um arquivo externo blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permitir conexões JSON-RPC de uma fonte específica. Válido para um único ip (ex. 1.2.3.4), até uma rede/máscara (ex. 1.2.3.4/255.255.255.0) ou uma rede/CIDR (ex. 1.2.3.4/24). Esta opção pode ser usada múltiplas vezes</translation> </message> @@ -2988,6 +3116,10 @@ <translation>Não foi possível obter acesso exclusivo ao diretório de dados %s. Provavelmente Bitcoin já está sendo executado.</translation> </message> <message> + <source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source> + <translation>Criar novos arquivos com permissões padrão do sistema, em vez de umask 077 (apenas efetivo com funcionalidade de carteira desabilitada)</translation> + </message> + <message> <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source> <translation>Descobrir o próprio IP (padrão: 1 enquanto aguardando conexões e sem -externalip ou -proxy)</translation> </message> @@ -3000,6 +3132,10 @@ <translation>Executa um comando quando um alerta relevante é recebido ou vemos uma longa segregação (%s em cmd é substituído pela mensagem)</translation> </message> <message> + <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source> + <translation>Buscar por endereços de peers via busca DNS, se estiver baixo em endereços (padrão: 1 a não ser que -connect)</translation> + </message> + <message> <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source> <translation>Define o tamanho máximo de alta-prioridade por taxa baixa nas transações em bytes (padrão: %d)</translation> </message> @@ -3168,10 +3304,6 @@ <translation>Aniquilando todas as transações da carteira...</translation> </message> <message> - <source>on startup</source> - <translation>ao iniciar</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrompido, recuperação falhou</translation> </message> @@ -3184,14 +3316,6 @@ <translation>Executa um comando quando o melhor bloco mudar (%s no comando será substituído pelo hash do bloco)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Atualizar carteira para o formato mais recente</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Re-escanear blocos procurando por transações perdidas da carteira</translation> - </message> - <message> <source>This help message</source> <translation>Exibe esta mensagem de ajuda</translation> </message> @@ -3212,6 +3336,10 @@ <translation>(padrão: %s)</translation> </message> <message> + <source>Always query for peer addresses via DNS lookup (default: %u)</source> + <translation>Sempre pergunte pelo endereço de peer via pesquisa DNS (padrão: %u)</translation> + </message> + <message> <source>Error loading wallet.dat</source> <translation>Erro ao carregar wallet.dat</translation> </message> @@ -3232,10 +3360,22 @@ <translation>Endereço -proxy inválido: '%s'</translation> </message> <message> + <source>Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)</source> + <translation>Escutar por conexões JSON-RPC na porta <port> (padrão: %u ou testnet: %u)</translation> + </message> + <message> <source>Listen for connections on <port> (default: %u or testnet: %u)</source> <translation>Aguardar por conexões na porta <port> (padrão: %u ou testnet: %u)</translation> </message> <message> + <source>Maintain at most <n> connections to peers (default: %u)</source> + <translation>Manter, no máximo, <n> conexões com peers (padrão: %u)</translation> + </message> + <message> + <source>Make the wallet broadcast transactions</source> + <translation>Fazer a carteira transmitir transações</translation> + </message> + <message> <source>Prepend debug output with timestamp (default: %u)</source> <translation>Adiciona timestamp como prefixo no debug (default: %u)</translation> </message> @@ -3264,6 +3404,10 @@ <translation>Especificar aqrquivo pid (default: %s)</translation> </message> <message> + <source>Spend unconfirmed change when sending transactions (default: %u)</source> + <translation>Gastar troco não confirmado quando enviar transações (padrão: %u)</translation> + </message> + <message> <source>Unknown network specified in -onlynet: '%s'</source> <translation>Rede desconhecida especificada em -onlynet: '%s'</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 8d1d364935..4549066363 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -1491,14 +1491,6 @@ <translation>Ultimo Recebimento</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes Enviados</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes Recebidos</translation> - </message> - <message> <source>Ping Time</source> <translation>Tempo de Latência</translation> </message> @@ -1987,10 +1979,6 @@ <translation>Pedido de pagamento expirou.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Pagar somente a taxa minima de %1</translation> - </message> - <message> <source>Warning: Invalid Bitcoin address</source> <translation>Aviso: Endereço Bitcoin inválido</translation> </message> @@ -2793,10 +2781,6 @@ <translation><categoria> pode ser:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Tentar recuperar chaves privadas de um wallet.dat corrupto</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opções de criação de bloco:</translation> </message> @@ -2909,10 +2893,6 @@ <translation>É necessário reconstruir as bases de dados usando -reindex para mudar o -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importar blocos de um ficheiro blk000??.dat externo</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permitir conexções JSON-RPC de fontes especificas. Valido para <ip> um unico IP (ex. 1.2.3.4), uma rede/netmask (ex. 1.2.3.4/255.255.255.0) ou uma rede/CIDR (ex. 1.2.3.4/24). Esta opção pode ser especificada varias vezes</translation> </message> @@ -3033,14 +3013,6 @@ <translation>Executar comando quando o melhor bloco mudar (no comando, %s é substituído pela hash do bloco)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Atualize a carteira para o formato mais recente</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Procurar transações em falta na cadeia de blocos</translation> - </message> - <message> <source>This help message</source> <translation>Esta mensagem de ajuda</translation> </message> diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index 7617150829..72ab2c5bdb 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -1466,14 +1466,6 @@ <translation>Ultima primire</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Octeţi trimişi</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Octeţi primiţi</translation> - </message> - <message> <source>Ping Time</source> <translation>Timp ping</translation> </message> @@ -1942,10 +1934,6 @@ <translation>Cererea de plată a expirat.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Plăteşte doar taxa minimă de %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Adresa destinatarului nu este validă, vă rugăm să o verificaţi.</translation> </message> @@ -2736,10 +2724,6 @@ <translation><category> poate fi:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Încercare de recuperare a cheilor private dintr-un wallet.dat corupt</translation> - </message> - <message> <source>Block creation options:</source> <translation>Opţiuni creare bloc:</translation> </message> @@ -2848,10 +2832,6 @@ <translation>Trebuie să reconstruiţi baza de date folosind -reindex pentru a schimba -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importă blocuri dintr-un fişier extern blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Permite conexiunile JSON-RPC din sursa specificată. Valid pentru <ip> sînt IP singulare (ex. 1.2.3.4), o reţea/mască-reţea (ex. 1.2.3.4/255.255.255.0) sau o reţea/CIDR (ex. 1.2.3.4/24). Această opţiune poate fi specificată de mai multe ori</translation> </message> @@ -3004,10 +2984,6 @@ <translation>Şterge toate tranzacţiile din portofel...</translation> </message> <message> - <source>on startup</source> - <translation>la pornire</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corupt, salvare nereuşită</translation> </message> @@ -3020,14 +2996,6 @@ <translation>Execută comanda cînd cel mai bun bloc se modifică (%s în cmd este înlocuit cu hash-ul blocului)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Actualizează portofelul la ultimul format</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Rescanează lanţul de bloc pentru tranzacţiile portofel lipsă</translation> - </message> - <message> <source>This help message</source> <translation>Acest mesaj de ajutor</translation> </message> diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index d4f37479ee..b69a3bda54 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -1044,6 +1044,10 @@ <translation>Порт прокси-сервера (например, 9050)</translation> </message> <message> + <source>Tor</source> + <translation>Tor</translation> + </message> + <message> <source>&Window</source> <translation>&Окно</translation> </message> @@ -1466,14 +1470,6 @@ <translation>Последний раз получено</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Байт передано</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Байт получено</translation> - </message> - <message> <source>Ping Time</source> <translation>Время задержки</translation> </message> @@ -1978,10 +1974,6 @@ <translation>Запрос платежа просрочен.</translation> </message> <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Всего %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Адрес получателя неверный. Пожалуйста, перепроверьте.</translation> </message> @@ -2816,10 +2808,6 @@ <translation><category> может быть:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Попытаться восстановить приватные ключи из повреждённого wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Параметры создания блоков:</translation> </message> @@ -2940,10 +2928,6 @@ <translation>Вам необходимо пересобрать базы данных с помощью -reindex, чтобы изменить -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Импортировать блоки из внешнего файла blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Разрешить подключения JSON-RPC с указанного источника. Разрешённые значения для <ip> — отдельный IP (например, 1.2.3.4), сеть/маска сети (например, 1.2.3.4/255.255.255.0) или сеть/CIDR (например, 1.2.3.4/24). Эту опцию можно использовать многократно</translation> </message> @@ -3192,10 +3176,6 @@ <translation>Стираем все транзакции из кошелька...</translation> </message> <message> - <source>on startup</source> - <translation>при запуске</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat повреждён, спасение данных не удалось</translation> </message> @@ -3208,14 +3188,6 @@ <translation>Выполнить команду, когда появляется новый блок (%s в команде заменяется на хэш блока)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Обновить бумажник до последнего формата</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций</translation> - </message> - <message> <source>This help message</source> <translation>Эта справка</translation> </message> diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index f8ae906128..83f5f2c8e7 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -1494,14 +1494,6 @@ <translation>Posledné prijatie</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Odoslaných bajtov</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Prijatých bajtov</translation> - </message> - <message> <source>Ping Time</source> <translation>Čas odozvy</translation> </message> @@ -1998,10 +1990,6 @@ <translation>Vypršala platnosť požiadavky na platbu.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Zaplatiť minimálny poplatok %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Adresa príjemcu je neplatná. Prosím, overte ju.</translation> </message> @@ -2818,10 +2806,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin <translation><category> môže byť:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Pokus zachrániť súkromné kľúče z poškodeného wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Voľby vytvorenia bloku:</translation> </message> @@ -2930,10 +2914,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin <translation>Potrebujete prebudovať databázu použitím -reindex zmeniť -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importuje bloky z externého súboru blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Povoliť JSON-RPC pripojenia zo zadaného zdroja. Pre <ip> sú platné jednoduché IP (napr. 1.2.3.4), sieť/netmask (napr. 1.2.3.4/255.255.255.0) alebo sieť/CIDR (napr. 1.2.3.4/24). Táto možnosť môže byť zadaná niekoľko krát</translation> </message> @@ -3146,10 +3126,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin <translation>Zmazať všetky transakcie z peňaženky...</translation> </message> <message> - <source>on startup</source> - <translation>pri štarte</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat je poškodený, záchrana zlyhala</translation> </message> @@ -3162,14 +3138,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin <translation>Vykonaj príkaz, ak zmeny v najlepšom bloku (%s v príkaze nahradí blok hash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Aktualizuj peňaženku na najnovší formát.</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Znovu skenovať reťaz blokov pre chýbajúce transakcie</translation> - </message> - <message> <source>This help message</source> <translation>Táto pomocná správa</translation> </message> diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts index 4378c74cd8..ca65810396 100644 --- a/src/qt/locale/bitcoin_sl_SI.ts +++ b/src/qt/locale/bitcoin_sl_SI.ts @@ -1490,14 +1490,6 @@ <translation>Nazadnje prejeto</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Oddanih bajtov</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Prejetih bajtov</translation> - </message> - <message> <source>Ping Time</source> <translation>Odzivni čas</translation> </message> @@ -2006,10 +1998,6 @@ <translation><numerusform>Predviden začetek potrditev po %n najdenem bloku.</numerusform><numerusform>Predviden začetek potrditev po %n najdenih blokih.</numerusform><numerusform>Predviden začetek potrditev po %n najdenih blokih.</numerusform><numerusform>Predviden začetek potrditev po %n najdenih blokih.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Plačilo samo minimalne provizije v znesku %1</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Naslov prejemnika je neveljaven. Prosimo, preverite.</translation> </message> @@ -2852,10 +2840,6 @@ <translation><category> je lahko:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Skušaj obnoviti zasebne ključe iz okvarjene datoteke wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Možnosti ustvarjanja blokov:</translation> </message> @@ -2976,10 +2960,6 @@ <translation>Ob spremembi vrednosti opcije -txindex boste morali obnoviti bazo podatkov z uporabo opcije -reindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Uvozi bloke iz zunanje datoteke blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Iz navedenega vira dovoli povezave na JSON-RPC. Veljavne oblike vrednosti parametra <ip> so: edinstven naslov IP (npr.: 1.2.3.4), kombinacija omrežje/netmask (npr.: 1.2.3.4/255.255.255.0), ali pa kombinacija omrežje/CIDR (1.2.3.4/24). To opcijo lahko navedete večkrat.</translation> </message> @@ -3116,10 +3096,6 @@ <translation>Brišem vse transakcije iz denarnice ...</translation> </message> <message> - <source>on startup</source> - <translation>ob zagonu</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>Datoteka wallet.dat je poškodovana in je ni bilo mogoče obnoviti.</translation> </message> @@ -3132,14 +3108,6 @@ <translation>Izvedi ukaz, ko je najden najboljši blok (niz %s v ukazu bo zamenjan s hash vrednostjo bloka)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Nadgradi denarnico na najnovejšo različico</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>S ponovnim pregledom verige blokov poišči manjkajoče transakcije iz denarnice</translation> - </message> - <message> <source>This help message</source> <translation>To sporočilo pomoči</translation> </message> diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index bb8583fc09..425c077b2b 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -762,10 +762,6 @@ <translation>Lozinka za JSON-RPC konekcije</translation> </message> <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Ponovo skeniraj lanac blokova za nedostajuće transakcije iz novčanika</translation> - </message> - <message> <source>This help message</source> <translation>Ova poruka Pomoći</translation> </message> diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 4691d7d204..69c175645b 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -1547,14 +1547,6 @@ Var vänlig och försök igen.</translation> <translation>Senast mottagen</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Bytes sänt</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Bytes mottaget</translation> - </message> - <message> <source>Ping Time</source> <translation>Pingtid</translation> </message> @@ -2099,14 +2091,6 @@ Var vänlig och försök igen.</translation> <translation><numerusform>Uppskattas till att påbörja bekräftelse inom %n block.</numerusform><numerusform>Uppskattas till att påbörja bekräftelse inom %n block.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Betala endast den minimala avgiften på %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Total summa %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Mottagarens adress är ogiltig. Kontrollera igen.</translation> </message> @@ -2881,10 +2865,6 @@ Var vänlig och försök igen.</translation> <translation>Tillåt kommandon från kommandotolken och JSON-RPC-kommandon</translation> </message> <message> - <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)</source> - <translation>Avgift (i %s/kB) mindre än detta betraktas som nollavgift för vidarebefordran(standard: %s)</translation> - </message> - <message> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation>Om <kategori> inte anges eller om <category> = 1, visa all avlusningsinformation.</translation> </message> @@ -3009,10 +2989,6 @@ Var vänlig och försök igen.</translation> <translation><category> Kan vara:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Försök att rädda de privata nycklarna från en korrupt wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Block skapande inställningar:</translation> </message> @@ -3169,10 +3145,6 @@ Var vänlig och försök igen.</translation> <translation>Du måste återskapa databasen med -reindex för att ändra -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Importerar block från extern blk000??.dat fil</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Tillåt JSON-RPC-anslutningar från specifik källa. Tillåtna <ip> är enkel IP (t.ex 1.2.3.4), en nätverk/nätmask (t.ex. 1.2.3.4/255.255.255.0) eller ett nätverk/CIDR (t.ex. 1.2.3.4/24). Detta alternativ anges flera gånger</translation> </message> @@ -3425,10 +3397,6 @@ Var vänlig och försök igen.</translation> <translation>ZeroMQ-alternativ för notiser:</translation> </message> <message> - <source>on startup</source> - <translation>under uppstarten</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat korrupt, räddning misslyckades</translation> </message> @@ -3441,14 +3409,6 @@ Var vänlig och försök igen.</translation> <translation>Exekvera kommando när det bästa blocket ändras (%s i cmd är utbytt av blockhash)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Uppgradera plånboken till senaste formatet</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Sök i blockkedjan efter saknade plånboks transaktioner</translation> - </message> - <message> <source>This help message</source> <translation>Det här hjälp medelandet</translation> </message> diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index 8d2945fba7..fa8392b3df 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -1494,14 +1494,6 @@ <translation>Son Alma</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Yollanan Baytlar</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Alınan Baytlar</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping Süresi</translation> </message> @@ -2006,10 +1998,6 @@ <translation>Ödeme talebinin ömrü doldu.</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Sadece asgari ücret olan %1 tutarını öde</translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Alıcı adresi geçerli değildir. Lütfen denetleyiniz.</translation> </message> @@ -2856,10 +2844,6 @@ <translation><kategori> şunlar olabilir:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Bozuk bir wallet.dat dosyasından özel anahtarları geri kazanmayı dene</translation> - </message> - <message> <source>Block creation options:</source> <translation>Blok oluşturma seçenekleri:</translation> </message> @@ -2980,10 +2964,6 @@ <translation>-txindex'i değiştirmek için veritabanını -reindex kullanarak tekrar inşa etmeniz gerekmektedir</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Harici blk000??.dat dosyasından blokları içe aktarır</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Belirtilen kaynaktan JSON-RPC bağlantılarını kabul et. Bir <ip> için geçerli olanlar şunlardır: salt IP adresi (mesela 1.2.3.4), bir şebeke/ağ maskesi (örneğin 1.2.3.4/255.255.255.0) ya da bir şebeke/CIDR (mesela 1.2.3.4/24). Bu seçenek birden fazla kez belirtilebilir</translation> </message> @@ -3232,10 +3212,6 @@ <translation>Cüzdandaki tüm muameleler kaldırılıyor...</translation> </message> <message> - <source>on startup</source> - <translation>başlangıçta</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat bozuk, geri kazanım başarısız oldu</translation> </message> @@ -3248,14 +3224,6 @@ <translation>En iyi blok değiştiğinde komutu çalıştır (komut için %s parametresi blok hash değeri ile değiştirilecektir)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Cüzdanı en yeni biçime güncelle</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Blok zincirini eksik cüzdan muameleleri için tekrar tara</translation> - </message> - <message> <source>This help message</source> <translation>Bu yardım mesajı</translation> </message> diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 4ab318425c..e0afa8eff8 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -1546,14 +1546,6 @@ <translation>Востаннє отримано</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Байтів відправлено</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Байтів отримано</translation> - </message> - <message> <source>Ping Time</source> <translation>Затримка</translation> </message> @@ -2102,14 +2094,6 @@ <translation><numerusform>Перше підтвердження очікується протягом %n блоку.</numerusform><numerusform>Перше підтвердження очікується протягом %n блоків.</numerusform><numerusform>Перше підтвердження очікується протягом %n блоків.</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>Платити тільки мінімальну комісію у розмірі %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>Всього %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Адреса отримувача неправильна. Будь ласка, перевірте її.</translation> </message> @@ -2888,10 +2872,6 @@ <translation>Приймати команди із командного рядка та команди JSON-RPC</translation> </message> <message> - <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)</source> - <translation>Комісії (в %s/КБ), що менші за вказану, вважатимуться нульовими (для ретрансляції) (типово: %s)</translation> - </message> - <message> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation>Якщо <category> не задано, або ж якщо <category> = 1, виводить всю налагоджувальну інформацію.</translation> </message> @@ -3012,10 +2992,6 @@ <translation><category> може бути:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>Спроба відновити закриті ключі з пошкодженого wallet.dat</translation> - </message> - <message> <source>Block creation options:</source> <translation>Опції створення блоку:</translation> </message> @@ -3156,10 +3132,6 @@ <translation>Вам необхідно перебудувати базу даних з використанням -reindex для того, щоб змінити -txindex</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>Імпорт блоків з зовнішнього файлу blk000??.dat</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>Дозволити підключення по протоколу JSON-RPC зі вказаного джерела. Правильною для <ip> є окрема IP-адреса (наприклад, 1.2.3.4), IP-адреса та маска підмережі (наприклад, 1.2.3.4/255.255.255.0) або CIDR-адреса (наприклад, 1.2.3.4/24). Цей параметр можна вказувати декілька разів.</translation> </message> @@ -3416,10 +3388,6 @@ <translation>Параметри сповіщень ZeroMQ:</translation> </message> <message> - <source>on startup</source> - <translation>під час запуску</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat пошкоджено, відновлення не вдалося</translation> </message> @@ -3432,14 +3400,6 @@ <translation>Виконати команду, коли з'явиться новий блок (%s в команді змінюється на хеш блоку)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>Модернізувати гаманець до найновішого формату</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>Пересканувати ланцюжок блоків, в пошуку втрачених транзакцій</translation> - </message> - <message> <source>This help message</source> <translation>Дана довідка</translation> </message> diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts index 0b382ac6c0..004857cf01 100644 --- a/src/qt/locale/bitcoin_uz@Cyrl.ts +++ b/src/qt/locale/bitcoin_uz@Cyrl.ts @@ -1220,14 +1220,6 @@ <translation>Сўнгги қабул қилинган</translation> </message> <message> - <source>Bytes Sent</source> - <translation>Жўнатилган байтлар</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>Қабул қилинган байтлар</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping вақти</translation> </message> diff --git a/src/qt/locale/bitcoin_vi_VN.ts b/src/qt/locale/bitcoin_vi_VN.ts index 1695f26ae7..c55aecd82d 100644 --- a/src/qt/locale/bitcoin_vi_VN.ts +++ b/src/qt/locale/bitcoin_vi_VN.ts @@ -686,10 +686,6 @@ <translation>Chú ý</translation> </message> <message> - <source>on startup</source> - <translation>khi khởi động</translation> - </message> - <message> <source>This help message</source> <translation>Thông điệp trợ giúp này</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index ecb35b0c4f..1cd7eed503 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -1522,14 +1522,6 @@ <translation>最后接收</translation> </message> <message> - <source>Bytes Sent</source> - <translation>发送字节</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>接收字节</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping 时间</translation> </message> @@ -2058,14 +2050,6 @@ <translation><numerusform>预计 %n 个数据块后被确认。</numerusform></translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>只支付最小费用 %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>总金额 %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> - </message> - <message> <source>The recipient address is not valid. Please recheck.</source> <translation>接收人地址无效。请重新检查。</translation> </message> @@ -2925,10 +2909,6 @@ <translation><category> 可能是:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>尝试从损坏的钱包文件wallet.dat中恢复私钥</translation> - </message> - <message> <source>Block creation options:</source> <translation>数据块创建选项:</translation> </message> @@ -3049,10 +3029,6 @@ <translation>您需要将 -reindex 改为 -txindex 以重建数据库</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>从blk000??.dat文件导入数据块</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>允许来自指定地址的 JSON-RPC 连接。 <ip>为单一IP (如: 1.2.3.4), 网络/掩码 (如: 1.2.3.4/255.255.255.0), 网络/CIDR (如: 1.2.3.4/24)。该选项可多次指定。</translation> </message> @@ -3302,10 +3278,6 @@ <translation>ZeroMQ 通知选项:</translation> </message> <message> - <source>on startup</source> - <translation>启动中</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>钱包文件wallet.dat损坏,抢救备份失败</translation> </message> @@ -3319,14 +3291,6 @@ <translation>当最佳数据块变化时执行命令 (命令行中的 %s 会被替换成数据块哈希值)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>将钱包升级到最新的格式</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>重新扫描区块链以查找遗漏的钱包交易</translation> - </message> - <message> <source>This help message</source> <translation>本帮助信息 </translation> diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 8a92be31b5..b4dbf85a33 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -1550,14 +1550,6 @@ <translation>最近收到</translation> </message> <message> - <source>Bytes Sent</source> - <translation>送出位元組</translation> - </message> - <message> - <source>Bytes Received</source> - <translation>收到位元組</translation> - </message> - <message> <source>Ping Time</source> <translation>Ping 時間</translation> </message> @@ -2070,6 +2062,10 @@ <translation>複製找零金額</translation> </message> <message> + <source>Total Amount %1</source> + <translation>總金額 %1</translation> + </message> + <message> <source>or</source> <translation>或</translation> </message> @@ -2102,12 +2098,8 @@ <translation>付款的要求過期了。</translation> </message> <message> - <source>Pay only the minimum fee of %1</source> - <translation>只付最低手續費 %1</translation> - </message> - <message> - <source>Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></source> - <translation>總金額 %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span></translation> + <source>Pay only the required fee of %1</source> + <translation>只付必要的手續費 %1</translation> </message> <message> <source>The recipient address is not valid. Please recheck.</source> @@ -2889,10 +2881,6 @@ </translation> </message> <message> - <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)</source> - <translation>當處理轉發的交易時,如果每千位元組(kB)的手續費比這個值(單位是 %s)低,就視為沒付手續費(預設值: %s)</translation> - </message> - <message> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation>如果沒有提供 <category> 或是值為 1 就會輸出所有的除錯資訊。</translation> </message> @@ -3017,10 +3005,6 @@ <translation><category> 可以是:</translation> </message> <message> - <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation>嘗試從壞掉的錢包檔 wallet.dat 復原密鑰</translation> - </message> - <message> <source>Block creation options:</source> <translation>區塊製造選項:</translation> </message> @@ -3173,10 +3157,6 @@ <translation>改變 -txindex 參數後,必須要用 -reindex 參數來重建資料庫</translation> </message> <message> - <source>Imports blocks from external blk000??.dat file</source> - <translation>從其它來源的 blk000??.dat 檔匯入區塊</translation> - </message> - <message> <source>Allow JSON-RPC connections from specified source. Valid for <ip> 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</source> <translation>允許指定的來源建立 JSON-RPC 連線。<ip> 的有效值可以是一個單獨位址(像是 1.2.3.4),一個網段/網段罩遮值(像是 1.2.3.4/255.255.255.0),或是網段/CIDR值(像是 1.2.3.4/24)。這個選項可以設定多次。</translation> </message> @@ -3209,6 +3189,10 @@ <translation>當收到相關警示,或發現相當長的分支時,所要執行的指令(指令中的 %s 會被取代成警示訊息)</translation> </message> <message> + <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source> + <translation>當處理轉發的交易、挖礦、或製造交易時,如果每千位元組(kB)的手續費比這個值(單位是 %s)低,就視為沒付手續費(預設值: %s)</translation> + </message> + <message> <source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source> <translation>當沒有設定 paytxfee 時,自動包含可以讓交易能在平均 n 個區塊內開始確認的手續費(預設值: %u)</translation> </message> @@ -3265,6 +3249,10 @@ <translation>啟用最佳鏈結...</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet.dat on startup</source> + <translation>啟動時嘗試從壞掉的錢包檔 wallet.dat 復原密鑰</translation> + </message> + <message> <source>Cannot resolve -whitebind address: '%s'</source> <translation>沒辦法解析 -whitebind 指定的位址: '%s'</translation> </message> @@ -3289,6 +3277,10 @@ <translation>讀取資料庫時發生錯誤,要關閉了。</translation> </message> <message> + <source>Imports blocks from external blk000??.dat file on startup</source> + <translation>啟動時從其它來源的 blk000??.dat 檔匯入區塊</translation> + </message> + <message> <source>Information</source> <translation>資訊</translation> </message> @@ -3345,6 +3337,10 @@ <translation>因為系統的限制,將 -maxconnections 參數從 %d 降到了 %d</translation> </message> <message> + <source>Rescan the block chain for missing wallet transactions on startup</source> + <translation>啟動時重新掃描區塊鏈,來尋找錢包可能漏掉的交易。</translation> + </message> + <message> <source>Send trace/debug info to console instead of debug.log file</source> <translation>在終端機顯示追蹤或除錯資訊,而不是寫到檔案 debug.log 中</translation> </message> @@ -3413,6 +3409,10 @@ <translation>無法和這台電腦上的 %s 繫結(回傳錯誤 %s)</translation> </message> <message> + <source>Upgrade wallet to latest format on startup</source> + <translation>啟動時把錢包檔案升級成最新的格式</translation> + </message> + <message> <source>Username for JSON-RPC connections</source> <translation>JSON-RPC 連線使用者名稱</translation> </message> @@ -3433,10 +3433,6 @@ <translation>ZeroMQ 通知選項:</translation> </message> <message> - <source>on startup</source> - <translation>當啟動時</translation> - </message> - <message> <source>wallet.dat corrupt, salvage failed</source> <translation>錢包檔 weallet.dat 壞掉了,拯救失敗</translation> </message> @@ -3449,14 +3445,6 @@ <translation>當最新區塊改變時要執行的指令(指令中的 %s 會被取代成區塊雜湊值)</translation> </message> <message> - <source>Upgrade wallet to latest format</source> - <translation>把錢包檔案升級成最新的格式</translation> - </message> - <message> - <source>Rescan the block chain for missing wallet transactions</source> - <translation>重新掃描區塊鏈,來尋找錢包可能漏掉的交易。</translation> - </message> - <message> <source>This help message</source> <translation>這些說明訊息</translation> </message> diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 65e490570e..3e5c6c72b1 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -26,10 +26,10 @@ #include <QSettings> #include <QStringList> -OptionsModel::OptionsModel(QObject *parent) : +OptionsModel::OptionsModel(QObject *parent, bool resetSettings) : QAbstractListModel(parent) { - Init(); + Init(resetSettings); } void OptionsModel::addOverriddenOption(const std::string &option) @@ -38,8 +38,11 @@ void OptionsModel::addOverriddenOption(const std::string &option) } // Writes all missing QSettings with their default values -void OptionsModel::Init() +void OptionsModel::Init(bool resetSettings) { + if (resetSettings) + Reset(); + QSettings settings; // Ensure restart flag is unset on client startup diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 8448cad8de..d5bddb1a94 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -24,7 +24,7 @@ class OptionsModel : public QAbstractListModel Q_OBJECT public: - explicit OptionsModel(QObject *parent = 0); + explicit OptionsModel(QObject *parent = 0, bool resetSettings = false); enum OptionID { StartAtStartup, // bool @@ -48,7 +48,7 @@ public: OptionIDRowCount, }; - void Init(); + void Init(bool resetSettings = false); void Reset(); int rowCount(const QModelIndex & parent = QModelIndex()) const; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 8401701821..619c8631ae 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -343,6 +343,8 @@ void RPCConsole::setClientModel(ClientModel *model) updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent()); connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64))); + connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t))); + // set up peer table ui->peerWidget->setModel(model->getPeerTableModel()); ui->peerWidget->verticalHeader()->hide(); @@ -523,6 +525,16 @@ void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate) ui->lastBlockTime->setText(blockDate.toString()); } +void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) +{ + ui->mempoolNumberTxs->setText(QString::number(numberOfTxs)); + + if (dynUsage < 1000000) + ui->mempoolSize->setText(QString::number(dynUsage/1000.0, 'f', 2) + " KB"); + else + ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB"); +} + void RPCConsole::on_lineEdit_returnPressed() { QString cmd = ui->lineEdit->text(); @@ -856,3 +868,8 @@ void RPCConsole::showOrHideBanTableIfRequired() ui->banlistWidget->setVisible(visible); ui->banHeading->setVisible(visible); } + +void RPCConsole::setTabFocus(enum TabTypes tabType) +{ + ui->tabWidget->setCurrentIndex(tabType); +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index d5932ff149..4b242affcd 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -44,6 +44,13 @@ public: CMD_ERROR }; + enum TabTypes { + TAB_INFO = 0, + TAB_CONSOLE = 1, + TAB_GRAPH = 2, + TAB_PEERS = 3 + }; + protected: virtual bool eventFilter(QObject* obj, QEvent *event); void keyPressEvent(QKeyEvent *); @@ -77,6 +84,8 @@ public Q_SLOTS: void setNumConnections(int count); /** Set number of blocks and last block date shown in the UI */ void setNumBlocks(int count, const QDateTime& blockDate); + /** Set size (number of transactions and memory usage) of the mempool in the UI */ + void setMempoolSize(long numberOfTxs, size_t dynUsage); /** Go forward or back in history */ void browseHistory(int offset); /** Scroll console view to end */ @@ -91,6 +100,8 @@ public Q_SLOTS: void banSelectedNode(int bantime); /** Unban a selected node on the Bans tab */ void unbanSelectedNode(); + /** set which tab has the focus (is visible) */ + void setTabFocus(enum TabTypes tabType); Q_SIGNALS: // For RPC command executor diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0ee08a1b0c..7b714be5b1 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -531,7 +531,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.second = CClientUIInterface::MSG_ERROR; break; case WalletModel::AbsurdFee: - msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); + msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), maxTxFee)); break; case WalletModel::PaymentRequestExpired: msgParams.first = tr("Payment request expired."); @@ -633,7 +633,8 @@ void SendCoinsDialog::updateSmartFeeLabel() return; int nBlocksToConfirm = defaultConfirmTarget - ui->sliderSmartFee->value(); - CFeeRate feeRate = mempool.estimateFee(nBlocksToConfirm); + int estimateFoundAtBlocks = nBlocksToConfirm; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks); if (feeRate <= CFeeRate(0)) // not enough data => minfee { ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB"); @@ -644,7 +645,7 @@ void SendCoinsDialog::updateSmartFeeLabel() { ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); ui->labelSmartFee2->hide(); - ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", nBlocksToConfirm)); + ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); } updateFeeMinimizedLabel(); diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 98ad1a44b6..e8ada9f762 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -13,6 +13,7 @@ #include "transactionrecord.h" #include "walletmodel.h" +#include "core_io.h" #include "main.h" #include "sync.h" #include "uint256.h" @@ -220,6 +221,18 @@ public: } return QString(); } + + QString getTxHex(TransactionRecord *rec) + { + LOCK2(cs_main, wallet->cs_wallet); + std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash); + if(mi != wallet->mapWallet.end()) + { + std::string strHex = EncodeHexTx(static_cast<CTransaction>(mi->second)); + return QString::fromStdString(strHex); + } + return QString(); + } }; TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent): @@ -594,6 +607,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return rec->getTxID(); case TxHashRole: return QString::fromStdString(rec->hash.ToString()); + case TxHexRole: + return priv->getTxHex(rec); case ConfirmedRole: return rec->status.countsForBalance; case FormattedAmountRole: diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 2089f703a6..601f893d47 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -60,6 +60,8 @@ public: TxIDRole, /** Transaction hash */ TxHashRole, + /** Transaction data, hex-encoded */ + TxHexRole, /** Is transaction confirmed? */ ConfirmedRole, /** Formatted amount, without brackets when unconfirmed */ diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 54e5a82720..11e6d750ac 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -141,6 +141,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa QAction *copyLabelAction = new QAction(tr("Copy label"), this); QAction *copyAmountAction = new QAction(tr("Copy amount"), this); QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); + QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this); QAction *editLabelAction = new QAction(tr("Edit label"), this); QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); @@ -149,6 +150,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); contextMenu->addAction(copyTxIDAction); + contextMenu->addAction(copyTxHexAction); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); @@ -170,6 +172,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); + connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } @@ -380,6 +383,11 @@ void TransactionView::copyTxID() GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole); } +void TransactionView::copyTxHex() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHexRole); +} + void TransactionView::editLabel() { if(!transactionView->selectionModel() ||!model) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index ac157fb98d..dde700c4d1 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -93,6 +93,7 @@ private Q_SLOTS: void copyLabel(); void copyAmount(); void copyTxID(); + void copyTxHex(); void openThirdPartyTxUrl(QString url); void updateWatchOnlyColumn(bool fHaveWatchOnly); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 5c21db8bdf..690ea0811e 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -290,8 +290,10 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return TransactionCreationFailed; } - // reject absurdly high fee > 0.1 bitcoin - if (nFeeRequired > 10000000) + // reject absurdly high fee. (This can never happen because the + // wallet caps the fee at maxTxFee. This merely serves as a + // belt-and-suspenders check) + if (nFeeRequired > maxTxFee) return AbsurdFee; } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 9c0e78f772..c80838e1f1 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -10,6 +10,7 @@ #include "coins.h" #include "consensus/validation.h" #include "main.h" +#include "policy/policy.h" #include "primitives/transaction.h" #include "rpcserver.h" #include "streams.h" @@ -71,6 +72,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))); @@ -111,6 +113,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))); @@ -313,6 +316,7 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"version\" : n, (numeric) The block version\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\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" @@ -374,6 +378,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" @@ -608,6 +613,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n" " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" + " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n" @@ -639,6 +645,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 343b6234d4..cab5819017 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -96,6 +96,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawmempool", 0 }, { "estimatefee", 0 }, { "estimatepriority", 0 }, + { "estimatesmartfee", 0 }, + { "estimatesmartpriority", 0 }, { "prioritisetransaction", 1 }, { "prioritisetransaction", 2 }, { "setban", 2 }, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index f42b31627c..19b031b860 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -157,7 +157,7 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -171,7 +171,7 @@ UniValue generate(const UniValue& params, bool fHelp) ++pblock->nNonce; } CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -426,7 +426,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; - TestBlockValidity(state, block, pindexPrev, false, true); + TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } } @@ -510,7 +510,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy); + pblocktemplate = CreateNewBlock(Params(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -652,7 +652,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { @@ -726,3 +726,75 @@ UniValue estimatepriority(const UniValue& params, bool fHelp) return mempool.estimatePriority(nBlocks); } + +UniValue estimatesmartfee(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartfee nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However it will not return a value below the mempool reject fee.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartfee", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound); + result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); + result.push_back(Pair("blocks", answerFound)); + return result; +} + +UniValue estimatesmartpriority(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartpriority nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"priority\" : x.x, (numeric) estimated priority\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartpriority", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + double priority = mempool.estimateSmartPriority(nBlocks, &answerFound); + result.push_back(Pair("priority", priority)); + result.push_back(Pair("blocks", answerFound)); + return result; +} diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 9bf017e385..2578848891 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -90,6 +90,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) " \"addr\":\"host:port\", (string) The ip address and port of the peer\n" " \"addrlocal\":\"ip:port\", (string) local address\n" " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n" + " \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n" " \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n" " \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n" " \"bytessent\": n, (numeric) The total bytes sent\n" @@ -134,6 +135,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) if (!(stats.addrLocal.empty())) obj.push_back(Pair("addrlocal", stats.addrLocal)); obj.push_back(Pair("services", strprintf("%016x", stats.nServices))); + obj.push_back(Pair("relaytxes", stats.fRelayTxes)); obj.push_back(Pair("lastsend", stats.nLastSend)); obj.push_back(Pair("lastrecv", stats.nLastRecv)); obj.push_back(Pair("bytessent", stats.nSendBytes)); @@ -368,7 +370,16 @@ UniValue getnettotals(const UniValue& params, bool fHelp) "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" " \"totalbytessent\": n, (numeric) Total bytes sent\n" - " \"timemillis\": t (numeric) Total cpu time\n" + " \"timemillis\": t, (numeric) Total cpu time\n" + " \"uploadtarget\":\n" + " {\n" + " \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n" + " \"target\": n, (numeric) Target in bytes\n" + " \"target_reached\": true|false, (boolean) True if target is reached\n" + " \"serve_historical_blocks\": true|false, (boolean) True if serving historical blocks\n" + " \"bytes_left_in_cycle\": t, (numeric) Bytes left in current time cycle\n" + " \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n" + " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnettotals", "") diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 11d9a6f2bb..3bda459245 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -506,7 +506,6 @@ UniValue decodescript(const UniValue& params, bool fHelp) + HelpExampleRpc("decodescript", "\"hexstring\"") ); - LOCK(cs_main); RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); UniValue r(UniValue::VOBJ); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 8bda5a0373..83d2c2d503 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -319,6 +319,8 @@ static const CRPCCommand vRPCCommands[] = { "util", "verifymessage", &verifymessage, true }, { "util", "estimatefee", &estimatefee, true }, { "util", "estimatepriority", &estimatepriority, true }, + { "util", "estimatesmartfee", &estimatesmartfee, true }, + { "util", "estimatesmartpriority", &estimatesmartpriority, true }, /* Not shown in help */ { "hidden", "invalidateblock", &invalidateblock, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index dde8dfdcc3..fc88f82be8 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -193,6 +193,8 @@ extern UniValue getblocktemplate(const UniValue& params, bool fHelp); 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 estimatesmartfee(const UniValue& params, bool fHelp); +extern UniValue estimatesmartpriority(const UniValue& params, bool fHelp); extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue getaccountaddress(const UniValue& params, bool fHelp); diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index b0d5faaf77..79504f6ad3 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -6,6 +6,7 @@ #include "bitcoinconsensus.h" #include "primitives/transaction.h" +#include "pubkey.h" #include "script/interpreter.h" #include "version.h" @@ -60,7 +61,13 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) return 0; } -} // anon namespace +struct ECCryptoClosure +{ + ECCVerifyHandle handle; +}; + +ECCryptoClosure instance_of_eccryptoclosure; +} int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, const unsigned char *txTo , unsigned int txToLen, diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 6a20d497c0..8dcab832cb 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -9,7 +9,6 @@ #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" @@ -165,16 +164,8 @@ 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]; - // 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)) - return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); - - return true; + std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1); + return CPubKey::CheckLowS(vchSigCopy); } bool static IsDefinedHashtypeSignature(const valtype &vchSig) { diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 099b4ad0e3..eee96e7c2d 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -5,17 +5,30 @@ #include "sigcache.h" +#include "memusage.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" #include <boost/thread.hpp> -#include <boost/tuple/tuple_comparison.hpp> +#include <boost/unordered_set.hpp> namespace { /** + * We're hashing a nonce into the entries themselves, so we don't need extra + * blinding in the set hash computation. + */ +class CSignatureCacheHasher +{ +public: + size_t operator()(const uint256& key) const { + return key.GetCheapHash(); + } +}; + +/** * Valid signature cache, to avoid doing expensive ECDSA signature checking * twice for every transaction (once when accepted into memory pool, and * again when accepted into the block chain) @@ -23,52 +36,54 @@ namespace { class CSignatureCache { private: - //! sigdata_type is (signature hash, signature, public key): - typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; + //! Entries are SHA256(nonce || signature hash || public key || signature): + uint256 nonce; + typedef boost::unordered_set<uint256, CSignatureCacheHasher> map_type; + map_type setValid; boost::shared_mutex cs_sigcache; + public: + CSignatureCache() + { + GetRandBytes(nonce.begin(), 32); + } + + void + ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) + { + CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); + } + bool - Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) + Get(const uint256& entry) { boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); + return setValid.count(entry); + } - sigdata_type k(hash, vchSig, pubKey); - std::set<sigdata_type>::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; + void Erase(const uint256& entry) + { + boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); + setValid.erase(entry); } - void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) + void Set(const uint256& entry) { - // DoS prevention: limit cache size to less than 10MB - // (~200 bytes per cache entry times 50,000 entries) - // Since there are a maximum of 20,000 signature operations per block - // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); if (nMaxCacheSize <= 0) return; boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); - - while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) + while (memusage::DynamicUsage(setValid) > nMaxCacheSize) { - // Evict a random entry. Random because that helps - // foil would-be DoS attackers who might try to pre-generate - // and re-use a set of valid signatures just-slightly-greater - // than our cache size. - uint256 randomHash = GetRandHash(); - std::vector<unsigned char> unused; - std::set<sigdata_type>::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); - if (it == setValid.end()) - it = setValid.begin(); - setValid.erase(*it); + map_type::size_type s = GetRand(setValid.bucket_count()); + map_type::local_iterator it = setValid.begin(s); + if (it != setValid.end(s)) { + setValid.erase(*it); + } } - sigdata_type k(hash, vchSig, pubKey); - setValid.insert(k); + setValid.insert(entry); } }; @@ -78,13 +93,21 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsig { static CSignatureCache signatureCache; - if (signatureCache.Get(sighash, vchSig, pubkey)) + uint256 entry; + signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); + + if (signatureCache.Get(entry)) { + if (!store) { + signatureCache.Erase(entry); + } return true; + } if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) return false; - if (store) - signatureCache.Set(sighash, vchSig, pubkey); + if (store) { + signatureCache.Set(entry); + } return true; } diff --git a/src/script/sigcache.h b/src/script/sigcache.h index b299038daa..2269972560 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -10,6 +10,10 @@ #include <vector> +// DoS prevention: limit cache size to less than 40MB (over 500000 +// entries on 64-bit systems). +static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 40; + class CPubKey; class CachingTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index 076ff1295f..e0b7b7a48a 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -1,9 +1,12 @@ bench_inv +bench_ecdh bench_sign bench_verify +bench_schnorr_verify bench_recover bench_internal tests +gen_context *.exe *.so *.a @@ -28,6 +31,7 @@ build-aux/ *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in +src/ecmult_static_context.h m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index 0d8089cfe4..4e1e73c39f 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -8,20 +8,24 @@ compiler: - gcc env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no matrix: - - SCALAR=32bit + - SCALAR=32bit RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes - SCALAR=64bit - - FIELD=64bit + - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit + - FIELD=32bit SCHNORR=yes - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes + - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes + - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 matrix: fast_finish: true include: @@ -55,5 +59,5 @@ before_script: ./autogen.sh 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-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index cc15338b7e..7772a4e9d2 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -19,6 +19,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 @@ -38,40 +40,72 @@ 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 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) +libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) libsecp256k1_la_LIBADD = $(SECP_LIBS) noinst_PROGRAMS = if USE_BENCHMARK -noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal +noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_verify_SOURCES = src/bench_verify.c bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_verify_LDFLAGS = -static -bench_recover_SOURCES = src/bench_recover.c -bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_recover_LDFLAGS = -static bench_sign_SOURCES = src/bench_sign.c bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_sign_LDFLAGS = -static bench_internal_SOURCES = src/bench_internal.c bench_internal_LDADD = $(SECP_LIBS) -bench_internal_LDFLAGS = -static bench_internal_CPPFLAGS = $(SECP_INCLUDES) endif if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) tests_LDFLAGS = -static TESTS = tests endif -EXTRA_DIST = autogen.sh +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 + +src/ecmult_static_context.h: $(gen_context_BIN) + ./$(gen_context_BIN) + +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h +endif + +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h + +if ENABLE_MODULE_ECDH +include src/modules/ecdh/Makefile.am.include +endif + +if ENABLE_MODULE_SCHNORR +include src/modules/schnorr/Makefile.am.include +endif + +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include +endif 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 0000000000..77fd346a79 --- /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 <bonzini@gnu.org> +# +# 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 index 4a398d6c93..d41bbb6487 100644 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -16,8 +16,7 @@ AC_MSG_RESULT([$has_64bit_asm]) dnl AC_DEFUN([SECP_OPENSSL_CHECK],[ -if test x"$use_pkgconfig" = x"yes"; then - : #NOP + 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 @@ -27,11 +26,16 @@ if test x"$use_pkgconfig" = x"yes"; then LIBS="$TEMP_LIBS" fi ]) -else - 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 = 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([[ diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 3dc1829516..786d8dcfb9 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -17,25 +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 if test "x$CFLAGS" = "x"; then CFLAGS="-O3 -g" fi +AM_PROG_CC_C_O + AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) fi -case $host in - *mingw*) - use_pkgconfig=no - ;; - *) - use_pkgconfig=yes - ;; -esac - case $host_os in *darwin*) if test x$cross_compiling != xyes; then @@ -80,6 +74,14 @@ 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 no)]), @@ -95,6 +97,26 @@ AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), [use_endomorphism=$enableval], [use_endomorphism=no]) + +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + [use_ecmult_static_precomputation=$enableval], + [use_ecmult_static_precomputation=yes]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]), + [enable_module_ecdh=$enableval], + [enable_module_ecdh=no]) + +AC_ARG_ENABLE(module_schnorr, + AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]), + [enable_module_schnorr=$enableval], + [enable_module_schnorr=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_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -305,6 +327,22 @@ if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi +if test x"$use_ecmult_static_precomputation" = 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_schnorr" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature 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() AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) @@ -312,6 +350,10 @@ 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 ECDH module: $enable_module_ecdh]) + +AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) +AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) @@ -321,6 +363,10 @@ AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) 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 0000000000..5b141a9948 --- /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 <string.h> +#include <secp256k1.h> + +#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 0000000000..6d27871a7c --- /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 <secp256k1.h> + +# 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 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 0000000000..c2e63b4b8d --- /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 <string.h> +#include <secp256k1.h> + +#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 0000000000..2fd088f8ab --- /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 <secp256k1.h> + +# 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 diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index 06afd4c65b..7145dbcc54 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -5,6 +5,99 @@ extern "C" { # endif +#include <stddef.h> + +/* 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 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 or transmission, use + * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. + * + * Furthermore, it is guaranteed that identical public keys (ignoring + * compression) will have identical representation, so they can be memcmp'ed. + */ +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 or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_serialize_* functions. + * + * Furthermore, it is guaranteed to identical signatures will have identical + * representation, so they can be memcmp'ed. + */ +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__) # define SECP256K1_GNUC_PREREQ(_maj,_min) \ @@ -26,6 +119,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,305 +147,434 @@ extern "C" { # define SECP256K1_ARG_NONNULL(_x) # endif -/** Opaque data structure that holds context information (precomputed tables etc.). - * Only functions that take a pointer to a non-const context require exclusive - * access to it. Multiple functions that take a pointer to a const context may - * run simultaneously. - */ -typedef struct secp256k1_context_struct secp256k1_context_t; +/** 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_context_create. */ -# define SECP256K1_CONTEXT_VERIFY (1 << 0) -# define SECP256K1_CONTEXT_SIGN (1 << 1) +#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) + +/** 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) /** Create a secp256k1 context object. + * * Returns: a newly created context object. * In: flags: which parts of the context to initialize. */ -secp256k1_context_t* secp256k1_context_create( - int flags +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. - * In: ctx: an existing context to copy + * Args: ctx: an existing context to copy (cannot be NULL) */ -secp256k1_context_t* secp256k1_context_clone( - const secp256k1_context_t* ctx -) SECP256K1_WARN_UNUSED_RESULT; +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) + */ +SECP256K1_API void secp256k1_context_destroy( + secp256k1_context* ctx +); + +/** 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_context_destroy( - secp256k1_context_t* ctx +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); + +/** 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: ctx: a secp256k1 context object, initialized for verification. + * 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) - * 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 + * 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_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - const unsigned char *sig, - int siglen, - const unsigned char *pubkey, - int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +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); -/** A pointer to a function to deterministically generate a nonce. - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. - * 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) - * 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. - * data: Arbitrary data pointer that is passed through. - * Out: nonce32: pointer to a 32-byte array to be filled by the function. - * Except for test cases, this function should compute some cryptographic hash of - * the message, the key and the attempt. +/** 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. */ -typedef int (*secp256k1_nonce_function_t)( - unsigned char *nonce32, - const unsigned char *msg32, - const unsigned char *key32, - unsigned int attempt, - const void *data -); +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. */ -extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979; +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; - +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. + * * Returns: 1: signature created - * 0: the nonce generation function failed, the private key was invalid, or there is not - * enough space in the signature (as indicated by siglen). - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * 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) + * 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). - * - * The sig always has an s value in the lower half of the range (From 0x1 - * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive), unlike many other implementations. - * With ECDSA a third-party can can forge a second distinct signature - * of the same message given a single initial signature without knowing - * the key by setting s to its additive inverse mod-order, 'flipping' the - * sign of the random point R which is not included in the signature. - * Since the forgery is of the same message this 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 canonical 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. Adjusting it inside the signing - * function avoids the need to re-serialize or have curve specific - * constants outside of the library. By always using a canonical form - * even in applications where it isn't needed it becomes possible to - * impose a requirement later if a need is discovered. - * 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. - */ -int secp256k1_ecdsa_sign( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig, - int *siglen, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Create a compact ECDSA signature (64 byte + recovery id). - * Returns: 1: signature created - * 0: the nonce generation function failed, or the secret key was invalid. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * msg32: the 32-byte message hash being signed (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) - * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) - * In case 0 is returned, the returned signature length will be zero. - * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. */ -int secp256k1_ecdsa_sign_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig64, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata, - int *recid +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); -/** Recover an ECDSA public key from a compact signature. - * Returns: 1: public key successfully recovered (which guarantees a correct signature). - * 0: otherwise. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) - * 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) - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - const unsigned char *sig64, - unsigned char *pubkey, - int *pubkeylen, - int compressed, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - /** Verify an ECDSA secret key. + * * Returns: 1: secret key is valid * 0: secret key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) + * 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 secp256k1_context_t* ctx, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Just validate a public key. - * Returns: 1: public key is valid - * 0: public key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * 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 secp256k1_context_t* ctx, - const unsigned char *pubkey, - int pubkeylen +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: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * 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 + * 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_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen, - const unsigned char *seckey, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Decompress a public key. - * In: ctx: pointer to a context object (cannot be NULL) - * 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: pubkey was invalid - * 1: pubkey was valid, and was replaced with its decompressed version - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen +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); -/** Export a private key in DER format. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) +/** 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_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( - const secp256k1_context_t* ctx, - const unsigned char *seckey, - unsigned char *privkey, - int *privkeylen, - 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. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *privkey, - int privkeylen +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 private key by adding tweak to it. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *tweak +/** Tweak a public key by adding tweak times the generator 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 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_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 public key by adding tweak times the generator to it. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) +/** 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_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Tweak a private key by multiplying it with tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *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. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) +/** 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( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +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); /** Updates the context randomization. * Returns: 1: randomization successfully updated * 0: error - * In: ctx: pointer to a context object (cannot be NULL) - * seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( - secp256k1_context_t* ctx, - const unsigned char *seed32 +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 } diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 0000000000..4b84d7a963 --- /dev/null +++ b/src/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,31 @@ +#ifndef _SECP256K1_ECDH_ +# define _SECP256K1_ECDH_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** 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: result: a 32-byte array which will be populated by an ECDH + * secret computed from the point and scalar + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context* ctx, + unsigned char *result, + const secp256k1_pubkey *pubkey, + const unsigned char *privkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h new file mode 100644 index 0000000000..0553797253 --- /dev/null +++ b/src/secp256k1/include/secp256k1_recovery.h @@ -0,0 +1,110 @@ +#ifndef _SECP256K1_RECOVERY_ +# define _SECP256K1_RECOVERY_ + +# 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 diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h new file mode 100644 index 0000000000..dc32fec1ea --- /dev/null +++ b/src/secp256k1/include/secp256k1_schnorr.h @@ -0,0 +1,173 @@ +#ifndef _SECP256K1_SCHNORR_ +# define _SECP256K1_SCHNORR_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Create a signature using a custom EC-Schnorr-SHA256 construction. It + * produces non-malleable 64-byte signatures which support public key recovery + * batch validation, and multiparty signing. + * 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: sig64: pointer to a 64-byte 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_schnorr_sign( + const secp256k1_context* ctx, + unsigned char *sig64, + 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 a signature created by secp256k1_schnorr_sign. + * Returns: 1: correct signature + * 0: incorrect signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig64: the 64-byte signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: the public key to verify with (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( + const secp256k1_context* ctx, + const unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an EC public key from a Schnorr signature created using + * secp256k1_schnorr_sign. + * 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 a pubkey to set to the recovered public key + * (cannot be NULL). + * In: sig64: signature as 64 byte array (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + */ +SECP256K1_API int secp256k1_schnorr_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *sig64, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Generate a nonce pair deterministically for use with + * secp256k1_schnorr_partial_sign. + * Returns: 1: valid nonce pair was generated. + * 0: otherwise (nonce generation function failed) + * Args: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * Out: pubnonce: public side of the nonce (cannot be NULL) + * privnonce32: private side of the nonce (32 byte) (cannot be NULL) + * In: msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + * sec32: the 32-byte private key (cannot be NULL) + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used + * noncedata: pointer to arbitrary data used by the nonce generation + * function (can be NULL) + * + * Do not use the output as a private/public key pair for signing/validation. + */ +SECP256K1_API int secp256k1_schnorr_generate_nonce_pair( + const secp256k1_context* ctx, + secp256k1_pubkey *pubnonce, + unsigned char *privnonce32, + const unsigned char *msg32, + const unsigned char *sec32, + secp256k1_nonce_function noncefp, + const void* noncedata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Produce a partial Schnorr signature, which can be combined using + * secp256k1_schnorr_partial_combine, to end up with a full signature that is + * verifiable using secp256k1_schnorr_verify. + * Returns: 1: signature created successfully. + * 0: no valid signature exists with this combination of keys, nonces + * and message (chance around 1 in 2^128) + * -1: invalid private key, nonce, or public nonces. + * Args: ctx: pointer to context object, initialized for signing (cannot + * be NULL) + * Out: sig64: pointer to 64-byte array to put partial signature in + * In: msg32: pointer to 32-byte message to sign + * sec32: pointer to 32-byte private key + * pubnonce_others: pointer to pubkey containing the sum of the other's + * nonces (see secp256k1_ec_pubkey_combine) + * secnonce32: pointer to 32-byte array containing our nonce + * + * The intended procedure for creating a multiparty signature is: + * - Each signer S[i] with private key x[i] and public key Q[i] runs + * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of + * private/public nonces. + * - All signers communicate their public nonces to each other (revealing your + * private nonce can lead to discovery of your private key, so it should be + * considered secret). + * - All signers combine all the public nonces they received (excluding their + * own) using secp256k1_ec_pubkey_combine to obtain an + * Rall[i] = sum(R[0..i-1,i+1..n]). + * - All signers produce a partial signature using + * secp256k1_schnorr_partial_sign, passing in their own private key x[i], + * their own private nonce k[i], and the sum of the others' public nonces + * Rall[i]. + * - All signers communicate their partial signatures to each other. + * - Someone combines all partial signatures using + * secp256k1_schnorr_partial_combine, to obtain a full signature. + * - The resulting signature is validatable using secp256k1_schnorr_verify, with + * public key equal to the result of secp256k1_ec_pubkey_combine of the + * signers' public keys (sum(Q[0..n])). + * + * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine + * function take their arguments in any order, and it is possible to + * pre-combine several inputs already with one call, and add more inputs later + * by calling the function again (they are commutative and associative). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char *msg32, + const unsigned char *sec32, + const secp256k1_pubkey *pubnonce_others, + const unsigned char *secnonce32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Combine multiple Schnorr partial signatures. + * Returns: 1: the passed signatures were successfully combined. + * 0: the resulting signature is not valid (chance of 1 in 2^256) + * -1: some inputs were invalid, or the signatures were not created + * using the same set of nonces + * Args: ctx: pointer to a context object + * Out: sig64: pointer to a 64-byte array to place the combined signature + * (cannot be NULL) + * In: sig64sin: pointer to an array of n pointers to 64-byte input + * signatures + * n: the number of signatures to combine (at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char * const * sig64sin, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h new file mode 100644 index 0000000000..c4c16eb7ca --- /dev/null +++ b/src/secp256k1/src/basic-config.h @@ -0,0 +1,32 @@ +/********************************************************************** + * 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_ +#define _SECP256K1_BASIC_CONFIG_ + +#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_ diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h index db5f68cee1..3a71b4aafa 100644 --- a/src/secp256k1/src/bench.h +++ b/src/secp256k1/src/bench.h @@ -20,7 +20,9 @@ static double gettimedouble(void) { void print_number(double x) { double y = x; int c = 0; - if (y < 0.0) y = -y; + if (y < 0.0) { + y = -y; + } while (y < 100.0) { y *= 10.0; c++; @@ -35,13 +37,21 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v double max = 0.0; for (i = 0; i < count; i++) { double begin, total; - if (setup) setup(data); + if (setup != NULL) { + setup(data); + } begin = gettimedouble(); benchmark(data); total = gettimedouble() - begin; - if (teardown) teardown(data); - if (total < min) min = total; - if (total > max) max = total; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } sum += total; } printf("%s: min ", name); diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c new file mode 100644 index 0000000000..5a7c6376e0 --- /dev/null +++ b/src/secp256k1/src/bench_ecdh.c @@ -0,0 +1,53 @@ +/********************************************************************** + * 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 <string.h> + +#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_t; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh_t *data = (bench_ecdh_t*)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 + }; + + data->ctx = secp256k1_context_create(0); + 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_t *data = (bench_ecdh_t*)arg; + + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); + } +} + +int main(void) { + bench_ecdh_t data; + + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index a960549b94..7809f5f8cf 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -13,15 +13,17 @@ #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_t scalar_x, scalar_y; - secp256k1_fe_t fe_x, fe_y; - secp256k1_ge_t ge_x, ge_y; - secp256k1_gej_t gej_x, gej_y; - unsigned char data[32]; + 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_t; @@ -51,6 +53,7 @@ void bench_setup(void* arg) { 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) { @@ -95,8 +98,8 @@ void bench_scalar_split(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_scalar_t l, r; - secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x); + 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); } } @@ -193,7 +196,7 @@ void bench_group_double_var(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_double_var(&data->gej_x, &data->gej_x); + secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); } } @@ -202,7 +205,7 @@ void bench_group_add_var(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y); + secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); } } @@ -220,7 +223,7 @@ void bench_group_add_affine_var(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y); + secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); } } @@ -229,7 +232,17 @@ void bench_ecmult_wnaf(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A); + 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_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -265,11 +278,27 @@ void bench_rfc6979_hmac_sha256(void* arg) { secp256k1_rfc6979_hmac_sha256_t rng; for (i = 0; i < 20000; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0); + 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)); + } +} + int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; @@ -278,7 +307,9 @@ int have_flag(int argc, char** argv, char *flag) { return 1; } while (argv != NULL && argv != argm) { - if (strcmp(*argv, flag) == 0) return 1; + if (strcmp(*argv, flag) == 0) { + return 1; + } argv++; } return 0; @@ -309,10 +340,15 @@ int main(int argc, char **argv) { 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, "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); + return 0; } diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c index 56faed11a0..6489378cc6 100644 --- a/src/secp256k1/src/bench_recover.c +++ b/src/secp256k1/src/bench_recover.c @@ -1,15 +1,16 @@ /********************************************************************** - * Copyright (c) 2014 Pieter Wuille * + * 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_t *ctx; + secp256k1_context *ctx; unsigned char msg[32]; unsigned char sig[64]; } bench_recover_t; @@ -17,16 +18,20 @@ typedef struct { void bench_recover(void* arg) { int i; bench_recover_t *data = (bench_recover_t*)arg; - unsigned char pubkey[33]; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; for (i = 0; i < 20000; i++) { int j; - int pubkeylen = 33; - CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); + 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] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ } } } @@ -35,8 +40,12 @@ void bench_recover_setup(void* arg) { int i; bench_recover_t *data = (bench_recover_t*)arg; - for (i = 0; i < 32; i++) data->msg[i] = 1 + i; - for (i = 0; i < 64; i++) data->sig[i] = 65 + i; + 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) { diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c new file mode 100644 index 0000000000..5f137dda23 --- /dev/null +++ b/src/secp256k1/src/bench_schnorr_verify.c @@ -0,0 +1,73 @@ +/********************************************************************** + * 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 <stdio.h> +#include <string.h> + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorr.h" +#include "util.h" +#include "bench.h" + +typedef struct { + unsigned char key[32]; + unsigned char sig[64]; + unsigned char pubkey[33]; + size_t pubkeylen; +} benchmark_schnorr_sig_t; + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + benchmark_schnorr_sig_t sigs[64]; + int numsigs; +} benchmark_schnorr_verify_t; + +static void benchmark_schnorr_init(void* arg) { + int i, k; + benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (k = 0; k < data->numsigs; k++) { + secp256k1_pubkey pubkey; + for (i = 0; i < 32; i++) { + data->sigs[k].key[i] = 33 + i + k; + } + secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL); + data->sigs[k].pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + } +} + +static void benchmark_schnorr_verify(void* arg) { + int i; + benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; + + for (i = 0; i < 20000 / data->numsigs; i++) { + secp256k1_pubkey pubkey; + data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen)); + CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0)); + data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); + } +} + + + +int main(void) { + benchmark_schnorr_verify_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + data.numsigs = 1; + run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, 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 072a37af51..ed7224d757 100644 --- a/src/secp256k1/src/bench_sign.c +++ b/src/secp256k1/src/bench_sign.c @@ -9,7 +9,7 @@ #include "bench.h" typedef struct { - secp256k1_context_t* ctx; + secp256k1_context* ctx; unsigned char msg[32]; unsigned char key[32]; } bench_sign_t; @@ -18,22 +18,28 @@ static void bench_sign_setup(void* arg) { int i; bench_sign_t *data = (bench_sign_t*)arg; - for (i = 0; i < 32; i++) data->msg[i] = i + 1; - for (i = 0; i < 32; i++) data->key[i] = i + 65; + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } } static void bench_sign(void* arg) { int i; bench_sign_t *data = (bench_sign_t*)arg; - unsigned char sig[64]; + unsigned char sig[74]; for (i = 0; i < 20000; i++) { + size_t siglen = 74; int j; - int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); + 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]; /* Move former R to message. */ - data->key[j] = sig[j + 32]; /* Move former S to key. */ + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; } } } diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c index c8c82752ce..5718320cda 100644 --- a/src/secp256k1/src/bench_verify.c +++ b/src/secp256k1/src/bench_verify.c @@ -12,13 +12,13 @@ #include "bench.h" typedef struct { - secp256k1_context_t *ctx; + secp256k1_context *ctx; unsigned char msg[32]; unsigned char key[32]; unsigned char sig[72]; - int siglen; + size_t siglen; unsigned char pubkey[33]; - int pubkeylen; + size_t pubkeylen; } benchmark_verify_t; static void benchmark_verify(void* arg) { @@ -26,10 +26,14 @@ static void benchmark_verify(void* arg) { benchmark_verify_t* data = (benchmark_verify_t*)arg; 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_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); + 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); @@ -38,16 +42,24 @@ static void benchmark_verify(void* arg) { 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; + 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; - secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); + 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_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h index 4ef78e8afb..54ae101b92 100644 --- a/src/secp256k1/src/ecdsa.h +++ b/src/secp256k1/src/ecdsa.h @@ -7,18 +7,15 @@ #ifndef _SECP256K1_ECDSA_ #define _SECP256K1_ECDSA_ +#include <stddef.h> + #include "scalar.h" #include "group.h" #include "ecmult.h" -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_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, 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_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); +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 diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index ed1d228189..d110b4bb1d 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * 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.* **********************************************************************/ @@ -28,7 +28,7 @@ * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' */ -static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( +static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL ); @@ -42,82 +42,150 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CON * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) * '14551231950b75fc4402da1722fc9baee' */ -static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( +static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { - unsigned char ra[32] = {0}, sa[32] = {0}; - const unsigned char *rp; - const unsigned char *sp; - int lenr; - int lens; - int overflow; - if (sig[0] != 0x30) { - return 0; +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; } - lenr = sig[3]; - if (5+lenr >= size) { - return 0; + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; } - lens = sig[lenr+5]; - if (sig[1] != lenr+lens+4) { - return 0; + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; } - if (lenr+lens+6 > size) { - return 0; + 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) { + if ((ret >> ((sizeof(size_t) - 1) * 8)) != 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; } - if (sig[2] != 0x02) { + return ret; +} + +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; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ return 0; } - if (lenr == 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[lenr+4] != 0x02) { + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ return 0; } - if (lens == 0) { + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ return 0; } - sp = sig + 6 + lenr; - while (lens > 0 && sp[0] == 0) { - lens--; - sp++; + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; } - if (lens > 32) { + 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 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; } - rp = sig + 4; - while (lenr > 0 && rp[0] == 0) { - lenr--; - rp++; + rlen = secp256k1_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ + return 0; } - if (lenr > 32) { + if (sig + rlen != sigend) { + /* Garbage after tuple. */ return 0; } - memcpy(ra + 32 - lenr, rp, lenr); - memcpy(sa + 32 - lens, sp, lens); - overflow = 0; - secp256k1_scalar_set_b32(&r->r, ra, &overflow); - if (overflow) { + + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { return 0; } - secp256k1_scalar_set_b32(&r->s, sa, &overflow); - if (overflow) { + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { return 0; } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + 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}; unsigned char *rp = r, *sp = s; - int lenR = 33, lenS = 33; - secp256k1_scalar_get_b32(&r[1], &a->r); - secp256k1_scalar_get_b32(&s[1], &a->s); + 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) { + *size = 6 + lenS + lenR; return 0; } *size = 6 + lenS + lenR; @@ -132,26 +200,26 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { +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_t sn, u1, u2; - secp256k1_fe_t xr; - secp256k1_gej_t pubkeyj; - secp256k1_gej_t pr; + secp256k1_scalar sn, u1, u2; + secp256k1_fe xr; + secp256k1_gej pubkeyj; + secp256k1_gej pr; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { return 0; } - 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_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; } - secp256k1_scalar_get_b32(c, &sig->r); + secp256k1_scalar_get_b32(c, sigr); secp256k1_fe_set_b32(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) @@ -171,11 +239,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. */ if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */ + /* 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 + p >= n, so we can skip testing the second case. */ + /* xr + n >= p, so we can skip testing the second case. */ return 0; } secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); @@ -186,44 +254,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con return 0; } -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { - unsigned char brx[32]; - secp256k1_fe_t fx; - secp256k1_ge_t x; - secp256k1_gej_t xj; - secp256k1_scalar_t rn, u1, u2; - secp256k1_gej_t qj; - - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { - return 0; - } - - secp256k1_scalar_get_b32(brx, &sig->r); - 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_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, &sig->r); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, &sig->s); - secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); -} - -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, 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_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_t rp; - secp256k1_ge_t r; - secp256k1_scalar_t n; + secp256k1_gej rp; + secp256k1_ge r; + secp256k1_scalar n; int overflow = 0; secp256k1_ecmult_gen(ctx, &rp, nonce); @@ -231,28 +266,33 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); - secp256k1_scalar_set_b32(&sig->r, b, &overflow); - if (secp256k1_scalar_is_zero(&sig->r)) { - /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ + secp256k1_scalar_set_b32(sigr, b, &overflow); + if (secp256k1_scalar_is_zero(sigr)) { + /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. + * This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. + */ secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); return 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_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 (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); if (recid) { *recid ^= 1; } diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h index 53b818485e..42739a3bea 100644 --- a/src/secp256k1/src/eckey.h +++ b/src/secp256k1/src/eckey.h @@ -7,20 +7,19 @@ #ifndef _SECP256K1_ECKEY_ #define _SECP256K1_ECKEY_ +#include <stddef.h> + #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(const secp256k1_ecmult_gen_context_t *ctx, 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(const secp256k1_ecmult_context_t *ctx, 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(const secp256k1_ecmult_context_t *ctx, 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 diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h index a332bd34ec..ce38071ac2 100644 --- a/src/secp256k1/src/eckey_impl.h +++ b/src/secp256k1/src/eckey_impl.h @@ -14,12 +14,12 @@ #include "group.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_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { - secp256k1_fe_t x; + secp256k1_fe x; return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); } 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; } @@ -33,7 +33,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned cha } } -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; } @@ -51,110 +51,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char return 1; } -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) { - unsigned char c[32] = {0}; - const unsigned char *end = privkey + privkeylen; - int lenb = 0; - int len = 0; - int overflow = 0; - /* 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(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(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { - secp256k1_gej_t rp; - secp256k1_ge_t r; - int pubkeylen = 0; - secp256k1_ecmult_gen(ctx, &rp, key); - 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); - 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); - 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)) { return 0; @@ -162,9 +59,9 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp return 1; } -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_gej_t pt; - secp256k1_scalar_t one; +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_set_int(&one, 1); secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); @@ -176,7 +73,7 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ct return 1; } -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { if (secp256k1_scalar_is_zero(tweak)) { return 0; } @@ -185,9 +82,9 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp return 1; } -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_scalar_t zero; - secp256k1_gej_t pt; +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; } diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index bab9e4ef52..20484134f5 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -12,20 +12,20 @@ typedef struct { /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */ + secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ #ifdef USE_ENDOMORPHISM - secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */ + secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ #endif -} secp256k1_ecmult_context_t; +} secp256k1_ecmult_context; -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src); -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); +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(const secp256k1_ecmult_context_t *ctx, 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 diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h new file mode 100644 index 0000000000..2b0097655c --- /dev/null +++ b/src/secp256k1/src/ecmult_const.h @@ -0,0 +1,15 @@ +/********************************************************************** + * 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_ +#define _SECP256K1_ECMULT_CONST_ + +#include "scalar.h" +#include "group.h" + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); + +#endif diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 0000000000..90ac94770e --- /dev/null +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,260 @@ +/********************************************************************** + * 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_ +#define _SECP256K1_ECMULT_CONST_IMPL_ + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) + +/* 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..return_val) + * with 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 returned; this is always (WNAF_BITS + w - 1) / w + * + * 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 global_sign; + int skew = 0; + int word = 0; + /* 1 2 3 */ + int u_last; + int u; + +#ifdef USE_ENDOMORPHISM + int flip; + int bit; + secp256k1_scalar neg_s; + int not_neg_one; + /* If we are using the endomorphism, we cannot handle even numbers by negating + * them, since we are working with 128-bit numbers whose negations would be 256 + * bits, eliminating the performance advantage. 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, then compensating after the + * multiplication. */ + /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */ + flip = secp256k1_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + bit = flip ^ (s.d[0] & 1); + /* 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; +#else + /* Otherwise, we just negate to force oddness */ + int is_even = secp256k1_scalar_is_even(&s); + global_sign = secp256k1_scalar_cond_negate(&s, is_even); +#endif + + /* 4 */ + u_last = secp256k1_scalar_shr_int(&s, w); + while (word * w < WNAF_BITS) { + 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(w)); + return skew; +} + + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; + +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_1; + int skew_lam; + secp256k1_scalar q_1, q_lam; +#else + int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)]; +#endif + + int i; + secp256k1_scalar sc = *scalar; + + /* build wnaf representation for q. */ +#ifdef USE_ENDOMORPHISM + /* 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); + /* no need for zero correction when using endomorphism since even + * numbers have one added to them anyway */ + skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); + skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); +#else + int is_zero = secp256k1_scalar_is_zero(scalar); + /* the wNAF ladder cannot handle zero, so bump this to one .. we will + * correct the result after the fact */ + sc.d[0] += is_zero; + VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc)); + + secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1); +#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 + 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) */ +#ifdef USE_ENDOMORPHISM + i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); + + i = wnaf_lam[WNAF_SIZE(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); +#else + i = wnaf[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE(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); + } +#ifdef USE_ENDOMORPHISM + 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); + + 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); +#else + n = wnaf[i]; + VERIFY_CHECK(n != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + } + + secp256k1_fe_mul(&r->z, &r->z, &Z); + +#ifdef USE_ENDOMORPHISM + { + /* Correct for wNAF skew */ + secp256k1_ge correction = *a; + secp256k1_ge_storage correction_1_stor; + secp256k1_ge_storage correction_lam_stor; + 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); + secp256k1_ge_to_storage(&correction_lam_stor, a); + 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); + secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); + + /* Apply the correction */ + secp256k1_ge_from_storage(&correction, &correction_1_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + + 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); + } +#else + /* correct for zero */ + r->infinity |= is_zero; +#endif +} + +#endif diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index 3745633c47..eb2cc9ead6 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -23,21 +23,21 @@ typedef struct { * 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_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ - secp256k1_scalar_t blind; - secp256k1_gej_t initial; -} secp256k1_ecmult_gen_context_t; + 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_t* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t* src); -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); +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(const secp256k1_ecmult_gen_context_t* ctx, 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_t *ctx, const unsigned char *seed32); +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); #endif diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 4697753ac8..b63c4d8662 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -11,22 +11,26 @@ #include "group.h" #include "ecmult_gen.h" #include "hash_impl.h" - -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) { +#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; } -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) { - secp256k1_ge_t prec[1024]; - secp256k1_gej_t gj; - secp256k1_gej_t nums_gej; +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 if (ctx->prec != NULL) { return; } - - ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); @@ -34,77 +38,93 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ { static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - secp256k1_fe_t nums_x; - secp256k1_ge_t nums_ge; - VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); - VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); + secp256k1_fe nums_x; + secp256k1_ge nums_ge; + int r; + r = secp256k1_fe_set_b32(&nums_x, nums_b32); + (void)r; + VERIFY_CHECK(r); + r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); + (void)r; + VERIFY_CHECK(r); secp256k1_gej_set_ge(&nums_gej, &nums_ge); /* Add G to make the bits in x uniformly distributed. */ - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g); + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); } /* compute prec. */ { - secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */ - secp256k1_gej_t gbase; - secp256k1_gej_t numsbase; + 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 (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase); + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); } /* Multiply gbase by 16. */ for (i = 0; i < 4; i++) { - secp256k1_gej_double_var(&gbase, &gbase); + 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(1024, prec, precj, cb); } 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); } -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) { +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { return ctx->prec != NULL; } -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t *src) { +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 { - dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); +#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; } } -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { +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(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { - secp256k1_ge_t add; - secp256k1_ge_storage_t adds; - secp256k1_scalar_t gnb; +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { + secp256k1_ge add; + secp256k1_ge_storage adds; + secp256k1_scalar gnb; int bits; int i, j; memset(&adds, 0, sizeof(adds)); @@ -136,14 +156,15 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp } /* Setup blinding values for secp256k1_ecmult_gen. */ -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) { - secp256k1_scalar_t b; - secp256k1_gej_t gb; - secp256k1_fe_t s; +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_t rng; int retry; - if (!seed32) { + 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); @@ -155,13 +176,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons * 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. */ - secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0); + 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); + } 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); @@ -170,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons 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); + } 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); diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index 1b2856f83d..e6e5f47188 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -24,62 +24,107 @@ #define WINDOW_G 16 #endif -/** 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. - * - * 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. +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) + +/** 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_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) { - secp256k1_gej_t d; +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; - pre[0] = *a; - secp256k1_gej_double_var(&d, &pre[0]); - for (i = 1; i < (1 << (w-2)); i++) { - secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]); + + 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. + * + * There are two versions of this function: + * - 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_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_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) { - secp256k1_gej_t d; +static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n); + secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n); + secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n); int i; - const int table_size = 1 << (w-2); - secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size); - secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size); - prej[0] = *a; - secp256k1_gej_double_var(&d, a); - for (i = 1; i < table_size; i++) { - secp256k1_gej_add_var(&prej[i], &d, &prej[i-1]); - } - secp256k1_ge_set_all_gej_var(table_size, prea, prej); - for (i = 0; i < table_size; i++) { + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); + /* Convert them in batch to affine coordinates. */ + secp256k1_ge_set_table_gej_var(n, prea, prej, zr); + /* Convert them to compact storage form. */ + for (i = 0; i < n; i++) { secp256k1_ge_to_storage(&pre[i], &prea[i]); } - free(prej); + free(prea); + free(prej); + free(zr); } -/** The number of entries a table with precomputed multiples needs to have. */ -#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) - /** The following two macro retrieves a particular odd multiple from a table * of precomputed multiples. */ -#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) do { \ +#define ECMULT_TABLE_GET_GE(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) { \ *(r) = (pre)[((n)-1)/2]; \ } else { \ - secp256k1_gej_neg((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ } \ } while(0) + #define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ @@ -92,15 +137,15 @@ static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t } \ } while(0) -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { ctx->pre_g = NULL; #ifdef USE_ENDOMORPHISM ctx->pre_g_128 = NULL; #endif } -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { - secp256k1_gej_t gj; +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { + secp256k1_gej gj; if (ctx->pre_g != NULL) { return; @@ -109,35 +154,35 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + 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_storage_var(*ctx->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_gej_t g_128j; + secp256k1_gej g_128j; int i; - ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + 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); + secp256k1_gej_double_var(&g_128j, &g_128j, NULL); } - secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); } #endif } -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src) { +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_t (*)[])checked_malloc(size); + dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); memcpy(dst->pre_g, src->pre_g, size); } #ifdef USE_ENDOMORPHISM @@ -145,17 +190,17 @@ static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, 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_t (*)[])checked_malloc(size); + dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); memcpy(dst->pre_g_128, src->pre_g_128, size); } #endif } -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) { +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { return ctx->pre_g != NULL; } -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { free(ctx->pre_g); #ifdef USE_ENDOMORPHISM free(ctx->pre_g_128); @@ -168,54 +213,68 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { * - 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; - int set_bits = 0; +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; } - while (bit < 256) { + while (bit < len) { int now; int word; - if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) { + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { bit++; continue; } - while (set_bits < bit) { - wnaf[set_bits++] = 0; - } + now = w; - if (bit + now > 256) { - now = 256 - bit; - } - 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; + 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(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { - secp256k1_gej_t tmpj; - secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge_t tmpa; +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_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; #ifdef USE_ENDOMORPHISM - secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_scalar_t na_1, na_lam; + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_scalar na_1, na_lam; /* Splitted G factors. */ - secp256k1_scalar_t ng_1, ng_128; + secp256k1_scalar ng_1, ng_128; int wnaf_na_1[130]; int wnaf_na_lam[130]; int bits_na_1; @@ -227,7 +286,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #else int wnaf_na[256]; int bits_na; - int wnaf_ng[257]; + int wnaf_ng[256]; int bits_ng; #endif int i; @@ -235,11 +294,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #ifdef USE_ENDOMORPHISM /* 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_scalar_split_lambda(&na_1, &na_lam, na); /* build wnaf representation for na_1 and na_lam. */ - bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); - bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); + bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); + bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); VERIFY_CHECK(bits_na_1 <= 130); VERIFY_CHECK(bits_na_lam <= 130); bits = bits_na_1; @@ -248,24 +307,33 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge } #else /* build wnaf representation for na. */ - bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); + bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); bits = bits_na; #endif - /* calculate odd multiples of a */ - secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A); + /* 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. + */ + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a); #ifdef USE_ENDOMORPHISM for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]); + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } /* 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, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); + 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; } @@ -273,7 +341,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge bits = bits_ng_128; } #else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); if (bits_ng > bits) { bits = bits_ng; } @@ -281,37 +349,41 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge secp256k1_gej_set_infinity(r); - for (i = bits-1; i >= 0; i--) { + for (i = bits - 1; i >= 0; i--) { int n; - secp256k1_gej_double_var(r, r); + 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); + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } 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); + ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, 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_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + 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); + ECMULT_TABLE_GET_GE(&tmpa, pre_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_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } #endif } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } } #endif diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h index 41b280892d..2d52af5e36 100644 --- a/src/secp256k1/src/field.h +++ b/src/secp256k1/src/field.h @@ -10,7 +10,7 @@ /** 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 @@ -31,89 +31,91 @@ #endif /** Normalize a field element. */ -static void secp256k1_fe_normalize(secp256k1_fe_t *r); +static void secp256k1_fe_normalize(secp256k1_fe *r); /** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r); +static void secp256k1_fe_normalize_weak(secp256k1_fe *r); /** Normalize a field element, without constant-time guarantee. */ -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r); +static void secp256k1_fe_normalize_var(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(secp256k1_fe_t *r); +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_t *r); +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); /** 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 magnitude-1 inputs. */ -static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +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); -/** 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_var(secp256k1_fe_t *r, const secp256k1_fe_t *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_var(secp256k1_fe *r, 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_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a); /** Convert a field element to the storage type. */ -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*); +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); /** Convert a field element back from the storage type. */ -static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*); +static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag); +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 diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h index 44bce6525d..61ee1e0965 100644 --- a/src/secp256k1/src/field_10x26.h +++ b/src/secp256k1/src/field_10x26.h @@ -16,20 +16,20 @@ 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, \ - ((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \ - ((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \ - ((d2) >> 14) | ((d3) & 0xFFUL) << 18, \ - ((d3) >> 8) | ((d4) & 0x3) << 24, \ - ((d4) >> 2) & 0x3FFFFFFUL, \ - ((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \ - ((d5) >> 22) | ((d6) & 0xFFFF) << 10, \ - ((d6) >> 16) | ((d7) & 0x3FF) << 16, \ - ((d7) >> 10) \ + (((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 @@ -40,8 +40,8 @@ typedef struct { typedef struct { uint32_t n[8]; -} secp256k1_fe_storage_t; +} 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 diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h index 871b91f912..212cc5396a 100644 --- a/src/secp256k1/src/field_10x26_impl.h +++ b/src/secp256k1/src/field_10x26_impl.h @@ -14,7 +14,7 @@ #include "field.h" #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); @@ -41,12 +41,12 @@ 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) { +static void secp256k1_fe_verify(const secp256k1_fe *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]; @@ -101,7 +101,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { +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]; @@ -132,7 +132,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { +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]; @@ -188,7 +188,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { +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]; @@ -217,7 +217,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { +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; @@ -252,7 +252,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { t9 &= 0x03FFFFFUL; t1 += (x << 6); - t1 += (t0 >> 26); t0 = z0; + 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; @@ -269,7 +269,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +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 @@ -279,7 +279,7 @@ 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); @@ -288,7 +288,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { 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); @@ -296,7 +296,7 @@ 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; @@ -307,7 +307,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -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); @@ -326,7 +326,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { int i; 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; @@ -350,7 +350,7 @@ 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) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -368,7 +368,7 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { } } -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); @@ -390,7 +390,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; @@ -408,7 +408,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 @@ -1039,7 +1039,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t } -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); @@ -1055,7 +1055,7 @@ 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); @@ -1068,7 +1068,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { +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; @@ -1083,12 +1083,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { +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; @@ -1102,7 +1104,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); #endif @@ -1116,7 +1118,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { +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); diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h index 4513d36f49..8e69a560dc 100644 --- a/src/secp256k1/src/field_5x52.h +++ b/src/secp256k1/src/field_5x52.h @@ -16,15 +16,15 @@ 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, \ - ((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \ - ((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \ - ((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \ - ((d6) >> 16) | ((uint64_t)(d7)) << 16 \ + (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 @@ -35,13 +35,13 @@ typedef struct { typedef struct { uint64_t n[4]; -} secp256k1_fe_storage_t; +} 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 \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ }} #endif diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h index bda4c3dfc2..b31e24ab81 100644 --- a/src/secp256k1/src/field_5x52_impl.h +++ b/src/secp256k1/src/field_5x52_impl.h @@ -31,7 +31,7 @@ */ #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. */ @@ -51,12 +51,12 @@ 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) { +static void secp256k1_fe_verify(const secp256k1_fe *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 */ @@ -99,7 +99,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { +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 */ @@ -123,7 +123,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { +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 */ @@ -167,7 +167,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { +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 */ @@ -190,7 +190,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { +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; @@ -219,7 +219,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { t4 &= 0x0FFFFFFFFFFFFULL; - t1 += (t0 >> 52); t0 = z0; + 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; @@ -231,7 +231,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +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 @@ -241,7 +241,7 @@ 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); @@ -250,7 +250,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { 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); @@ -258,7 +258,7 @@ 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; @@ -269,7 +269,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -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); @@ -288,7 +288,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { int i; r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; for (i=0; i<32; i++) { @@ -311,7 +311,7 @@ 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) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -329,7 +329,7 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { } } -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); @@ -346,7 +346,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; @@ -359,7 +359,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 @@ -375,7 +375,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); @@ -391,7 +391,7 @@ 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); @@ -404,7 +404,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { +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; @@ -414,12 +414,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { +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; @@ -429,7 +431,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); #endif @@ -439,7 +441,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { +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); diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index e6ec11e8f2..77f4aae2f9 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/src/field_impl.h @@ -21,15 +21,24 @@ #error "Please select field implementation" #endif -SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t na; +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_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; +static int secp256k1_fe_sqrt_var(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 @@ -117,8 +126,8 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { return secp256k1_fe_equal_var(&t1, a); } -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; +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 @@ -207,11 +216,15 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { 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_t n, m; + 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, @@ -220,21 +233,28 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F }; unsigned char b[32]; - secp256k1_fe_t c = *a; + int res; + 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); 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_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t u; +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe u; size_t i; if (len < 1) { return; @@ -252,7 +272,7 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25 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]); } diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c new file mode 100644 index 0000000000..1835fd491d --- /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 \"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 0b08b3b991..ebfe1ca70c 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -12,110 +12,130 @@ /** 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; +} secp256k1_gej; #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} typedef struct { - secp256k1_fe_storage_t x; - secp256k1_fe_storage_t y; -} secp256k1_ge_storage_t; + secp256k1_fe_storage x; + secp256k1_fe_storage y; +} secp256k1_ge_storage; #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_var(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_var(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_var(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); +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, const secp256k1_gej_t *a); +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, 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(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr); -/** 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 (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); /** Compare the X coordinate of a group element (jacobian). */ -static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a); +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); -/** 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); + +/** 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); /** Convert a group element to the storage type. */ -static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t*); +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_t *r, const secp256k1_ge_storage_t*); +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_t *r, const secp256k1_ge_storage_t *a, int flag); +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_t *r, const secp256k1_fe_t *b); +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); #endif diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index 0f64576fbb..42e2f6e6eb 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -16,35 +16,41 @@ /** Generator for secp256k1, value 'g' defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ -static const secp256k1_ge_t secp256k1_ge_const_g = SECP256K1_GE_CONST( +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 ); -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) { - r->infinity = 1; +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) { +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_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { - secp256k1_fe_t z2, z3; +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_sqr(&z2, &a->z); @@ -56,8 +62,8 @@ 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) { - secp256k1_fe_t z2, z3; +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; @@ -72,19 +78,19 @@ 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, const secp256k1_gej_t *a) { - secp256k1_fe_t *az; - secp256k1_fe_t *azi; +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_fe *az; + secp256k1_fe *azi; size_t i; size_t count = 0; - az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len); + az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len); for (i = 0; i < len; i++) { if (!a[i].infinity) { az[count++] = a[i].z; } } - azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count); + azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); secp256k1_fe_inv_all_var(count, azi, az); free(az); @@ -92,53 +98,86 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const se for (i = 0; i < len; i++) { r[i].infinity = a[i].infinity; if (!a[i].infinity) { - secp256k1_fe_t zi2, zi3; - secp256k1_fe_t *zi = &azi[count++]; - secp256k1_fe_sqr(&zi2, zi); - secp256k1_fe_mul(&zi3, &zi2, zi); - secp256k1_fe_mul(&r[i].x, &a[i].x, &zi2); - secp256k1_fe_mul(&r[i].y, &a[i].y, &zi3); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); } } free(azi); } -static void secp256k1_gej_set_infinity(secp256k1_gej_t *r) { +static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zi; + + if (len > 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); } -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_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_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) { - secp256k1_fe_t x2, x3, c; +static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) { + secp256k1_fe x2, x3, c; r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; secp256k1_fe_set_int(&c, 7); secp256k1_fe_add(&c, &x3); - if (!secp256k1_fe_sqrt_var(&r->y, &c)) { + return secp256k1_fe_sqrt_var(&r->y, &c); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + if (!secp256k1_ge_set_xquad_var(r, x)) { return 0; } secp256k1_fe_normalize_var(&r->y); @@ -146,24 +185,25 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, i 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 int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) { - secp256k1_fe_t r, r2; +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; @@ -172,12 +212,12 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { 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_var(const secp256k1_gej_t *a) { - secp256k1_fe_t y2, x3, z2, z6; +static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { + secp256k1_fe y2, x3, z2, z6; if (a->infinity) { return 0; } @@ -196,8 +236,8 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { return secp256k1_fe_equal_var(&y2, &x3); } -static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { - secp256k1_fe_t y2, x3, c; +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { + secp256k1_fe y2, x3, c; if (a->infinity) { return 0; } @@ -210,18 +250,27 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { return secp256k1_fe_equal_var(&y2, &x3); } -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { +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 */ - secp256k1_fe_t t1,t2,t3,t4; + 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. */ r->infinity = a->infinity; if (r->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } return; } + 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); @@ -244,17 +293,29 @@ 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_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + 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_sqr(&z22, &b->z); secp256k1_fe_sqr(&z12, &a->z); @@ -266,8 +327,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, 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); + secp256k1_gej_double_var(r, a, rzr); } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } r->infinity = 1; } return; @@ -275,7 +339,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_sqr(&i2, &i); secp256k1_fe_sqr(&h2, &h); 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_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); @@ -283,21 +351,23 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, 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_t z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + 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_sqr(&z12, &a->z); u1 = a->x; secp256k1_fe_normalize_weak(&u1); secp256k1_fe_mul(&u2, &b->x, &z12); @@ -307,7 +377,69 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * 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); + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + 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; } @@ -324,11 +456,13 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * 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) { - /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */ - static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr; - int infinity; + +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); @@ -352,53 +486,102 @@ 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_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*Z2^2 (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) */ - z = a->z; /* z = Z = Z1*Z2 (8) */ 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(&n, &m); /* n = M^2 (1) */ - secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */ - secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */ 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_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 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */ - r->x = t; /* r->x = R^2 (1) */ + 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_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 * (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) */ + 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, the above code results in r->x, r->y, and r->z all equal to 0. - * Replace r with b->x, b->y, 1 in that case. - */ + /** 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_t *r, const secp256k1_fe_t *s) { +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ - secp256k1_fe_t zz; + 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 */ @@ -407,8 +590,8 @@ static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ } -static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) { - secp256k1_fe_t x, y; +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); @@ -418,20 +601,20 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_g secp256k1_fe_to_storage(&r->y, &y); } -static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) { +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 SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag) { +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) { - static const secp256k1_fe_t beta = SECP256K1_FE_CONST( +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 ); diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h index 843423d7f7..0ff01e63fa 100644 --- a/src/secp256k1/src/hash.h +++ b/src/secp256k1/src/hash.h @@ -34,7 +34,7 @@ typedef struct { int retry; } secp256k1_rfc6979_hmac_sha256_t; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h index 9828827bcd..ae55df6d8a 100644 --- a/src/secp256k1/src/hash_impl.h +++ b/src/secp256k1/src/hash_impl.h @@ -202,7 +202,7 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen) { +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { secp256k1_hmac_sha256_t hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -215,11 +215,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 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_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -230,11 +225,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 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_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); 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 0000000000..670b9c1152 --- /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) +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 0000000000..c23e4f82f7 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,54 @@ +/********************************************************************** + * 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_ +#define _SECP256K1_MODULE_ECDH_MAIN_ + +#include "include/secp256k1_ecdh.h" +#include "ecmult_const_impl.h" + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_gej res; + secp256k1_ge pt; + secp256k1_scalar s; + ARG_CHECK(result != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + 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[1]; + secp256k1_sha256_t sha; + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + /* Compute a hash of the point in compressed form + * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not + * expect its output to be secret and has a timing sidechannel. */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, y, sizeof(y)); + secp256k1_sha256_write(&sha, x, sizeof(x)); + secp256k1_sha256_finalize(&sha, result); + ret = 1; + } + + secp256k1_scalar_clear(&s); + return ret; +} + +#endif 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 0000000000..7badc9033f --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,75 @@ +/********************************************************************** + * 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_ +#define _SECP256K1_MODULE_ECDH_TESTS_ + +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_t sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[32]; + unsigned char output_ser[32]; + unsigned char point_ser[33]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_scalar s; + + random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + /* compute using ECDH function */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + CHECK(point_ser_len == sizeof(point_ser)); + 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, sizeof(output_ser)) == 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) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); +} + +void run_ecdh_tests(void) { + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif 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 0000000000..5de3ea33ea --- /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) +endif diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h new file mode 100644 index 0000000000..ec42f4bb6c --- /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_ +#define _SECP256K1_MODULE_RECOVERY_MAIN_ + +#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 int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { + break; + } + } + count++; + } + 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); + ARG_CHECK(recid >= 0 && recid < 4); + 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 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 0000000000..8932d5f0af --- /dev/null +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,250 @@ +/********************************************************************** + * 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_ +#define _SECP256K1_MODULE_RECOVERY_TESTS_ + +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 < 64*count; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include new file mode 100644 index 0000000000..b3bfa7d5cc --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include @@ -0,0 +1,10 @@ +include_HEADERS += include/secp256k1_schnorr.h +noinst_HEADERS += src/modules/schnorr/main_impl.h +noinst_HEADERS += src/modules/schnorr/schnorr.h +noinst_HEADERS += src/modules/schnorr/schnorr_impl.h +noinst_HEADERS += src/modules/schnorr/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_schnorr_verify +bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c +bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) +endif diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h new file mode 100644 index 0000000000..fa176a1767 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/main_impl.h @@ -0,0 +1,164 @@ +/********************************************************************** + * 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.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORR_MAIN +#define SECP256K1_MODULE_SCHNORR_MAIN + +#include "include/secp256k1_schnorr.h" +#include "modules/schnorr/schnorr_impl.h" + +static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { + secp256k1_sha256_t sha; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, r32, 32); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, h32); +} + +static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; + +int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar sec, non; + int ret = 0; + int overflow = 0; + unsigned int count = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) { + break; + } + } + count++; + } + if (!ret) { + memset(sig64, 0, 64); + } + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_pubkey_load(ctx, &q, pubkey); + return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); +} + +int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) { + secp256k1_ge q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pubkey != NULL); + + if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) { + int count = 0; + int ret = 1; + secp256k1_gej Qj; + secp256k1_ge Q; + secp256k1_scalar sec; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sec32 != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(privnonce32 != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + do { + int overflow; + ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&sec, privnonce32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&sec)) { + continue; + } + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec); + secp256k1_ge_set_gej(&Q, &Qj); + + secp256k1_pubkey_save(pubnonce, &Q); + break; + } while(1); + + secp256k1_scalar_clear(&sec); + if (!ret) { + memset(pubnonce, 0, sizeof(*pubnonce)); + } + return ret; +} + +int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) { + int overflow = 0; + secp256k1_scalar sec, non; + secp256k1_ge pubnon; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(sec32 != NULL); + ARG_CHECK(secnonce32 != NULL); + ARG_CHECK(pubnonce_others != NULL); + + secp256k1_scalar_set_b32(&sec, sec32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&sec)) { + return -1; + } + secp256k1_scalar_set_b32(&non, secnonce32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&non)) { + return -1; + } + secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others); + return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32); +} + +int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) { + ARG_CHECK(sig64 != NULL); + ARG_CHECK(n >= 1); + ARG_CHECK(sig64sin != NULL); + return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr.h b/src/secp256k1/src/modules/schnorr/schnorr.h new file mode 100644 index 0000000000..de18147bd5 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr.h @@ -0,0 +1,20 @@ +/*********************************************************************** + * 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. * + ***********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORR_H_ +#define _SECP256K1_MODULE_SCHNORR_H_ + +#include "scalar.h" +#include "group.h" + +typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins); + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h new file mode 100644 index 0000000000..e13ab6db7c --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h @@ -0,0 +1,207 @@ +/*********************************************************************** + * 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. * + ***********************************************************************/ + +#ifndef _SECP256K1_SCHNORR_IMPL_H_ +#define _SECP256K1_SCHNORR_IMPL_H_ + +#include <string.h> + +#include "schnorr.h" +#include "num.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +/** + * Custom Schnorr-based signature scheme. They support multiparty signing, public key + * recovery and batch validation. + * + * Rationale for verifying R's y coordinate: + * In order to support batch validation and public key recovery, the full R point must + * be known to verifiers, rather than just its x coordinate. In order to not risk + * being more strict in batch validation than normal validation, validators must be + * required to reject signatures with incorrect y coordinate. This is only possible + * by including a (relatively slow) field inverse, or a field square root. However, + * batch validation offers potentially much higher benefits than this cost. + * + * Rationale for having an implicit y coordinate oddness: + * If we commit to having the full R point known to verifiers, there are two mechanism. + * Either include its oddness in the signature, or give it an implicit fixed value. + * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the + * latter, as it comes with nearly zero impact on signing or validation performance, and + * saves a byte in the signature. + * + * Signing: + * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) + * + * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). + * Compute 32-byte r, the serialization of R's x coordinate. + * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. + * Compute scalar s = k - h * x. + * The signature is (r, s). + * + * + * Verification: + * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) + * + * Signature is invalid if s >= order. + * Signature is invalid if r >= p. + * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. + * Option 1 (faster for single verification): + * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. + * Signature is valid if the serialization of R's x coordinate equals r. + * Option 2 (allows batch validation and pubkey recovery): + * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. + * Signature is valid if R + h * Q + s * G == 0. + */ + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Rj; + secp256k1_ge Ra; + unsigned char h32[32]; + secp256k1_scalar h, s; + int overflow; + secp256k1_scalar n; + + if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { + return 0; + } + n = *nonce; + + secp256k1_ecmult_gen(ctx, &Rj, &n); + if (pubnonce != NULL) { + secp256k1_gej_add_ge(&Rj, &Rj, pubnonce); + } + secp256k1_ge_set_gej(&Ra, &Rj); + secp256k1_fe_normalize(&Ra.y); + if (secp256k1_fe_is_odd(&Ra.y)) { + /* R's y coordinate is odd, which is not allowed (see rationale above). + Force it to be even by negating the nonce. Note that this even works + for multiparty signing, as the R point is known to all participants, + which can all decide to flip the sign in unison, resulting in the + overall R point to be negated too. */ + secp256k1_scalar_negate(&n, &n); + } + secp256k1_fe_normalize(&Ra.x); + secp256k1_fe_get_b32(sig64, &Ra.x); + hash(h32, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, h32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + secp256k1_scalar_clear(&n); + return 0; + } + secp256k1_scalar_mul(&s, &h, key); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_add(&s, &s, &n); + secp256k1_scalar_clear(&n); + secp256k1_scalar_get_b32(sig64 + 32, &s); + return 1; +} + +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Qj, Rj; + secp256k1_ge Ra; + secp256k1_fe Rx; + secp256k1_scalar h, s; + unsigned char hh[32]; + int overflow; + + if (secp256k1_ge_is_infinity(pubkey)) { + return 0; + } + hash(hh, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, hh, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + return 0; + } + overflow = 0; + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_fe_set_b32(&Rx, sig64)) { + return 0; + } + secp256k1_gej_set_ge(&Qj, pubkey); + secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); + if (secp256k1_gej_is_infinity(&Rj)) { + return 0; + } + secp256k1_ge_set_gej_var(&Ra, &Rj); + secp256k1_fe_normalize_var(&Ra.y); + if (secp256k1_fe_is_odd(&Ra.y)) { + return 0; + } + return secp256k1_fe_equal_var(&Rx, &Ra.x); +} + +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Qj, Rj; + secp256k1_ge Ra; + secp256k1_fe Rx; + secp256k1_scalar h, s; + unsigned char hh[32]; + int overflow; + + hash(hh, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, hh, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + return 0; + } + overflow = 0; + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_fe_set_b32(&Rx, sig64)) { + return 0; + } + if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { + return 0; + } + secp256k1_gej_set_ge(&Rj, &Ra); + secp256k1_scalar_inverse_var(&h, &h); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_mul(&s, &s, &h); + secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(pubkey, &Qj); + return 1; +} + +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) { + secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + size_t i; + for (i = 0; i < n; i++) { + secp256k1_scalar si; + int overflow; + secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow); + if (overflow) { + return -1; + } + if (i) { + if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) { + return -1; + } + } + secp256k1_scalar_add(&s, &s, &si); + } + if (secp256k1_scalar_is_zero(&s)) { + return 0; + } + memcpy(sig64, sig64ins[0], 32); + secp256k1_scalar_get_b32(sig64 + 32, &s); + secp256k1_scalar_clear(&s); + return 1; +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h new file mode 100644 index 0000000000..5bd14a03e3 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/tests_impl.h @@ -0,0 +1,175 @@ +/********************************************************************** + * 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.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORR_TESTS +#define SECP256K1_MODULE_SCHNORR_TESTS + +#include "include/secp256k1_schnorr.h" + +void test_schnorr_end_to_end(void) { + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char schnorr_signature[64]; + secp256k1_pubkey pubkey, recpubkey; + + /* Generate a random key and message. */ + { + secp256k1_scalar key; + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_rand256_test(message); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Schnorr sign. */ + CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); + CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Destroy signature and verify again. */ + schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); + CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/** Horribly broken hash function. Do not use for anything but tests. */ +void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { + int i; + for (i = 0; i < 32; i++) { + h32[i] = r32[i] ^ msg32[i]; + } +} + +void test_schnorr_sign_verify(void) { + unsigned char msg32[32]; + unsigned char sig64[3][64]; + secp256k1_gej pubkeyj[3]; + secp256k1_ge pubkey[3]; + secp256k1_scalar nonce[3], key[3]; + int i = 0; + int k; + + secp256k1_rand256_test(msg32); + + for (k = 0; k < 3; k++) { + random_scalar_order_test(&key[k]); + + do { + random_scalar_order_test(&nonce[k]); + if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { + break; + } + } while(1); + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); + secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); + + for (i = 0; i < 4; i++) { + int pos = secp256k1_rand_bits(6); + int mod = 1 + secp256k1_rand_int(255); + sig64[k][pos] ^= mod; + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); + sig64[k][pos] ^= mod; + } + } +} + +void test_schnorr_threshold(void) { + unsigned char msg[32]; + unsigned char sec[5][32]; + secp256k1_pubkey pub[5]; + unsigned char nonce[5][32]; + secp256k1_pubkey pubnonce[5]; + unsigned char sig[5][64]; + const unsigned char* sigs[5]; + unsigned char allsig[64]; + const secp256k1_pubkey* pubs[5]; + secp256k1_pubkey allpub; + int n, i; + int damage; + int ret = 0; + + damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; + secp256k1_rand256_test(msg); + n = 2 + secp256k1_rand_int(4); + for (i = 0; i < n; i++) { + do { + secp256k1_rand256_test(sec[i]); + } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); + CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); + CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); + pubs[i] = &pub[i]; + } + if (damage == 1) { + nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } else if (damage == 2) { + sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } + for (i = 0; i < n; i++) { + secp256k1_pubkey allpubnonce; + const secp256k1_pubkey *pubnonces[4]; + int j; + for (j = 0; j < i; j++) { + pubnonces[j] = &pubnonce[j]; + } + for (j = i + 1; j < n; j++) { + pubnonces[j - 1] = &pubnonce[j]; + } + CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); + ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; + sigs[i] = sig[i]; + } + if (damage == 3) { + sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); + } + ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; + if ((ret & 1) == 0) { + ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; + } + if (damage == 4) { + allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } + if ((ret & 7) == 0) { + ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; + } + CHECK((ret == 0) == (damage == 0)); +} + +void test_schnorr_recovery(void) { + unsigned char msg32[32]; + unsigned char sig64[64]; + secp256k1_ge Q; + + secp256k1_rand256_test(msg32); + secp256k1_rand256_test(sig64); + secp256k1_rand256_test(sig64 + 32); + if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); + } +} + +void run_schnorr_tests(void) { + int i; + for (i = 0; i < 32*count; i++) { + test_schnorr_end_to_end(); + } + for (i = 0; i < 32 * count; i++) { + test_schnorr_sign_verify(); + } + for (i = 0; i < 16 * count; i++) { + test_schnorr_recovery(); + } + for (i = 0; i < 10 * count; i++) { + test_schnorr_threshold(); + } +} + +#endif diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h index 339b6bb6ec..ebfa71eb44 100644 --- a/src/secp256k1/src/num.h +++ b/src/secp256k1/src/num.h @@ -20,48 +20,48 @@ #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); /** 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 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 diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h index baa1f2bf2e..7dd813088a 100644 --- a/src/secp256k1/src/num_gmp.h +++ b/src/secp256k1/src/num_gmp.h @@ -15,6 +15,6 @@ typedef struct { mp_limb_t data[2*NUM_LIMBS]; int neg; int limbs; -} secp256k1_num_t; +} secp256k1_num; #endif diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h index dbbc458d5d..7b6a89719a 100644 --- a/src/secp256k1/src/num_gmp_impl.h +++ b/src/secp256k1/src/num_gmp_impl.h @@ -15,18 +15,18 @@ #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; @@ -42,7 +42,7 @@ 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); @@ -59,7 +59,7 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un } } -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) { @@ -68,8 +68,9 @@ 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) { @@ -77,7 +78,7 @@ static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, } } -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); @@ -97,7 +98,7 @@ 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]; @@ -125,6 +126,7 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t } 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; @@ -142,15 +144,15 @@ 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_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) { +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { if (a->limbs > b->limbs) { return 1; } @@ -160,7 +162,7 @@ static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) return mpn_cmp(a->data, b->data, a->limbs); } -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) { if (a->limbs > b->limbs) { return 0; } @@ -173,7 +175,7 @@ static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) 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) { @@ -192,19 +194,19 @@ 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); @@ -231,13 +233,13 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { - int i; +static void secp256k1_num_shift(secp256k1_num *r, int bits) { if (bits % GMP_NUMB_BITS) { /* Shift within limbs. */ mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); } if (bits >= GMP_NUMB_BITS) { + int i; /* Shift full limbs. */ for (i = 0; i < r->limbs; i++) { int index = i + (bits / GMP_NUMB_BITS); @@ -253,7 +255,7 @@ static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { } } -static void secp256k1_num_negate(secp256k1_num_t *r) { +static void secp256k1_num_negate(secp256k1_num *r) { r->neg ^= 1; } diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index f5d09f8d47..b590ccd6dd 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -22,72 +22,83 @@ #endif /** 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 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_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *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 diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h index 82899aa7b0..cff406038f 100644 --- a/src/secp256k1/src/scalar_4x64.h +++ b/src/secp256k1/src/scalar_4x64.h @@ -12,7 +12,7 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint64_t d[4]; -} secp256k1_scalar_t; +} secp256k1_scalar; #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)}} diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index ff365292f8..aa2703dd23 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -24,26 +24,26 @@ #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) { @@ -54,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. */ @@ -66,7 +66,7 @@ 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); t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; @@ -80,7 +80,7 @@ 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; @@ -96,9 +96,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t 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); + 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)); @@ -113,7 +114,7 @@ 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; @@ -125,18 +126,18 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char } } -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; @@ -148,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); @@ -164,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. */ @@ -250,7 +267,7 @@ 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) { +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; @@ -559,7 +576,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l 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__( @@ -721,12 +738,12 @@ 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 */ @@ -871,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; @@ -893,12 +923,13 @@ 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) { +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; @@ -912,9 +943,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * 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 diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h index f17017e24e..1319664f65 100644 --- a/src/secp256k1/src/scalar_8x32.h +++ b/src/secp256k1/src/scalar_8x32.h @@ -12,7 +12,7 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint32_t d[8]; -} secp256k1_scalar_t; +} secp256k1_scalar; #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index 22b31d4112..aae4f35c08 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -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,7 +90,7 @@ 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); t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; @@ -112,7 +112,7 @@ 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; @@ -136,9 +136,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t 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); + 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)); @@ -161,7 +162,7 @@ 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; @@ -177,7 +178,7 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char } } -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]; @@ -188,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; @@ -212,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); @@ -234,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. */ @@ -320,7 +346,7 @@ 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; @@ -462,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, 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; @@ -550,7 +576,7 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, c l[15] = c0; } -static void secp256k1_scalar_sqr_512(uint32_t *l, 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; @@ -618,20 +644,36 @@ static void secp256k1_scalar_sqr_512(uint32_t *l, 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); } #ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +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]; @@ -651,11 +693,11 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ } #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) { +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; @@ -673,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 diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h index 33824983e4..88ea97de86 100644 --- a/src/secp256k1/src/scalar_impl.h +++ b/src/secp256k1/src/scalar_impl.h @@ -25,14 +25,14 @@ #endif #ifndef USE_NUM_NONE -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) { unsigned char c[32]; secp256k1_scalar_get_b32(c, a); secp256k1_num_set_bin(r, c, 32); } /** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { +static void secp256k1_scalar_order_get_num(secp256k1_num *r) { static const unsigned char order[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, @@ -43,11 +43,11 @@ static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { } #endif -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { - secp256k1_scalar_t *t; +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_scalar *t; int i; /* 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 x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; secp256k1_scalar_sqr(&x2, x); secp256k1_scalar_mul(&x2, &x2, x); @@ -234,18 +234,27 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal 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) { + /* d[0] is present and is the lowest word for all representations */ + return !(a->d[0] & 1); +} + +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_num_t n, m; - secp256k1_scalar_get_b32(b, x); + secp256k1_num n, m; + secp256k1_scalar t = *x; + secp256k1_scalar_get_b32(b, &t); secp256k1_num_set_bin(&n, b, 32); 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 @@ -290,30 +299,31 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_ * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { - secp256k1_scalar_t c1, c2; - static const secp256k1_scalar_t minus_lambda = SECP256K1_SCALAR_CONST( +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_t minus_b1 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL ); - static const secp256k1_scalar_t minus_b2 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL ); - static const secp256k1_scalar_t g1 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL ); - static const secp256k1_scalar_t g2 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL ); VERIFY_CHECK(r1 != a); VERIFY_CHECK(r2 != a); + /* 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); diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index d6192dc4ed..62d192baeb 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -14,150 +14,348 @@ #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" +#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(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + + struct secp256k1_context_struct { - secp256k1_ecmult_context_t ecmult_ctx; - secp256k1_ecmult_gen_context_t ecmult_gen_ctx; + secp256k1_ecmult_context ecmult_ctx; + secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_callback illegal_callback; + secp256k1_callback error_callback; }; -secp256k1_context_t* secp256k1_context_create(int flags) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); +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; + } secp256k1_ecmult_context_init(&ret->ecmult_ctx); secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); - if (flags & SECP256K1_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&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_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx); + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); } return ret; } -secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); +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; } -void secp256k1_context_destroy(secp256k1_context_t* ctx) { - secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +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); + free(ctx); + } } -int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t s; - secp256k1_scalar_t m; - int ret = -3; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig != NULL); - DEBUG_CHECK(pubkey != NULL); +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; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} - secp256k1_scalar_set_b32(&m, msg32, NULL); +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; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} - if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { - if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { - if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { - /* success is 1, all other values are fail */ - ret = 1; - } else { - ret = 0; - } - } else { - ret = -2; - } +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], 64); + 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); + } + 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, 64); } else { - ret = -1; + 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); } +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_ge Q; + + (void)ctx; + 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; + (void)ctx; + 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; + } + } return ret; } -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { - secp256k1_rfc6979_hmac_sha256_t rng; - unsigned int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0); - for (i = 0; i <= counter; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - return 1; +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); + } } -const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; -const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; +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 secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; - int ret = 0; +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; + + (void)ctx; + 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; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(signature != NULL); - DEBUG_CHECK(signaturelen != NULL); - DEBUG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; + + (void)ctx; + 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_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); } + return ret; +} - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) { - break; - } - } - count++; - } +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; + + (void)ctx; + 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; + + (void)ctx; + 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; + + 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) { - ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); + secp256k1_scalar_negate(&s, &s); } - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (!ret) { - *signaturelen = 0; + secp256k1_ecdsa_signature_save(sigout, &r, &s); } + return ret; } -int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; +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 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]; + int keylen = 64; + secp256k1_rfc6979_hmac_sha256_t 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. + */ + memcpy(keydata, key32, 32); + memcpy(keydata + 32, msg32, 32); + if (data != NULL) { + memcpy(keydata + 64, data, 32); + keylen = 96; + } + if (algo16 != NULL) { + memcpy(keydata + keylen, algo16, 16); + keylen += 16; + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); + 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; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(seckey != NULL); + 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; } @@ -165,139 +363,87 @@ int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) { + if (!overflow && !secp256k1_scalar_is_zero(&non)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { break; } } count++; } - if (ret) { - secp256k1_scalar_get_b32(sig64, &sig.r); - secp256k1_scalar_get_b32(sig64 + 32, &sig.s); - } secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); } - if (!ret) { - memset(sig64, 0, 64); - } - return ret; -} - -int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t m; - int ret = 0; - int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(recid >= 0 && recid <= 3); - - secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&m, msg32, NULL); - - if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { - ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); - } - } + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); } return ret; } -int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { - secp256k1_scalar_t sec; +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; int ret; int overflow; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); (void)ctx; secp256k1_scalar_set_b32(&sec, seckey, &overflow); - 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 secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(pubkey != NULL); - (void)ctx; - - return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); -} - -int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { - secp256k1_gej_t pj; - secp256k1_ge_t p; - secp256k1_scalar_t sec; +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; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(seckey != NULL); + 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_scalar_set_b32(&sec, seckey, &overflow); - if (!overflow) { + ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + if (ret) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_scalar_clear(&sec); secp256k1_ge_set_gej(&p, &pj); - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); - } - if (!ret) { - *pubkeylen = 0; - } - return ret; -} - -int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { - secp256k1_ge_t p; - int ret = 0; - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - (void)ctx; - - if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); + secp256k1_pubkey_save(pubkey, &p); } + secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar_t term; - secp256k1_scalar_t sec; +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; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); (void)ctx; secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); - 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); } @@ -307,45 +453,44 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - secp256k1_ge_t p; - 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; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + 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) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + 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(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar_t factor; - secp256k1_scalar_t sec; +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; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); (void)ctx; secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); - 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); } @@ -355,65 +500,69 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - secp256k1_ge_t p; - 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; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + 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) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + 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 secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { - secp256k1_scalar_t key; - int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - DEBUG_CHECK(privkeylen != NULL); - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - - secp256k1_scalar_set_b32(&key, seckey, NULL); - ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, 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(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) { - secp256k1_scalar_t key; - int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - (void)ctx; +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; - 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); -int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) { - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + 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_SCHNORR +# include "modules/schnorr/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 041bb92c47..f8efa93c7c 100644 --- a/src/secp256k1/src/testrand.h +++ b/src/secp256k1/src/testrand.h @@ -16,13 +16,23 @@ /** Seed the pseudorandom number generator for testing. */ SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); -/** Generate a pseudorandom 32-bit number. */ +/** 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); +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); + #endif diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h index 21c69f1c51..15c7b9f12d 100644 --- a/src/secp256k1/src/testrand_impl.h +++ b/src/secp256k1/src/testrand_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * 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.* **********************************************************************/ @@ -16,9 +16,11 @@ static secp256k1_rfc6979_hmac_sha256_t 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(const unsigned char *seed16) { - secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, (const unsigned char*)"TestRNG", 7, seed16, 16, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); } SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { @@ -29,32 +31,80 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { 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; +} + +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) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } -static void secp256k1_rand256_test(unsigned char *b32) { - int bits=0; - uint64_t ent = 0; - int entleft = 0; - memset(b32, 0, 32); - while (bits < 256) { +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; - if (entleft < 12) { - ent |= ((uint64_t)secp256k1_rand32()) << entleft; - entleft += 32; - } - now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31; - val = 1 & (ent >> 11); - ent >>= 12; - entleft -= 12; - while (now > 0 && bits < 256) { - b32[bits / 8] |= val << (bits % 8); + 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++; } } } +static void secp256k1_rand256_test(unsigned char *b32) { + secp256k1_rand_bytes_test(b32, 32); +} + #endif diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index d0e05057f2..687a5f2fdd 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -14,6 +14,7 @@ #include <time.h> #include "secp256k1.c" +#include "include/secp256k1.h" #include "testrand_impl.h" #ifdef ENABLE_OPENSSL_TESTS @@ -23,10 +24,40 @@ #include "openssl/obj_mac.h" #endif +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" + +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include <valgrind/memcheck.h> +# 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_t *ctx = NULL; +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)++; +} -void random_field_element_test(secp256k1_fe_t *fe) { +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 *fe) { do { unsigned char b32[32]; secp256k1_rand256_test(b32); @@ -36,9 +67,9 @@ void random_field_element_test(secp256k1_fe_t *fe) { } while(1); } -void random_field_element_magnitude(secp256k1_fe_t *fe) { - secp256k1_fe_t zero; - int n = secp256k1_rand32() % 9; +void random_field_element_magnitude(secp256k1_fe *fe) { + secp256k1_fe zero; + int n = secp256k1_rand_int(9); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -47,23 +78,22 @@ void random_field_element_magnitude(secp256k1_fe_t *fe) { secp256k1_fe_negate(&zero, &zero, 0); secp256k1_fe_mul_int(&zero, n - 1); secp256k1_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif + 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_var(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) { - secp256k1_fe_t z2, z3; +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)) { @@ -77,7 +107,7 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge 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]; int overflow = 0; @@ -90,7 +120,7 @@ void random_scalar_order_test(secp256k1_scalar_t *num) { } while(1); } -void random_scalar_order(secp256k1_scalar_t *num) { +void random_scalar_order(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -104,19 +134,31 @@ void random_scalar_order(secp256k1_scalar_t *num) { } void run_context_tests(void) { - secp256k1_context_t *none = secp256k1_context_create(0); - secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - secp256k1_gej_t pubj; - secp256k1_ge_t pub; - secp256k1_scalar_t msg, key, nonce; - secp256k1_ecdsa_sig_t sig; + secp256k1_pubkey 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; + + 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_t *ctx_tmp; + 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); @@ -124,30 +166,74 @@ void run_context_tests(void) { 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_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 13); + 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, &sig, &key, &msg, &nonce, NULL)); + } 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, &sig, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + 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, &sig, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); + 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); } /***** HASH TESTS *****/ @@ -178,7 +264,7 @@ void run_sha256_tests(void) { secp256k1_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + 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); @@ -222,7 +308,7 @@ void run_hmac_sha256_tests(void) { secp256k1_hmac_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + 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); @@ -233,16 +319,14 @@ void run_hmac_sha256_tests(void) { } void run_rfc6979_hmac_sha256_tests(void) { - static const unsigned char key1[32] = {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}; - static const unsigned char msg1[32] = {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}; + 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[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}; - static const unsigned char msg2[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}; + 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}, @@ -251,24 +335,23 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_t rng; unsigned char out[32]; - unsigned char zero[1] = {0}; int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1); + 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, 32, msg1, 32, zero, 1); + 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, 32, msg2, 32, zero, 0); + 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); @@ -276,30 +359,102 @@ void run_rfc6979_hmac_sha256_tests(void) { 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 */ @@ -318,16 +473,15 @@ void test_num_negate(void) { } void test_num_add_sub(void) { - secp256k1_num_t n1; - secp256k1_num_t n2; - secp256k1_num_t n1p2, n2p1, n1m2, n2m1; - int r = secp256k1_rand32(); + 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_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ @@ -358,12 +512,12 @@ void run_num_smalltests(void) { /***** SCALAR TESTS *****/ void scalar_test(void) { - secp256k1_scalar_t s; - secp256k1_scalar_t s1; - secp256k1_scalar_t s2; + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; #ifndef USE_NUM_NONE - secp256k1_num_t snum, s1num, s2num; - secp256k1_num_t order, half_order; + secp256k1_num snum, s1num, s2num; + secp256k1_num order, half_order; #endif unsigned char c[32]; @@ -390,10 +544,10 @@ void scalar_test(void) { { 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 (i = 0; i < 256; i += 4) { - secp256k1_scalar_t t; + secp256k1_scalar t; int j; secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); for (j = 0; j < 4; j++) { @@ -406,13 +560,13 @@ 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 n; int i = 0; secp256k1_scalar_set_int(&n, 0); while (i < 256) { - secp256k1_scalar_t t; + secp256k1_scalar t; int j; - int now = (secp256k1_rand32() % 15) + 1; + int now = secp256k1_rand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -429,9 +583,9 @@ 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_t r2num; - secp256k1_scalar_t r; + secp256k1_num rnum; + secp256k1_num r2num; + secp256k1_scalar r; secp256k1_num_add(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); secp256k1_scalar_add(&r, &s, &s2); @@ -440,10 +594,10 @@ void scalar_test(void) { } { - /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ - secp256k1_scalar_t r; - secp256k1_num_t r2num; - 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_mul(&r, &s, &s2); @@ -457,9 +611,9 @@ void scalar_test(void) { } { - secp256k1_scalar_t neg; - secp256k1_num_t negnum; - secp256k1_num_t negnum2; + 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. */ @@ -484,12 +638,12 @@ void scalar_test(void) { { /* Test secp256k1_scalar_mul_shift_var. */ - secp256k1_scalar_t r; - secp256k1_num_t one; - secp256k1_num_t rnum; - secp256k1_num_t rnum2; + secp256k1_scalar r; + secp256k1_num one; + secp256k1_num rnum; + secp256k1_num rnum2; unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + (secp256k1_rand32() % 257); + unsigned int shift = 256 + secp256k1_rand_int(257); secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); secp256k1_num_mul(&rnum, &s1num, &s2num); secp256k1_num_shift(&rnum, shift - 1); @@ -499,15 +653,29 @@ void scalar_test(void) { 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_t invnum; - secp256k1_num_t invnum2; + secp256k1_num invnum; + secp256k1_num invnum2; #endif secp256k1_scalar_inverse(&inv, &s); #ifndef USE_NUM_NONE @@ -526,18 +694,18 @@ void scalar_test(void) { { /* 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_t r1, r2; - secp256k1_scalar_t b; + secp256k1_scalar r1, r2; + secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_rand32() % 256; + int bit = secp256k1_rand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -547,14 +715,17 @@ void scalar_test(void) { 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)); @@ -562,7 +733,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); @@ -572,7 +743,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); @@ -582,7 +753,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); @@ -593,7 +764,7 @@ 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)); @@ -601,7 +772,7 @@ void scalar_test(void) { { /* Test multiplicative identity. */ - secp256k1_scalar_t r1, v1; + secp256k1_scalar r1, v1; secp256k1_scalar_set_int(&v1,1); secp256k1_scalar_mul(&r1, &s1, &v1); CHECK(secp256k1_scalar_eq(&r1, &s1)); @@ -609,7 +780,7 @@ void scalar_test(void) { { /* Test additive identity. */ - secp256k1_scalar_t r1, v0; + secp256k1_scalar r1, v0; secp256k1_scalar_set_int(&v0,0); secp256k1_scalar_add(&r1, &s1, &v0); CHECK(secp256k1_scalar_eq(&r1, &s1)); @@ -617,7 +788,7 @@ void scalar_test(void) { { /* Test zero product property. */ - secp256k1_scalar_t r1, v0; + secp256k1_scalar r1, v0; secp256k1_scalar_set_int(&v0,0); secp256k1_scalar_mul(&r1, &s1, &v0); CHECK(secp256k1_scalar_eq(&r1, &v0)); @@ -633,7 +804,7 @@ void run_scalar_tests(void) { { /* (-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); @@ -646,8 +817,8 @@ void run_scalar_tests(void) { #ifndef USE_NUM_NONE { /* A scalar with value of the curve order should be 0. */ - secp256k1_num_t order; - secp256k1_scalar_t zero; + secp256k1_num order; + secp256k1_scalar zero; unsigned char bin[32]; int overflow = 0; secp256k1_scalar_order_get_num(&order); @@ -657,11 +828,589 @@ void run_scalar_tests(void) { 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[32][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}} + }; + unsigned char res[32][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}} + }; + secp256k1_scalar_set_int(&one, 1); + for (i = 0; i < 32; 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); @@ -671,7 +1420,17 @@ 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); @@ -684,25 +1443,25 @@ void random_fe_non_zero(secp256k1_fe_t *nz) { CHECK(tries >= 0); } -void random_fe_non_square(secp256k1_fe_t *ns) { - secp256k1_fe_t r; +void random_fe_non_square(secp256k1_fe *ns) { + secp256k1_fe r; random_fe_non_zero(ns); if (secp256k1_fe_sqrt_var(&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_t bn = *b; +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_t one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 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); } @@ -714,17 +1473,17 @@ void run_field_convert(void) { 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 }; - static const secp256k1_fe_storage_t fes = SECP256K1_FE_STORAGE_CONST( + static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - static const secp256k1_fe_t fe = SECP256K1_FE_CONST( + static const secp256k1_fe fe = SECP256K1_FE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - secp256k1_fe_t fe2; + secp256k1_fe fe2; unsigned char b322[32]; - secp256k1_fe_storage_t fes2; + secp256k1_fe_storage fes2; /* Check conversions to fe. */ CHECK(secp256k1_fe_set_b32(&fe2, b32)); CHECK(secp256k1_fe_equal_var(&fe, &fe2)); @@ -737,15 +1496,24 @@ void run_field_convert(void) { 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_t x; - secp256k1_fe_t y; - secp256k1_fe_t z; - secp256k1_fe_t q; - secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); - int i; + 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_t xs, ys, zs; + secp256k1_fe_storage xs, ys, zs; random_fe(&x); random_fe_non_zero(&y); /* Test the fe equality and comparison operations. */ @@ -756,14 +1524,27 @@ void run_field_misc(void) { /* 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(memcmp(&x, &z, sizeof(x)) != 0); - CHECK(memcmp(&x, &q, sizeof(x)) == 0); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); secp256k1_fe_cmov(&q, &z, 1); - CHECK(memcmp(&q, &z, sizeof(q)) == 0); - /* Test storage conversion and conditional moves. */ - secp256k1_fe_normalize(&z); + 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); @@ -797,7 +1578,7 @@ void run_field_misc(void) { } void run_field_inv(void) { - secp256k1_fe_t x, xi, xii; + secp256k1_fe x, xi, xii; int i; for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); @@ -809,7 +1590,7 @@ void run_field_inv(void) { } void run_field_inv_var(void) { - secp256k1_fe_t x, xi, xii; + secp256k1_fe x, xi, xii; int i; for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); @@ -821,13 +1602,13 @@ void run_field_inv_var(void) { } void run_field_inv_all_var(void) { - secp256k1_fe_t x[16], xi[16], xii[16]; + secp256k1_fe x[16], xi[16], xii[16]; int i; /* Check it's safe to call for 0 elements */ secp256k1_fe_inv_all_var(0, xi, x); for (i = 0; i < count; i++) { size_t j; - size_t len = (secp256k1_rand32() & 15) + 1; + size_t len = secp256k1_rand_int(15) + 1; for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); } @@ -843,7 +1624,7 @@ void run_field_inv_all_var(void) { } void run_sqr(void) { - secp256k1_fe_t x, s; + secp256k1_fe x, s; { int i; @@ -858,8 +1639,8 @@ void run_sqr(void) { } } -void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { - secp256k1_fe_t r1, r2; +void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { + secp256k1_fe r1, r2; int v = secp256k1_fe_sqrt_var(&r1, a); CHECK((v == 0) == (k == NULL)); @@ -873,7 +1654,7 @@ void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { } void run_sqrt(void) { - secp256k1_fe_t ns, x, s, t; + secp256k1_fe ns, x, s, t; int i; /* Check sqrt(0) is 0 */ @@ -908,19 +1689,19 @@ void run_sqrt(void) { /***** GROUP TESTS *****/ -void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { +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(&b->y, &b->y)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); } /* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { - secp256k1_gej_t a2; - secp256k1_gej_t b2; +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) { @@ -939,9 +1720,9 @@ int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { return ret; } -void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { - secp256k1_fe_t z2s; - secp256k1_fe_t u1, u2, s1, s2; +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; @@ -958,21 +1739,39 @@ void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { void test_ge(void) { 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 eachother, using all applicable methods. + * 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_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); - secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); + secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); + secp256k1_fe zf; + secp256k1_fe zfi2, zfi3; + 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_t g; + 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); @@ -990,18 +1789,65 @@ void test_ge(void) { } } + /* Compute z inverses. */ + { + secp256k1_fe *zs = malloc(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(4 * runs + 1, zinv, zs); + free(zs); + } + + /* 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); + 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_t refj, resj; - secp256k1_ge_t ref; - secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2]); + 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 (var). */ - secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2]); + /* 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) { @@ -1012,10 +1858,15 @@ void test_ge(void) { /* Test doubling (var). */ if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { - /* Normal doubling. */ - secp256k1_gej_double_var(&resj, &gej[i1]); + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); ge_equals_gej(&ref, &resj); - secp256k1_gej_double_var(&resj, &gej[i2]); + /* 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); } @@ -1040,41 +1891,121 @@ void test_ge(void) { /* Test adding all points together in random order equals infinity. */ { - secp256k1_gej_t sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej_t *gej_shuffled = (secp256k1_gej_t *)malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); + secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((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_rand32() % (4 * runs + 1 - i); + int swap = i + secp256k1_rand_int(4 * runs + 1 - i); if (swap != i) { - secp256k1_gej_t t = gej_shuffled[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]); + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); } CHECK(secp256k1_gej_is_infinity(&sum)); free(gej_shuffled); } - /* Test batch gej -> ge conversion. */ + /* Test batch gej -> ge conversion with and without known z ratios. */ { - secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); - secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej); + secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe)); + secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_fe_t s; + /* 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_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr); + secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &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); } free(ge); free(gej); + free(zinv); +} + +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/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) { @@ -1082,36 +2013,125 @@ void run_ge(void) { 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 tmp; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_quad, ge_even, ge_odd; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_quad = secp256k1_ge_set_xquad_var(&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_sqrt_var(&tmp, &ge_quad.y)); + secp256k1_fe_sqr(&tmp, &tmp); + CHECK(secp256k1_fe_equal_var(&tmp, &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)); + } +} + +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_t a = SECP256K1_GEJ_CONST( + 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_t xn = SECP256K1_SCALAR_CONST( + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 ); - secp256k1_scalar_t gn = SECP256K1_SCALAR_CONST( + 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_t xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); - static const secp256k1_scalar_t gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + 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_t ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar_t ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + 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_t x = a; - secp256k1_gej_t x2; + secp256k1_gej x; + secp256k1_gej x2; int i; /* the point being computed */ @@ -1131,7 +2151,7 @@ void run_ecmult_chain(void) { /* verify */ if (i == 19999) { /* expected result after 19999 iterations */ - secp256k1_gej_t rp = SECP256K1_GEJ_CONST( + secp256k1_gej rp = SECP256K1_GEJ_CONST( 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, @@ -1139,30 +2159,32 @@ void run_ecmult_chain(void) { ); secp256k1_gej_neg(&rp, &rp); - secp256k1_gej_add_var(&rp, &rp, &x); + 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); + secp256k1_gej_add_var(&x2, &x2, &x, NULL); CHECK(secp256k1_gej_is_infinity(&x2)); } -void test_point_times_order(const secp256k1_gej_t *point) { +void test_point_times_order(const secp256k1_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - secp256k1_scalar_t x; - secp256k1_scalar_t nx; - secp256k1_gej_t res1, res2; - secp256k1_ge_t res3; + 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]; - int psize = 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); + 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); @@ -1171,19 +2193,29 @@ void test_point_times_order(const secp256k1_gej_t *point) { 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_t x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); - static const secp256k1_fe_t xr = SECP256K1_FE_CONST( + 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_t p; + secp256k1_ge p; if (secp256k1_ge_set_xo_var(&p, &x, 1)) { - secp256k1_gej_t j; + secp256k1_gej j; CHECK(secp256k1_ge_is_valid_var(&p)); secp256k1_gej_set_ge(&j, &p); CHECK(secp256k1_gej_is_valid_var(&j)); @@ -1195,15 +2227,118 @@ void run_point_times_order(void) { CHECK(secp256k1_fe_equal_var(&x, &xr)); } -void test_wnaf(const secp256k1_scalar_t *number, int w) { - secp256k1_scalar_t x, two, t; +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); + + 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); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); + 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); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_is_infinity(&res2)); + secp256k1_ecmult_const(&res1, &point, &one); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_ecmult_const(&res1, &point, &negone); + 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); + } + 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(); +} + +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); - bits = secp256k1_ecmult_wnaf(wnaf, number, w); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); CHECK(bits <= 256); for (i = bits-1; i >= 0; i--) { int v = wnaf[i]; @@ -1229,20 +2364,95 @@ 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; +#ifdef USE_ENDOMORPHISM + int skew; +#endif + 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); + } + skew = secp256k1_wnaf_const(wnaf, num, w); +#else + secp256k1_wnaf_const(wnaf, num, w); +#endif + + for (i = WNAF_SIZE(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); + } +#ifdef USE_ENDOMORPHISM + /* Skew num because when encoding 128-bit numbers as odd we use an offset */ + secp256k1_scalar_cadd_bit(&num, skew == 2, 1); +#endif + CHECK(secp256k1_scalar_eq(&x, &num)); +} + void run_wnaf(void) { int i; - secp256k1_scalar_t n; + secp256k1_scalar n = {{0}}; + + /* Sanity check: 1 and 2 are the smallest odd and even numbers and should + * have easier-to-diagnose failure modes */ + n.d[0] = 1; + test_constant_wnaf(&n, 4); + n.d[0] = 2; + test_constant_wnaf(&n, 4); + /* Random tests */ for (i = 0; i < count; i++) { random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); + test_constant_wnaf_negate(&n); + test_constant_wnaf(&n, 4 + (i % 10)); } + secp256k1_scalar_set_int(&n, 0); + CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_scalar_is_zero(&n)); + CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_scalar_is_zero(&n)); } void test_ecmult_constants(void) { /* Test ecmult_gen() for [0..36) and [order-36..0). */ - secp256k1_scalar_t x; - secp256k1_gej_t r; - secp256k1_ge_t ng; + secp256k1_scalar x; + secp256k1_gej r; + secp256k1_ge ng; int i; int j; secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); @@ -1276,14 +2486,14 @@ void run_ecmult_constants(void) { } void test_ecmult_gen_blind(void) { - /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */ - secp256k1_scalar_t key; - secp256k1_scalar_t b; + /* 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_t pgej; - secp256k1_gej_t pgej2; - secp256k1_gej_t i; - secp256k1_ge_t pge; + 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); @@ -1300,8 +2510,8 @@ void test_ecmult_gen_blind(void) { void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ - secp256k1_scalar_t b; - secp256k1_gej_t initial; + 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; @@ -1318,35 +2528,702 @@ void run_ecmult_gen_blind(void) { } } +#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 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 changed. */ + 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_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { - secp256k1_scalar_t nonce; +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(&ctx->ecmult_gen_ctx, 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_t pubj; - secp256k1_ge_t pub; - secp256k1_scalar_t one; - secp256k1_scalar_t msg, key; - secp256k1_ecdsa_sig_t sig; + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar one; + secp256k1_scalar msg, key; + secp256k1_scalar sigr, sigs; int recid; int getrec; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand32()&1; - random_sign(&sig, &key, &msg, getrec?&recid:NULL); + 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, &sig, &pub, &msg)); + 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(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); } void run_ecdsa_sign_verify(void) { @@ -1357,22 +3234,23 @@ void run_ecdsa_sign_verify(void) { } /** 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, unsigned int counter, const void *data) { +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, unsigned int counter, const void *data) { +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, counter - 1, data); + 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, unsigned int counter, const void *data) { +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); @@ -1394,17 +3272,17 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char } return 1; } - /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */ + /* 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, counter - 5, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); } -int is_empty_compact_signature(const unsigned char *sig64) { - static const unsigned char res[64] = {0}; - return memcmp(sig64, res, 64) == 0; +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) { @@ -1412,26 +3290,19 @@ void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - unsigned char csignature[64]; - unsigned char signature[72]; - unsigned char signature2[72]; - unsigned char signature3[72]; - unsigned char signature4[72]; - unsigned char pubkey[65]; - unsigned char recpubkey[65]; + 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; unsigned char seckey[300]; - int signaturelen = 72; - int signaturelen2 = 72; - int signaturelen3 = 72; - int signaturelen4 = 72; - int recid = 0; - int recpubkeylen = 0; - int pubkeylen = 65; - int seckeylen = 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); @@ -1440,117 +3311,120 @@ void test_ecdsa_end_to_end(void) { /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); - if (secp256k1_rand32() & 1) { - CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); - } - CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen)); + 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 private key import and export. */ - CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); - CHECK(secp256k1_ec_privkey_import(ctx, 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]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + 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]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); - CHECK(signaturelen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); - CHECK(signaturelen2 > 0); + 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, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); - CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); - CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); - CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0)); - CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); + 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(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); - /* Destroy signature and verify again. */ - signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); - - /* Compact sign. */ - CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); - CHECK(!is_empty_compact_signature(csignature)); - /* Recover. */ - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, 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(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || - memcmp(pubkey, recpubkey, pubkeylen) != 0); - CHECK(recpubkeylen == pubkeylen); - + 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_t elem; - secp256k1_ge_t elem2; + secp256k1_ge elem; + secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - uint32_t r = secp256k1_rand32(); - int len = (r & 3) == 0 ? 65 : 33; - r>>=2; - if ((r & 3) == 0) { - len = (r & 252) >> 3; + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); } - r>>=8; if (len == 65) { - in[0] = (r & 2) ? 4 : (r & 1? 6 : 7); + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); } else { - in[0] = (r & 1) ? 2 : 3; + in[0] = secp256k1_rand_bits(1) ? 2 : 3; } - r>>=2; - if ((r & 7) == 0) { - in[0] = (r & 2040) >> 3; + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); } - r>>=11; if (len > 1) { secp256k1_rand256(&in[1]); } @@ -1561,7 +3435,7 @@ void test_random_pubkeys(void) { unsigned char out[65]; unsigned char firstb; int res; - int size = len; + 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)); @@ -1577,7 +3451,7 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); ge_equals_ge(&elem,&elem2); /* Check that the X9.62 hybrid type is checked. */ - in[0] = (r & 1) ? 6 : 7; + 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) { @@ -1608,185 +3482,505 @@ void run_ecdsa_end_to_end(void) { } } +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}; + 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 + }; + + 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 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) { + valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->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) { + /* Delete a byte. */ + pos = secp256k1_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2) { + /* 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; + } + 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); + 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) { - 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 t; - int pubkeylen = 65; - /* 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, - }; - unsigned char pubkeyb[33]; - int pubkeyblen = 33; - int recid; + secp256k1_ecdsa_signature sig; - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); + /* Test the case where ECDSA recomputes a point that is infinity. */ + { + 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); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } - 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, + /* Verify signature with r of zero fails. */ + { + 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 }; - unsigned char sigbderalt3[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, + 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, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + 0x01 }; - unsigned char sigbderalt4[40] = { - 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, + 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x02 }; - /* (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 + 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 }; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); - for (recid2 = 0; recid2 < 4; recid2++) { - unsigned char pubkey2b[33]; - int pubkey2blen = 33; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); - /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); - } - /* DER parsing tests. */ - /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); - /* Leading zeros. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); - sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); - sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); - /* Damage signature. */ - sigbder[7]++; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); - sigbder[7]--; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); - 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_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == - (i==4 || i==7) ? 0 : -2 ); - } - sigbder[i] = orig; - } + 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); } - /* Test the case where ECDSA recomputes a point that is infinity. */ + /* Verify signature with message 1 passes. */ { - secp256k1_gej_t keyj; - secp256k1_ge_t key; - secp256k1_scalar_t msg; - 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_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); - secp256k1_ge_set_gej(&key, &keyj); - msg = sig.s; - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); + 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); } - /* Test r/s equal to zero */ + /* Verify signature with message -1 passes. */ { - /* (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, + 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 }; - unsigned char pubkeyc[65]; - int pubkeyclen = 65; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); - } - - /*Signature where s would be zero.*/ + 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. */ { - const unsigned char nonce[32] = { + 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, @@ -1810,21 +4004,72 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - unsigned char sig[72]; - int siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); - CHECK(siglen == 0); + 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_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); - CHECK(siglen > 0); + 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; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); - CHECK(siglen == 0); + /* 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. */ @@ -1833,65 +4078,43 @@ void test_ecdsa_edge_cases(void) { int i; unsigned char key[32]; unsigned char msg[32]; - unsigned char sig[72]; - unsigned char sig2[72]; - secp256k1_ecdsa_sig_t s[512]; - int siglen = 72; - int siglen2 = 72; - int recid2; + 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, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + 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, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + 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, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); - CHECK(is_empty_compact_signature(sig)); + 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. */ - siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); - CHECK(siglen > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig2)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); - /* The default nonce function is determinstic. */ - siglen = 72; - siglen2 = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(siglen2 > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + 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; - siglen2 = 72; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + 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(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } msg[0] = 0; @@ -1899,17 +4122,45 @@ void test_ecdsa_edge_cases(void) { /* The default nonce function changes output with different keys. */ for(i = 256; i < 512; i++) { int j; - siglen2 = 72; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + 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(&s[i].r, &s[j].r)); + 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]; @@ -1919,9 +4170,10 @@ void test_ecdsa_edge_cases(void) { 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; - int outlen = 300; - CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0)); - CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1)); + 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)); } } @@ -1930,46 +4182,48 @@ 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; + size_t privkeylen; const unsigned char* pbegin = privkey; - int compr = secp256k1_rand32() & 1; + int compr = secp256k1_rand_bits(1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, 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_gej_t qj; - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t one; - secp256k1_scalar_t msg2; - 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; - int secp_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_scalar_get_b32(key32, &key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); secp256k1_ge_set_gej(&q, &qj); - ec_key = get_openssl_key(&key); - CHECK(ec_key); + ec_key = get_openssl_key(key32); + CHECK(ec_key != NULL); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); + 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_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); - random_sign(&sig, &key, &msg, NULL); - 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); @@ -1983,6 +4237,18 @@ void run_ecdsa_openssl(void) { } #endif +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/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}; @@ -2007,7 +4273,7 @@ int main(int argc, char **argv) { } } else { FILE *frand = fopen("/dev/urandom", "r"); - if (!frand || !fread(&seed16, sizeof(seed16), 1, frand)) { + if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) { uint64_t t = time(NULL) * (uint64_t)1337; seed16[0] ^= t; seed16[1] ^= t >> 8; @@ -2028,12 +4294,14 @@ int main(int argc, char **argv) { /* initialize */ run_context_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - if (secp256k1_rand32() & 1) { + if (secp256k1_rand_bits(1)) { secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL)); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); } + run_rand_bits(); + run_rand_int(); + run_sha256_tests(); run_hmac_sha256_tests(); run_rfc6979_hmac_sha256_tests(); @@ -2057,6 +4325,7 @@ int main(int argc, char **argv) { /* group tests */ run_ge(); + run_group_decompress(); /* ecmult tests */ run_wnaf(); @@ -2064,9 +4333,28 @@ int main(int argc, char **argv) { run_ecmult_chain(); run_ecmult_constants(); run_ecmult_gen_blind(); + run_ecmult_const_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(); @@ -2074,10 +4362,22 @@ int main(int argc, char **argv) { run_ecdsa_openssl(); #endif +#ifdef ENABLE_MODULE_SCHNORR + /* Schnorr tests */ + run_schnorr_tests(); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif + 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]); /* shutdown */ secp256k1_context_destroy(ctx); + + printf("no problems found\n"); return 0; } diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index ae98639f7c..4eef4ded47 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -15,6 +15,15 @@ #include <stdint.h> #include <stdio.h> +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); \ @@ -47,23 +56,20 @@ } 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. */ +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ #ifdef 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(size_t size) { +static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { void *ret = malloc(size); - CHECK(ret != NULL); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } return ret; } diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 0c2ade48d6..4a294c6712 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333333; ae.strOtherAccount = "b"; ae.strComment = ""; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); wtx.mapValue["comment"] = "z"; pwalletMain->AddToWallet(wtx, false, &walletdb); @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333336; ae.strOtherAccount = "c"; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333330; ae.strOtherAccount = "d"; ae.nOrderPos = pwalletMain->IncOrderPosNext(); - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333334; ae.strOtherAccount = "e"; ae.nOrderPos = -1; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 13d848311a..9489a19f63 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -6,6 +6,8 @@ #include "random.h" #include "uint256.h" #include "test/test_bitcoin.h" +#include "main.h" +#include "consensus/validation.h" #include <vector> #include <map> @@ -45,15 +47,18 @@ public: bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) { - map_[it->first] = it->second.coins; - if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { - // Randomly delete empty entries on write. - map_.erase(it->first); + if (it->second.flags & CCoinsCacheEntry::DIRTY) { + // Same optimization used in CCoinsViewDB is to only write dirty entries. + map_[it->first] = it->second.coins; + if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { + // Randomly delete empty entries on write. + map_.erase(it->first); + } } mapCoins.erase(it++); } - mapCoins.clear(); - hashBestBlock_ = hashBlock; + if (!hashBlock.IsNull()) + hashBestBlock_ = hashBlock; return true; } @@ -160,13 +165,22 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) } if (insecure_rand() % 100 == 0) { + // Every 100 iterations, flush an intermediate cache + if (stack.size() > 1 && insecure_rand() % 2 == 0) { + unsigned int flushIndex = insecure_rand() % (stack.size() - 1); + stack[flushIndex]->Flush(); + } + } + if (insecure_rand() % 100 == 0) { // Every 100 iterations, change the cache stack. if (stack.size() > 0 && insecure_rand() % 2 == 0) { + //Remove the top cache stack.back()->Flush(); delete stack.back(); stack.pop_back(); } if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) { + //Add a new cache CCoinsView* tip = &base; if (stack.size() > 0) { tip = stack.back(); @@ -197,4 +211,140 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) BOOST_CHECK(missed_an_entry); } +// This test is similar to the previous test +// except the emphasis is on testing the functionality of UpdateCoins +// random txs are created and UpdateCoins is used to update the cache stack +// In particular it is tested that spending a duplicate coinbase tx +// has the expected effect (the other duplicate is overwitten at all cache levels) +BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) +{ + bool spent_a_duplicate_coinbase = false; + // A simple map to track what we expect the cache stack to represent. + std::map<uint256, CCoins> result; + + // The cache stack. + CCoinsViewTest base; // A CCoinsViewTest at the bottom. + std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top. + stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache. + + // Track the txids we've used and whether they have been spent or not + std::map<uint256, CAmount> coinbaseids; + std::set<uint256> alltxids; + std::set<uint256> duplicateids; + + for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { + { + CMutableTransaction tx; + tx.vin.resize(1); + tx.vout.resize(1); + tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate + unsigned int height = insecure_rand(); + + // 1/10 times create a coinbase + if (insecure_rand() % 10 == 0 || coinbaseids.size() < 10) { + // 1/100 times create a duplicate coinbase + if (insecure_rand() % 10 == 0 && coinbaseids.size()) { + std::map<uint256, CAmount>::iterator coinbaseIt = coinbaseids.lower_bound(GetRandHash()); + if (coinbaseIt == coinbaseids.end()) { + coinbaseIt = coinbaseids.begin(); + } + //Use same random value to have same hash and be a true duplicate + tx.vout[0].nValue = coinbaseIt->second; + assert(tx.GetHash() == coinbaseIt->first); + duplicateids.insert(coinbaseIt->first); + } + else { + coinbaseids[tx.GetHash()] = tx.vout[0].nValue; + } + assert(CTransaction(tx).IsCoinBase()); + } + // 9/10 times create a regular tx + else { + uint256 prevouthash; + // equally likely to spend coinbase or non coinbase + std::set<uint256>::iterator txIt = alltxids.lower_bound(GetRandHash()); + if (txIt == alltxids.end()) { + txIt = alltxids.begin(); + } + prevouthash = *txIt; + + // Construct the tx to spend the coins of prevouthash + tx.vin[0].prevout.hash = prevouthash; + tx.vin[0].prevout.n = 0; + + // Update the expected result of prevouthash to know these coins are spent + CCoins& oldcoins = result[prevouthash]; + oldcoins.Clear(); + + // It is of particular importance here that once we spend a coinbase tx hash + // it is no longer available to be duplicated (or spent again) + // BIP 34 in conjunction with enforcing BIP 30 (at least until BIP 34 was active) + // results in the fact that no coinbases were duplicated after they were already spent + alltxids.erase(prevouthash); + coinbaseids.erase(prevouthash); + + // The test is designed to ensure spending a duplicate coinbase will work properly + // if that ever happens and not resurrect the previously overwritten coinbase + if (duplicateids.count(prevouthash)) + spent_a_duplicate_coinbase = true; + + assert(!CTransaction(tx).IsCoinBase()); + } + // Track this tx to possibly spend later + alltxids.insert(tx.GetHash()); + + // Update the expected result to know about the new output coins + CCoins &coins = result[tx.GetHash()]; + coins.FromTx(tx, height); + + CValidationState dummy; + UpdateCoins(tx, dummy, *(stack.back()), height); + } + + // Once every 1000 iterations and at the end, verify the full cache. + if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) { + const CCoins* coins = stack.back()->AccessCoins(it->first); + if (coins) { + BOOST_CHECK(*coins == it->second); + } else { + BOOST_CHECK(it->second.IsPruned()); + } + } + } + + if (insecure_rand() % 100 == 0) { + // Every 100 iterations, flush an intermediate cache + if (stack.size() > 1 && insecure_rand() % 2 == 0) { + unsigned int flushIndex = insecure_rand() % (stack.size() - 1); + stack[flushIndex]->Flush(); + } + } + if (insecure_rand() % 100 == 0) { + // Every 100 iterations, change the cache stack. + if (stack.size() > 0 && insecure_rand() % 2 == 0) { + stack.back()->Flush(); + delete stack.back(); + stack.pop_back(); + } + if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) { + CCoinsView* tip = &base; + if (stack.size() > 0) { + tip = stack.back(); + } + stack.push_back(new CCoinsViewCacheTest(tip)); + } + } + } + + // Clean up the stack. + while (stack.size() > 0) { + delete stack.back(); + stack.pop_back(); + } + + // Verify coverage. + BOOST_CHECK(spent_a_duplicate_coinbase); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 0cf906a259..896e1237ed 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -17,6 +17,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) { // Test CTxMemPool::remove functionality + TestMemPoolEntryHelper entry; // Parent transaction with three children, // and three grand-children: CMutableTransaction txParent; @@ -60,17 +61,17 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) BOOST_CHECK_EQUAL(removed.size(), 0); // Just the parent: - testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1)); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); testPool.remove(txParent, removed, true); BOOST_CHECK_EQUAL(removed.size(), 1); removed.clear(); // Parent, children, grandchildren: - testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1)); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1)); - testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1)); + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: testPool.remove(txChild[0], removed, true); @@ -90,8 +91,8 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) // Add children and grandchildren, but NOT the parent (simulate the parent being in a block) for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1)); - testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1)); + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be // put into the mempool (maybe because it is non-standard): @@ -114,41 +115,45 @@ void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { CTxMemPool pool(CFeeRate(0)); + TestMemPoolEntryHelper entry; + entry.hadNoDependencies = true; /* 3rd highest fee */ CMutableTransaction tx1 = CMutableTransaction(); tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), CTxMemPoolEntry(tx1, 10000LL, 0, 10.0, 1, true)); + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); /* highest fee */ CMutableTransaction tx2 = CMutableTransaction(); tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN; - pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 20000LL, 0, 9.0, 1, true)); + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); /* lowest fee */ CMutableTransaction tx3 = CMutableTransaction(); tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN; - pool.addUnchecked(tx3.GetHash(), CTxMemPoolEntry(tx3, 0LL, 0, 100.0, 1, true)); + pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN; - pool.addUnchecked(tx4.GetHash(), CTxMemPoolEntry(tx4, 15000LL, 0, 1.0, 1, true)); + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); /* equal fee rate to tx1, but newer */ CMutableTransaction tx5 = CMutableTransaction(); tx5.vout.resize(1); tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; - pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 10000LL, 1, 10.0, 1, true)); + entry.nTime = 1; + entry.dPriority = 10.0; + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5); std::vector<std::string> sortedOrder; @@ -166,7 +171,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx6.vout.resize(1); tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx6.vout[0].nValue = 20 * COIN; - pool.addUnchecked(tx6.GetHash(), CTxMemPoolEntry(tx6, 0LL, 1, 10.0, 1, true)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6); // Check that at this point, tx6 is sorted low sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); @@ -186,11 +191,10 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) CTxMemPool::setEntries setAncestorsCalculated; std::string dummy; - CTxMemPoolEntry entry7(tx7, 2000000LL, 1, 10.0, 1, true); - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry7, setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 2000000LL, 1, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors); BOOST_CHECK_EQUAL(pool.size(), 7); // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... @@ -208,7 +212,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx8.vout[0].nValue = 10 * COIN; setAncestors.insert(pool.mapTx.find(tx7.GetHash())); - pool.addUnchecked(tx8.GetHash(), CTxMemPoolEntry(tx8, 0LL, 2, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); // Now tx8 should be sorted low, but tx6/tx both high sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); @@ -222,7 +226,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx9.vout.resize(1); tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx9.vout[0].nValue = 1 * COIN; - pool.addUnchecked(tx9.GetHash(), CTxMemPoolEntry(tx9, 0LL, 3, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9); @@ -245,11 +249,10 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx10.vout[0].nValue = 10 * COIN; setAncestorsCalculated.clear(); - CTxMemPoolEntry entry10(tx10, 200000LL, 4, 10.0, 1, true); - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry10, setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx10.GetHash(), CTxMemPoolEntry(tx10, 200000LL, 4, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors); /** * tx8 and tx9 should both now be sorted higher @@ -284,6 +287,8 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) { CTxMemPool pool(CFeeRate(1000)); + TestMemPoolEntryHelper entry; + entry.dPriority = 10.0; CMutableTransaction tx1 = CMutableTransaction(); tx1.vin.resize(1); @@ -291,7 +296,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), CTxMemPoolEntry(tx1, 10000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx1))); + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool)); CMutableTransaction tx2 = CMutableTransaction(); tx2.vin.resize(1); @@ -299,7 +304,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; tx2.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 5000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx2))); + pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool)); pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing BOOST_CHECK(pool.exists(tx1.GetHash())); @@ -309,7 +314,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx1.GetHash())); BOOST_CHECK(!pool.exists(tx2.GetHash())); - pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 5000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx2))); + pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool)); CMutableTransaction tx3 = CMutableTransaction(); tx3.vin.resize(1); tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); @@ -317,7 +322,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; tx3.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx3.GetHash(), CTxMemPoolEntry(tx3, 20000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx3))); + pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool)); pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) BOOST_CHECK(!pool.exists(tx1.GetHash())); @@ -377,13 +382,13 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx7.vout.resize(2); tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[0].nValue = 10 * COIN; - tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; - tx7.vout[0].nValue = 10 * COIN; + tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; + tx7.vout[1].nValue = 10 * COIN; - pool.addUnchecked(tx4.GetHash(), CTxMemPoolEntry(tx4, 7000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx4))); - pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5))); - pool.addUnchecked(tx6.GetHash(), CTxMemPoolEntry(tx6, 1100LL, 0, 10.0, 1, pool.HasNoInputsOf(tx6))); - pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 9000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx7))); + pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that pool.TrimToSize(pool.DynamicMemoryUsage() - 1); @@ -392,8 +397,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(!pool.exists(tx7.GetHash())); if (!pool.exists(tx5.GetHash())) - pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5))); - pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 9000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx7))); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 BOOST_CHECK(pool.exists(tx4.GetHash())); @@ -401,8 +406,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx6.GetHash())); BOOST_CHECK(!pool.exists(tx7.GetHash())); - pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5))); - pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 9000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx7))); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); std::vector<CTransaction> vtx; std::list<CTransaction> conflicts; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 827525783a..dc20e34634 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -59,17 +59,22 @@ struct { // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { + const CChainParams& chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CMutableTransaction tx,tx2; CScript script; uint256 hash; + TestMemPoolEntryHelper entry; + entry.nFee = 11; + entry.dPriority = 111.0; + entry.nHeight = 11; LOCK(cs_main); fCheckpointsEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -91,14 +96,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = pblock->ComputeMerkleRoot(); pblock->nNonce = blockinfo[i].nonce; CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL)); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -113,10 +118,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -133,17 +138,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { tx.vout[0].nValue -= 10000000; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -152,7 +157,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 4900000000LL; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -160,8 +165,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[1].prevout.n = 0; tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -171,8 +176,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; tx.vout[0].nValue = 0; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -184,13 +189,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script; tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -200,21 +205,21 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 4900000000LL; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; @@ -229,7 +234,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = chainActive.Tip()->nHeight+1; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST)); // time locked @@ -243,10 +248,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx2.vout[0].scriptPubKey = CScript() << OP_1; tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1; hash = tx2.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx2)); BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); // Neither tx should have make it into the template. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); @@ -261,7 +266,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) //BOOST_CHECK(CheckFinalTx(tx)); //BOOST_CHECK(CheckFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2); delete pblocktemplate; diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index cb64ee7c69..1315146f10 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -16,6 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) { CTxMemPool mpool(CFeeRate(1000)); + TestMemPoolEntryHelper entry; CAmount basefee(2000); double basepri = 1e6; CAmount deltaFee(100); @@ -63,7 +64,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx))); + mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); txHashes[j].push_back(hash); } } @@ -83,11 +84,18 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) block.clear(); if (blocknum == 30) { // At this point we should need to combine 5 buckets to get enough data points - // So estimateFee(1) should fail and estimateFee(2) should return somewhere around - // 8*baserate + // So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around + // 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98% BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); - BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee); - BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee); + BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee); + int answerFound; + BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8); } } @@ -96,9 +104,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // Highest feerate is 10*baseRate and gets in all blocks, // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, - // so estimateFee(1) should return 9*baseRate. - // Third highest feerate has 90% chance of being included by 2 blocks, - // so estimateFee(2) should return 8*baseRate etc... + // so estimateFee(1) should return 10*baseRate. + // Second highest feerate has 100% chance of being included by 2 blocks, + // so estimateFee(2) should return 9*baseRate etc... for (int i = 1; i < 10;i++) { origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); origPriEst.push_back(mpool.estimatePriority(i)); @@ -106,10 +114,11 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]); } - BOOST_CHECK(origFeeEst[i-1] < (10-i)*baseRate.GetFeePerK() + deltaFee); - BOOST_CHECK(origFeeEst[i-1] > (10-i)*baseRate.GetFeePerK() - deltaFee); - BOOST_CHECK(origPriEst[i-1] < pow(10,10-i) * basepri + deltaPri); - BOOST_CHECK(origPriEst[i-1] > pow(10,10-i) * basepri - deltaPri); + int mult = 11-i; + BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); + BOOST_CHECK(origPriEst[i-1] < pow(10,mult) * basepri + deltaPri); + BOOST_CHECK(origPriEst[i-1] > pow(10,mult) * basepri - deltaPri); } // Mine 50 more blocks with no transactions happening, estimates shouldn't change @@ -132,16 +141,19 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx))); + mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); txHashes[j].push_back(hash); } } mpool.removeForBlock(block, ++blocknum, dummyConflicted); } + int answerFound; for (int i = 1; i < 10;i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); - BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); + BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee); + BOOST_CHECK(mpool.estimatePriority(i) == -1 || mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); + BOOST_CHECK(mpool.estimateSmartPriority(i, &answerFound) > origPriEst[answerFound-1] - deltaPri); } // Mine all those transactions @@ -161,14 +173,14 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); } - // Mine 100 more blocks where everything is mined every block - // Estimates should be below original estimates (not possible for last estimate) - while (blocknum < 365) { + // Mine 200 more blocks where everything is mined every block + // Estimates should be below original estimates + while (blocknum < 465) { for (int j = 0; j < 10; j++) { // For each fee/pri multiple for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx))); + mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); CTransaction btx; if (mpool.lookup(hash, btx)) block.push_back(btx); @@ -177,10 +189,22 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) mpool.removeForBlock(block, ++blocknum, dummyConflicted); block.clear(); } - for (int i = 1; i < 9; i++) { + for (int i = 1; i < 10; i++) { BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri); } + + // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee + // and that estimateSmartPriority returns essentially an infinite value + mpool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, feeV[0][5], GetTime(), priV[1][5], blocknum, mpool.HasNoInputsOf(tx))); + // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5] + mpool.TrimToSize(1); + BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]); + for (int i = 1; i < 10; i++) { + BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK()); + BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK()); + BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 23e5e66d84..9a3517a27b 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -15,6 +15,7 @@ #include "pubkey.h" #include "random.h" #include "txdb.h" +#include "txmempool.h" #include "ui_interface.h" #include "util.h" #ifdef ENABLE_WALLET @@ -114,7 +115,8 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) { - CBlockTemplate *pblocktemplate = CreateNewBlock(scriptPubKey); + const CChainParams& chainparams = Params(); + CBlockTemplate *pblocktemplate = CreateNewBlock(chainparams, scriptPubKey); CBlock& block = pblocktemplate->block; // Replace mempool-selected txns with just coinbase plus passed-in txns: @@ -125,10 +127,10 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& unsigned int extraNonce = 0; IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); - while (!CheckProofOfWork(block.GetHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CValidationState state; - ProcessNewBlock(state, NULL, &block, true, NULL); + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); CBlock result = block; delete pblocktemplate; @@ -139,6 +141,12 @@ TestChain100Setup::~TestChain100Setup() { } + +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) { + return CTxMemPoolEntry(tx, nFee, nTime, dPriority, nHeight, + pool ? pool->HasNoInputsOf(tx) : hadNoDependencies); +} + void Shutdown(void* parg) { exit(0); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 0bab4b6831..815b227411 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -3,6 +3,7 @@ #include "chainparamsbase.h" #include "key.h" +#include "pubkey.h" #include "txdb.h" #include <boost/filesystem.hpp> @@ -12,6 +13,8 @@ * This just configures logging and chain parameters. */ struct BasicTestingSetup { + ECCVerifyHandle globalVerifyHandle; + BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~BasicTestingSetup(); }; @@ -51,4 +54,29 @@ struct TestChain100Setup : public TestingSetup { CKey coinbaseKey; // private/public key needed to spend coinbase transactions }; +class CTxMemPoolEntry; +class CTxMemPool; + +struct TestMemPoolEntryHelper +{ + // Default values + CAmount nFee; + int64_t nTime; + double dPriority; + unsigned int nHeight; + bool hadNoDependencies; + + TestMemPoolEntryHelper() : + nFee(0), nTime(0), dPriority(0.0), nHeight(1), + hadNoDependencies(false) { } + + CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL); + + // Change the default value + TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; } + TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; } + TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; } + TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; } + TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; } +}; #endif diff --git a/src/timedata.cpp b/src/timedata.cpp index 0641009537..861c375989 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -55,7 +55,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) // Add data static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0); vTimeOffsets.input(nOffsetSample); - LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); + LogPrint("net","added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); // There is a known issue here (see issue #4521): // @@ -105,11 +105,11 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) } } } - if (fDebug) { - BOOST_FOREACH(int64_t n, vSorted) - LogPrintf("%+d ", n); - LogPrintf("| "); - } - LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); + + BOOST_FOREACH(int64_t n, vSorted) + LogPrint("net", "%+d ", n); + LogPrint("net", "| "); + + LogPrint("net", "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); } } diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp new file mode 100644 index 0000000000..08644f2968 --- /dev/null +++ b/src/torcontrol.cpp @@ -0,0 +1,685 @@ +#include "torcontrol.h" +#include "utilstrencodings.h" +#include "net.h" +#include "util.h" +#include "crypto/hmac_sha256.h" + +#include <vector> +#include <deque> +#include <set> +#include <stdlib.h> + +#include <boost/function.hpp> +#include <boost/bind.hpp> +#include <boost/signals2/signal.hpp> +#include <boost/foreach.hpp> +#include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> +#include <boost/algorithm/string/replace.hpp> + +#include <event2/bufferevent.h> +#include <event2/buffer.h> +#include <event2/util.h> +#include <event2/event.h> +#include <event2/thread.h> + +/** Default control port */ +const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051"; +/** Tor cookie size (from control-spec.txt) */ +static const int TOR_COOKIE_SIZE = 32; +/** Size of client/server nonce for SAFECOOKIE */ +static const int TOR_NONCE_SIZE = 32; +/** For computing serverHash in SAFECOOKIE */ +static const std::string TOR_SAFE_SERVERKEY = "Tor safe cookie authentication server-to-controller hash"; +/** For computing clientHash in SAFECOOKIE */ +static const std::string TOR_SAFE_CLIENTKEY = "Tor safe cookie authentication controller-to-server hash"; +/** Exponential backoff configuration - initial timeout in seconds */ +static const float RECONNECT_TIMEOUT_START = 1.0; +/** Exponential backoff configuration - growth factor */ +static const float RECONNECT_TIMEOUT_EXP = 1.5; +/** Maximum length for lines received on TorControlConnection. + * tor-control-spec.txt mentions that there is explicitly no limit defined to line length, + * this is belt-and-suspenders sanity limit to prevent memory exhaustion. + */ +static const int MAX_LINE_LENGTH = 100000; + +/****** Low-level TorControlConnection ********/ + +/** Reply from Tor, can be single or multi-line */ +class TorControlReply +{ +public: + TorControlReply() { Clear(); } + + int code; + std::vector<std::string> lines; + + void Clear() + { + code = 0; + lines.clear(); + } +}; + +/** Low-level handling for Tor control connection. + * Speaks the SMTP-like protocol as defined in torspec/control-spec.txt + */ +class TorControlConnection +{ +public: + typedef boost::function<void(TorControlConnection&)> ConnectionCB; + typedef boost::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB; + + /** Create a new TorControlConnection. + */ + TorControlConnection(struct event_base *base); + ~TorControlConnection(); + + /** + * Connect to a Tor control port. + * target is address of the form host:port. + * connected is the handler that is called when connection is succesfully established. + * disconnected is a handler that is called when the connection is broken. + * Return true on success. + */ + bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected); + + /** + * Disconnect from Tor control port. + */ + bool Disconnect(); + + /** Send a command, register a handler for the reply. + * A trailing CRLF is automatically added. + * Return true on success. + */ + bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler); + + /** Response handlers for async replies */ + boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler; +private: + /** Callback when ready for use */ + boost::function<void(TorControlConnection&)> connected; + /** Callback when connection lost */ + boost::function<void(TorControlConnection&)> disconnected; + /** Libevent event base */ + struct event_base *base; + /** Connection to control socket */ + struct bufferevent *b_conn; + /** Message being received */ + TorControlReply message; + /** Response handlers */ + std::deque<ReplyHandlerCB> reply_handlers; + + /** Libevent handlers: internal */ + static void readcb(struct bufferevent *bev, void *ctx); + static void eventcb(struct bufferevent *bev, short what, void *ctx); +}; + +TorControlConnection::TorControlConnection(struct event_base *base): + base(base), b_conn(0) +{ +} + +TorControlConnection::~TorControlConnection() +{ + if (b_conn) + bufferevent_free(b_conn); +} + +void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) +{ + TorControlConnection *self = (TorControlConnection*)ctx; + struct evbuffer *input = bufferevent_get_input(bev); + size_t n_read_out = 0; + char *line; + assert(input); + // If there is not a whole line to read, evbuffer_readln returns NULL + while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != NULL) + { + std::string s(line, n_read_out); + free(line); + if (s.size() < 4) // Short line + continue; + // <status>(-|+| )<data><CRLF> + self->message.code = atoi(s.substr(0,3)); + self->message.lines.push_back(s.substr(4)); + char ch = s[3]; // '-','+' or ' ' + if (ch == ' ') { + // Final line, dispatch reply and clean up + if (self->message.code >= 600) { + // Dispatch async notifications to async handler + // Synchronous and asynchronous messages are never interleaved + self->async_handler(*self, self->message); + } else { + if (!self->reply_handlers.empty()) { + // Invoke reply handler with message + self->reply_handlers.front()(*self, self->message); + self->reply_handlers.pop_front(); + } else { + LogPrint("tor", "tor: Received unexpected sync reply %i\n", self->message.code); + } + } + self->message.Clear(); + } + } + // Check for size of buffer - protect against memory exhaustion with very long lines + // Do this after evbuffer_readln to make sure all full lines have been + // removed from the buffer. Everything left is an incomplete line. + if (evbuffer_get_length(input) > MAX_LINE_LENGTH) { + LogPrintf("tor: Disconnecting because MAX_LINE_LENGTH exceeded\n"); + self->Disconnect(); + } +} + +void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx) +{ + TorControlConnection *self = (TorControlConnection*)ctx; + if (what & BEV_EVENT_CONNECTED) { + LogPrint("tor", "tor: Succesfully connected!\n"); + self->connected(*self); + } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { + if (what & BEV_EVENT_ERROR) + LogPrint("tor", "tor: Error connecting to Tor control socket\n"); + else + LogPrint("tor", "tor: End of stream\n"); + self->Disconnect(); + self->disconnected(*self); + } +} + +bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected) +{ + if (b_conn) + Disconnect(); + // Parse target address:port + struct sockaddr_storage connect_to_addr; + int connect_to_addrlen = sizeof(connect_to_addr); + if (evutil_parse_sockaddr_port(target.c_str(), + (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) { + LogPrintf("tor: Error parsing socket address %s\n", target); + return false; + } + + // Create a new socket, set up callbacks and enable notification bits + b_conn = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); + if (!b_conn) + return false; + bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this); + bufferevent_enable(b_conn, EV_READ|EV_WRITE); + this->connected = connected; + this->disconnected = disconnected; + + // Finally, connect to target + if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { + LogPrintf("tor: Error connecting to address %s\n", target); + return false; + } + return true; +} + +bool TorControlConnection::Disconnect() +{ + if (b_conn) + bufferevent_free(b_conn); + b_conn = 0; + return true; +} + +bool TorControlConnection::Command(const std::string &cmd, const ReplyHandlerCB& reply_handler) +{ + if (!b_conn) + return false; + struct evbuffer *buf = bufferevent_get_output(b_conn); + if (!buf) + return false; + evbuffer_add(buf, cmd.data(), cmd.size()); + evbuffer_add(buf, "\r\n", 2); + reply_handlers.push_back(reply_handler); + return true; +} + +/****** General parsing utilities ********/ + +/* Split reply line in the form 'AUTH METHODS=...' into a type + * 'AUTH' and arguments 'METHODS=...'. + */ +static std::pair<std::string,std::string> SplitTorReplyLine(const std::string &s) +{ + size_t ptr=0; + std::string type; + while (ptr < s.size() && s[ptr] != ' ') { + type.push_back(s[ptr]); + ++ptr; + } + if (ptr < s.size()) + ++ptr; // skip ' ' + return make_pair(type, s.substr(ptr)); +} + +/** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=".../control_auth_cookie"'. + */ +static std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s) +{ + std::map<std::string,std::string> mapping; + size_t ptr=0; + while (ptr < s.size()) { + std::string key, value; + while (ptr < s.size() && s[ptr] != '=') { + key.push_back(s[ptr]); + ++ptr; + } + if (ptr == s.size()) // unexpected end of line + return std::map<std::string,std::string>(); + ++ptr; // skip '=' + if (ptr < s.size() && s[ptr] == '"') { // Quoted string + ++ptr; // skip '=' + bool escape_next = false; + while (ptr < s.size() && (!escape_next && s[ptr] != '"')) { + escape_next = (s[ptr] == '\\'); + value.push_back(s[ptr]); + ++ptr; + } + if (ptr == s.size()) // unexpected end of line + return std::map<std::string,std::string>(); + ++ptr; // skip closing '"' + /* TODO: unescape value - according to the spec this depends on the + * context, some strings use C-LogPrintf style escape codes, some + * don't. So may be better handled at the call site. + */ + } else { // Unquoted value. Note that values can contain '=' at will, just no spaces + while (ptr < s.size() && s[ptr] != ' ') { + value.push_back(s[ptr]); + ++ptr; + } + } + if (ptr < s.size() && s[ptr] == ' ') + ++ptr; // skip ' ' after key=value + mapping[key] = value; + } + return mapping; +} + +/** Read full contents of a file and return them in a std::string. + * Returns a pair <status, string>. + * If an error occured, status will be false, otherwise status will be true and the data will be returned in string. + * + * @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data + * (with len > maxsize) will be returned. + */ +static std::pair<bool,std::string> ReadBinaryFile(const std::string &filename, size_t maxsize=std::numeric_limits<size_t>::max()) +{ + FILE *f = fopen(filename.c_str(), "rb"); + if (f == NULL) + return std::make_pair(false,""); + std::string retval; + char buffer[128]; + size_t n; + while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) { + retval.append(buffer, buffer+n); + if (retval.size() > maxsize) + break; + } + fclose(f); + return std::make_pair(true,retval); +} + +/** Write contents of std::string to a file. + * @return true on success. + */ +static bool WriteBinaryFile(const std::string &filename, const std::string &data) +{ + FILE *f = fopen(filename.c_str(), "wb"); + if (f == NULL) + return false; + if (fwrite(data.data(), 1, data.size(), f) != data.size()) { + fclose(f); + return false; + } + fclose(f); + return true; +} + +/****** Bitcoin specific TorController implementation ********/ + +/** Controller that connects to Tor control socket, authenticate, then create + * and maintain a ephemeral hidden service. + */ +class TorController +{ +public: + TorController(struct event_base* base, const std::string& target); + ~TorController(); + + /** Get name fo file to store private key in */ + std::string GetPrivateKeyFile(); + + /** Reconnect, after getting disconnected */ + void Reconnect(); +private: + struct event_base* base; + std::string target; + TorControlConnection conn; + std::string private_key; + std::string service_id; + bool reconnect; + struct event *reconnect_ev; + float reconnect_timeout; + CService service; + /** Cooie for SAFECOOKIE auth */ + std::vector<uint8_t> cookie; + /** ClientNonce for SAFECOOKIE auth */ + std::vector<uint8_t> clientNonce; + + /** Callback for ADD_ONION result */ + void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for AUTHENTICATE result */ + void auth_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for AUTHCHALLENGE result */ + void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for PROTOCOLINFO result */ + void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback after succesful connection */ + void connected_cb(TorControlConnection& conn); + /** Callback after connection lost or failed connection attempt */ + void disconnected_cb(TorControlConnection& conn); + + /** Callback for reconnect timer */ + static void reconnect_cb(evutil_socket_t fd, short what, void *arg); +}; + +TorController::TorController(struct event_base* base, const std::string& target): + base(base), + target(target), conn(base), reconnect(true), reconnect_ev(0), + reconnect_timeout(RECONNECT_TIMEOUT_START) +{ + // Start connection attempts immediately + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + boost::bind(&TorController::disconnected_cb, this, _1) )) { + LogPrintf("tor: Initiating connection to Tor control port %s failed\n", target); + } + // Read service private key if cached + std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile()); + if (pkf.first) { + LogPrint("tor", "tor: Reading cached private key from %s\n", GetPrivateKeyFile()); + private_key = pkf.second; + } +} + +TorController::~TorController() +{ + if (reconnect_ev) + event_del(reconnect_ev); + if (service.IsValid()) { + RemoveLocal(service); + } +} + +void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: ADD_ONION succesful\n"); + BOOST_FOREACH(const std::string &s, reply.lines) { + std::map<std::string,std::string> m = ParseTorReplyMapping(s); + std::map<std::string,std::string>::iterator i; + if ((i = m.find("ServiceID")) != m.end()) + service_id = i->second; + if ((i = m.find("PrivateKey")) != m.end()) + private_key = i->second; + } + + service = CService(service_id+".onion", GetListenPort(), false); + LogPrintf("tor: Got service ID %s, advertizing service %s\n", service_id, service.ToString()); + if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { + LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); + } else { + LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile()); + } + AddLocal(service, LOCAL_MANUAL); + // ... onion requested - keep connection open + } else if (reply.code == 510) { // 510 Unrecognized command + LogPrintf("tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\n"); + } else { + LogPrintf("tor: Add onion failed; error code %d\n", reply.code); + } +} + +void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: Authentication succesful\n"); + // Finally - now create the service + if (private_key.empty()) // No private key, generate one + private_key = "NEW:BEST"; + // Request hidden service, redirect port. + // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient + // choice. TODO; refactor the shutdown sequence some day. + conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()), + boost::bind(&TorController::add_onion_cb, this, _1, _2)); + } else { + LogPrintf("tor: Authentication failed\n"); + } +} + +/** Compute Tor SAFECOOKIE response. + * + * ServerHash is computed as: + * HMAC-SHA256("Tor safe cookie authentication server-to-controller hash", + * CookieString | ClientNonce | ServerNonce) + * (with the HMAC key as its first argument) + * + * After a controller sends a successful AUTHCHALLENGE command, the + * next command sent on the connection must be an AUTHENTICATE command, + * and the only authentication string which that AUTHENTICATE command + * will accept is: + * + * HMAC-SHA256("Tor safe cookie authentication controller-to-server hash", + * CookieString | ClientNonce | ServerNonce) + * + */ +static std::vector<uint8_t> ComputeResponse(const std::string &key, const std::vector<uint8_t> &cookie, const std::vector<uint8_t> &clientNonce, const std::vector<uint8_t> &serverNonce) +{ + CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size()); + std::vector<uint8_t> computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0); + computeHash.Write(begin_ptr(cookie), cookie.size()); + computeHash.Write(begin_ptr(clientNonce), clientNonce.size()); + computeHash.Write(begin_ptr(serverNonce), serverNonce.size()); + computeHash.Finalize(begin_ptr(computedHash)); + return computedHash; +} + +void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: SAFECOOKIE authentication challenge succesful\n"); + std::pair<std::string,std::string> l = SplitTorReplyLine(reply.lines[0]); + if (l.first == "AUTHCHALLENGE") { + std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); + std::vector<uint8_t> serverHash = ParseHex(m["SERVERHASH"]); + std::vector<uint8_t> serverNonce = ParseHex(m["SERVERNONCE"]); + LogPrint("tor", "tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce)); + if (serverNonce.size() != 32) { + LogPrintf("tor: ServerNonce is not 32 bytes, as required by spec\n"); + return; + } + + std::vector<uint8_t> computedServerHash = ComputeResponse(TOR_SAFE_SERVERKEY, cookie, clientNonce, serverNonce); + if (computedServerHash != serverHash) { + LogPrintf("tor: ServerHash %s does not match expected ServerHash %s\n", HexStr(serverHash), HexStr(computedServerHash)); + return; + } + + std::vector<uint8_t> computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); + conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); + } + } else { + LogPrintf("tor: SAFECOOKIE authentication challenge failed\n"); + } +} + +void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + std::set<std::string> methods; + std::string cookiefile; + /* + * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="/home/x/.tor/control_auth_cookie" + * 250-AUTH METHODS=NULL + * 250-AUTH METHODS=HASHEDPASSWORD + */ + BOOST_FOREACH(const std::string &s, reply.lines) { + std::pair<std::string,std::string> l = SplitTorReplyLine(s); + if (l.first == "AUTH") { + std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); + std::map<std::string,std::string>::iterator i; + if ((i = m.find("METHODS")) != m.end()) + boost::split(methods, i->second, boost::is_any_of(",")); + if ((i = m.find("COOKIEFILE")) != m.end()) + cookiefile = i->second; + } else if (l.first == "VERSION") { + std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); + std::map<std::string,std::string>::iterator i; + if ((i = m.find("Tor")) != m.end()) { + LogPrint("tor", "tor: Connected to Tor version %s\n", i->second); + } + } + } + BOOST_FOREACH(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 + /* Authentication: + * cookie: hex-encoded ~/.tor/control_auth_cookie + * password: "password" + */ + std::string torpassword = GetArg("-torpassword", ""); + if (methods.count("NULL")) { + LogPrint("tor", "tor: Using NULL authentication\n"); + conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else if (methods.count("SAFECOOKIE")) { + // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie + LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); + std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); + if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { + // conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); + cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end()); + clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0); + GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); + conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); + } else { + if (status_cookie.first) { + LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE); + } else { + LogPrintf("tor: Authentication cookie %s could not be opened (check permissions)\n", cookiefile); + } + } + } else if (methods.count("HASHEDPASSWORD")) { + if (!torpassword.empty()) { + LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); + boost::replace_all(torpassword, "\"", "\\\""); + conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n"); + } + } else { + LogPrintf("tor: No supported authentication method\n"); + } + } else { + LogPrintf("tor: Requesting protocol info failed\n"); + } +} + +void TorController::connected_cb(TorControlConnection& conn) +{ + reconnect_timeout = RECONNECT_TIMEOUT_START; + // First send a PROTOCOLINFO command to figure out what authentication is expected + if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) + LogPrintf("tor: Error sending initial protocolinfo command\n"); +} + +void TorController::disconnected_cb(TorControlConnection& conn) +{ + // Stop advertizing service when disconnected + if (service.IsValid()) + RemoveLocal(service); + service = CService(); + if (!reconnect) + return; + LogPrintf("tor: Disconnected from Tor control port %s, trying to reconnect\n", target); + // Single-shot timer for reconnect. Use exponential backoff. + struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); + reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); + event_add(reconnect_ev, &time); + reconnect_timeout *= RECONNECT_TIMEOUT_EXP; +} + +void TorController::Reconnect() +{ + /* Try to reconnect and reestablish if we get booted - for example, Tor + * may be restarting. + */ + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + boost::bind(&TorController::disconnected_cb, this, _1) )) { + LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target); + } +} + +std::string TorController::GetPrivateKeyFile() +{ + return (GetDataDir() / "onion_private_key").string(); +} + +void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) +{ + TorController *self = (TorController*)arg; + self->Reconnect(); +} + +/****** Thread ********/ +struct event_base *base; +boost::thread torControlThread; + +static void TorControlThread() +{ + TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); + + event_base_dispatch(base); +} + +void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + assert(!base); +#ifdef WIN32 + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif + base = event_base_new(); + if (!base) { + LogPrintf("tor: Unable to create event_base\n"); + return; + } + + torControlThread = boost::thread(boost::bind(&TraceThread<void (*)()>, "torcontrol", &TorControlThread)); +} + +void InterruptTorControl() +{ + if (base) { + LogPrintf("tor: Thread interrupt\n"); + event_base_loopbreak(base); + } +} + +void StopTorControl() +{ + if (base) { + torControlThread.join(); + event_base_free(base); + base = 0; + } +} + diff --git a/src/torcontrol.h b/src/torcontrol.h new file mode 100644 index 0000000000..72dc82c5b1 --- /dev/null +++ b/src/torcontrol.h @@ -0,0 +1,20 @@ +// 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. + +/** + * Functionality for communicating with Tor. + */ +#ifndef BITCOIN_TORCONTROL_H +#define BITCOIN_TORCONTROL_H + +#include "scheduler.h" + +extern const std::string DEFAULT_TOR_CONTROL; +static const bool DEFAULT_LISTEN_ONION = true; + +void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler); +void InterruptTorControl(); +void StopTorControl(); + +#endif /* BITCOIN_TORCONTROL_H */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a772e7adea..ec7971c2f1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -701,11 +701,21 @@ CFeeRate CTxMemPool::estimateFee(int nBlocks) const LOCK(cs); return minerPolicyEstimator->estimateFee(nBlocks); } +CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this); +} double CTxMemPool::estimatePriority(int nBlocks) const { LOCK(cs); return minerPolicyEstimator->estimatePriority(nBlocks); } +double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, *this); +} bool CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const diff --git a/src/txmempool.h b/src/txmempool.h index 3d8ac435f5..7f43120f7f 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -459,9 +459,21 @@ public: bool lookup(uint256 hash, CTransaction& result) const; + /** Estimate fee rate needed to get into the next nBlocks + * If no answer can be given at nBlocks, return an estimate + * at the lowest number of blocks where one can be given + */ + CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks = NULL) const; + /** Estimate fee rate needed to get into the next nBlocks */ CFeeRate estimateFee(int nBlocks) const; + /** Estimate priority needed to get into the next nBlocks + * If no answer can be given at nBlocks, return an estimate + * at the lowest number of blocks where one can be given + */ + double estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks = NULL) const; + /** Estimate priority needed to get into the next nBlocks */ double estimatePriority(int nBlocks) const; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d93050d98c..b6eaca80b3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -835,7 +835,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) debit.nTime = nNow; debit.strOtherAccount = strTo; debit.strComment = strComment; - walletdb.WriteAccountingEntry(debit); + pwalletMain->AddAccountingEntry(debit, walletdb); // Credit CAccountingEntry credit; @@ -845,7 +845,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) credit.nTime = nNow; credit.strOtherAccount = strFrom; credit.strComment = strComment; - walletdb.WriteAccountingEntry(credit); + pwalletMain->AddAccountingEntry(credit, walletdb); if (!walletdb.TxnCommit()) throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); @@ -1417,7 +1417,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n" " 'move' category for moves outbound. It is positive for the 'receive' category,\n" " and for the 'move' category for inbound funds.\n" - " \"vout\" : n, (numeric) the vout value\n" + " \"vout\": n, (numeric) the vout value\n" " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" " 'send' category of transactions.\n" " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" @@ -1426,12 +1426,13 @@ UniValue listtransactions(const UniValue& params, bool fHelp) " category of transactions.\n" " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n" " category of transactions.\n" + " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n" " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" " for 'send' and 'receive' category of transactions.\n" " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" - " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n" + " \"label\": \"label\" (string) A comment for the address/transaction, if any\n" " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n" " from (for receiving funds, positive amounts), or went to (for sending funds,\n" " negative amounts).\n" @@ -1470,11 +1471,10 @@ UniValue listtransactions(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - std::list<CAccountingEntry> acentries; - CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered; // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) @@ -1579,8 +1579,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) } } - list<CAccountingEntry> acentries; - CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); + const list<CAccountingEntry> & acentries = pwalletMain->laccentries; BOOST_FOREACH(const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; @@ -2396,7 +2395,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) "\nResult:\n" "{\n" " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n" - " \"fee\": n, (numeric) The fee added to the transaction\n" + " \"fee\": n, (numeric) Fee the resulting transaction pays\n" " \"changepos\": n (numeric) The position of the added change output, or -1\n" "}\n" "\"hex\" \n" @@ -2418,9 +2417,12 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) if (!DecodeHexTx(origTx, params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (origTx.vout.size() == 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output"); + bool includeWatching = false; if (params.size() > 1) - includeWatching = true; + includeWatching = params[1].get_bool(); CMutableTransaction tx(origTx); CAmount nFee; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d51b8ddaef..c5246d909e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -588,31 +588,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) return nRet; } -CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount) -{ - AssertLockHeld(cs_wallet); // mapWallet - CWalletDB walletdb(strWalletFile); - - // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. - TxItems txOrdered; - - // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry - // would make this much faster for applications that do this a lot. - for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - CWalletTx* wtx = &((*it).second); - txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); - } - acentries.clear(); - walletdb.ListAccountCreditDebit(strAccount, acentries); - BOOST_FOREACH(CAccountingEntry& entry, acentries) - { - txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); - } - - return txOrdered; -} - void CWallet::MarkDirty() { { @@ -629,7 +604,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD if (fFromLoadWallet) { mapWallet[hash] = wtxIn; - mapWallet[hash].BindWallet(this); + CWalletTx& wtx = mapWallet[hash]; + wtx.BindWallet(this); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(hash); } else @@ -644,6 +621,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(pwalletdb); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); wtx.nTimeSmart = wtx.nTimeReceived; if (!wtxIn.hashBlock.IsNull()) @@ -655,9 +633,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD { // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future int64_t latestTolerated = latestNow + 300; - std::list<CAccountingEntry> acentries; - TxItems txOrdered = OrderedTxItems(acentries); - for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + const TxItems & txOrdered = wtxOrdered; + for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx == &wtx) @@ -2033,13 +2010,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE) { // Not enough fee: enough priority? - double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget); - // Not enough mempool history to estimate: use hard-coded AllowFree. - if (dPriorityNeeded <= 0 && AllowFree(dPriority)) - break; - - // Small enough, and priority high enough, to send for free - if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded) + double dPriorityNeeded = mempool.estimateSmartPriority(nTxConfirmTarget); + // Require at least hard-coded AllowFree. + if (dPriority >= dPriorityNeeded && AllowFree(dPriority)) break; } @@ -2118,6 +2091,18 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) return true; } +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb) +{ + if (!pwalletdb.WriteAccountingEntry_Backend(acentry)) + return false; + + laccentries.push_back(acentry); + CAccountingEntry & entry = laccentries.back(); + wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + + return true; +} + CAmount CWallet::GetRequiredFee(unsigned int nTxBytes) { return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes)); @@ -2131,12 +2116,14 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK()) nFeeNeeded = payTxFee.GetFeePerK(); // User didn't set: use -txconfirmtarget to estimate... - if (nFeeNeeded == 0) - nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes); - // ... unless we don't have enough mempool data, in which case fall - // back to the required fee - if (nFeeNeeded == 0) - nFeeNeeded = GetRequiredFee(nTxBytes); + if (nFeeNeeded == 0) { + int estimateFoundTarget = nConfirmTarget; + nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes); + // ... unless we don't have enough mempool data for our desired target + // so we make sure we're paying at least minTxFee + if (nFeeNeeded == 0 || (unsigned int)estimateFoundTarget > nConfirmTarget) + nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); + } // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes)) nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 719f11f206..7e846569ff 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -531,6 +531,11 @@ public: } std::map<uint256, CWalletTx> mapWallet; + std::list<CAccountingEntry> laccentries; + + typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; + typedef std::multimap<int64_t, TxPair > TxItems; + TxItems wtxOrdered; int64_t nOrderPosNext; std::map<uint256, int> mapRequestCount; @@ -617,16 +622,6 @@ public: */ int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL); - typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; - typedef std::multimap<int64_t, TxPair > TxItems; - - /** - * Get the wallet's activity log - * @return multimap of ordered transactions and accounting entries - * @warning Returned pointers are *only* valid within the scope of passed acentries - */ - TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = ""); - void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); void SyncTransaction(const CTransaction& tx, const CBlock* pblock); @@ -656,6 +651,8 @@ public: std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); + bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); + static CFeeRate minTxFee; /** * Estimate the minimum fee considering user set parameters diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index ea8a4eb043..9ce9f53bd9 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -191,7 +191,7 @@ bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccount return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry); } -bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) +bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry) { return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } @@ -709,6 +709,12 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = ReorderTransactions(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))); + } + return result; } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 270f826aed..3ebc05afd1 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -110,6 +110,9 @@ public: bool WriteMinVersion(int nVersion); + /// This writes directly to the database, and will not update the CWallet's cached accounting entries! + /// Use wallet.AddAccountingEntry instead, to write *and* update its caches. + bool WriteAccountingEntry_Backend(const CAccountingEntry& acentry); bool ReadAccount(const std::string& strAccount, CAccount& account); bool WriteAccount(const std::string& strAccount, const CAccount& account); @@ -118,7 +121,6 @@ public: /// Erase destination data tuple from wallet database bool EraseDestData(const std::string &address, const std::string &key); - bool WriteAccountingEntry(const CAccountingEntry& acentry); CAmount GetAccountCreditDebit(const std::string& strAccount); void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 09fe3aeb4c..be2aec7d15 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -12,7 +12,7 @@ void zmqError(const char *str) { - LogPrint("zmq", "Error: %s, errno=%s\n", str, zmq_strerror(errno)); + LogPrint("zmq", "zmq: Error: %s, errno=%s\n", str, zmq_strerror(errno)); } CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL) @@ -72,7 +72,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const // Called at startup to conditionally set up ZMQ socket(s) bool CZMQNotificationInterface::Initialize() { - LogPrint("zmq", "Initialize notification interface\n"); + LogPrint("zmq", "zmq: Initialize notification interface\n"); assert(!pcontext); pcontext = zmq_init(1); @@ -110,7 +110,7 @@ bool CZMQNotificationInterface::Initialize() // Called during shutdown sequence void CZMQNotificationInterface::Shutdown() { - LogPrint("zmq", "Shutdown notification interface\n"); + LogPrint("zmq", "zmq: Shutdown notification interface\n"); if (pcontext) { for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i) diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index ac788843eb..ddc8fe93e9 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -78,7 +78,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) } else { - LogPrint("zmq", " Reuse socket for address %s\n", address); + LogPrint("zmq", "zmq: Reusing socket for address %s\n", address); psocket = i->second->psocket; mapPublishNotifiers.insert(std::make_pair(address, this)); @@ -120,7 +120,7 @@ void CZMQAbstractPublishNotifier::Shutdown() bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint("zmq", "Publish hash block %s\n", hash.GetHex()); + LogPrint("zmq", "zmq: Publish hashblock %s\n", hash.GetHex()); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -131,7 +131,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint("zmq", "Publish hash transaction %s\n", hash.GetHex()); + LogPrint("zmq", "zmq: Publish hashtx %s\n", hash.GetHex()); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -141,7 +141,7 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { - LogPrint("zmq", "Publish raw block %s\n", pindex->GetBlockHash().GetHex()); + LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -164,7 +164,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint("zmq", "Publish raw transaction %s\n", hash.GetHex()); + LogPrint("zmq", "zmq: Publish rawtx %s\n", hash.GetHex()); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << transaction; int rc = zmq_send_multipart(psocket, "rawtx", 5, &(*ss.begin()), ss.size(), 0); |