diff options
193 files changed, 2129 insertions, 1483 deletions
diff --git a/.travis.yml b/.travis.yml index 8b9ede3e1c..3c995be9a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ matrix: - compiler: ": 32-bit + dash" env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat" USE_SHELL="/bin/dash" - compiler: ": Cross-Mac" - env: HOST=x86_64-apple-darwin11 PACKAGES="cmake libcap-dev libz-dev libbz2-dev" OSX_SDK=10.7 GOAL="deploy" + env: HOST=x86_64-apple-darwin11 PACKAGES="cmake libcap-dev libz-dev libbz2-dev" OSX_SDK=10.9 GOAL="deploy" - compiler: ": Win64" env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui" MAKEJOBS="-j2" - compiler: ": Win32" diff --git a/Makefile.am b/Makefile.am index 5649770602..c59648fd02 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EX OSX_APP=Bitcoin-Qt.app OSX_DMG=Bitcoin-Qt.dmg +OSX_BACKGROUND_IMAGE=background.tiff OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns @@ -30,7 +31,7 @@ WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ $(top_srcdir)/doc/README_windows.txt OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ - $(top_srcdir)/contrib/macdeploy/background.png \ + $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ $(top_srcdir)/contrib/macdeploy/DS_Store \ $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh @@ -95,7 +96,7 @@ $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) deploydir: $(OSX_DMG) else APP_DIST_DIR=$(top_builddir)/dist -APP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/background.png $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications +APP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE) $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications $(APP_DIST_DIR)/Applications: @rm -f $@ @@ -106,11 +107,11 @@ $(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-Qt" -no-pad -r -apple -o $@ dist -$(APP_DIST_DIR)/.background/background.png: +$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) $(MKDIR_P) $(@D) - $(INSTALL) $(top_srcdir)/contrib/macdeploy/background.png $@ -$(APP_DIST_DIR)/.DS_Store: - $(INSTALL) $(top_srcdir)/contrib/macdeploy/DS_Store $@ + $(INSTALL) $< $@ +$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/DS_Store + $(INSTALL) $< $@ $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 diff --git a/configure.ac b/configure.ac index 9ca2f19bf9..85e3d1d669 100644 --- a/configure.ac +++ b/configure.ac @@ -64,13 +64,6 @@ AC_PATH_PROG(CCACHE,ccache) AC_PATH_PROG(XGETTEXT,xgettext) AC_PATH_PROG(HEXDUMP,hexdump) -# This m4 will only be used if a system copy cannot be found. This is helpful -# on systems where autotools are installed but the pkg-config macros are not in -# a default location. It is currently used for building on OSX where autotools -# are preinstalled but pkg-config comes from macports or homebrew. It should -# probably be removed when building on <= 10.6 is no longer supported. -m4_include([pkg.m4]) - dnl pkg-config check. PKG_PROG_PKG_CONFIG diff --git a/contrib/debian/manpages/bitcoind.1 b/contrib/debian/manpages/bitcoind.1 index a1b17d6077..c225b9f3e9 100644 --- a/contrib/debian/manpages/bitcoind.1 +++ b/contrib/debian/manpages/bitcoind.1 @@ -85,19 +85,19 @@ This help message Safely copies *wallet.dat* to 'destination', which can be a directory or a path with filename. .TP \fBgetaccount 'bitcoinaddress'\fR -Returns the account associated with the given address. +DEPRECATED. Returns the account associated with the given address. .TP \fBsetaccount 'bitcoinaddress' ['account']\fR -Sets the ['account'] associated with the given address. ['account'] may be omitted to remove an address from ['account']. +DEPRECATED. Sets the ['account'] associated with the given address. ['account'] may be omitted to remove an address from ['account']. .TP \fBgetaccountaddress 'account'\fR -Returns a new bitcoin address for 'account'. +DEPRECATED. Returns a new bitcoin address for 'account'. .TP \fBgetaddressesbyaccount 'account'\fR -Returns the list of addresses associated with the given 'account'. +DEPRECATED. Returns the list of addresses associated with the given 'account'. .TP \fBgetbalance 'account'\fR -Returns the server's available balance, or the balance for 'account'. +Returns the server's available balance, or the balance for 'account' (accounts are deprecated). .TP \fBgetblockcount\fR Returns the number of blocks in the longest block chain. @@ -124,10 +124,10 @@ Returns a recent hashes per second performance measurement while generating. Returns an object containing server information. .TP \fBgetnewaddress 'account'\fR -Returns a new bitcoin address for receiving payments. If 'account' is specified (recommended), it is added to the address book so payments received with the address will be credited to 'account'. +Returns a new bitcoin address for receiving payments. If 'account' is specified (deprecated), it is added to the address book so payments received with the address will be credited to 'account'. .TP \fBgetreceivedbyaccount 'account' ['minconf=1']\fR -Returns the total amount received by addresses associated with 'account' in transactions with at least ['minconf'] confirmations. +DEPRECATED. Returns the total amount received by addresses associated with 'account' in transactions with at least ['minconf'] confirmations. .TP \fBgetreceivedbyaddress 'bitcoinaddress' ['minconf=1']\fR Returns the total amount received by 'bitcoinaddress' in transactions with at least ['minconf'] confirmations. @@ -147,13 +147,13 @@ If 'data' is specified, tries to solve the block and returns true if it was succ List commands, or get help for a command. .TP \fBlistaccounts ['minconf=1']\fR -List accounts and their current balances. +DEPRECATED. List accounts and their current balances. *note: requires bitcoin 0.3.20 or later. .TP \fBlistreceivedbyaccount ['minconf=1'] ['includeempty=false']\fR ['minconf'] is the minimum number of confirmations before payments are included. ['includeempty'] whether to include addresses that haven't received any payments. Returns an array of objects containing: - "account" : the account of the receiving address. + "account" : DEPRECATED. the account of the receiving address. "amount" : total amount received by the address. "confirmations" : number of confirmations of the most recent transaction included. .TP @@ -161,7 +161,7 @@ List accounts and their current balances. ['minconf'] is the minimum number of confirmations before payments are included. ['includeempty'] whether to include addresses that haven't received any payments. Returns an array of objects containing: "address" : receiving address. - "account" : the account of the receiving address. + "account" : DEPRECATED. the account of the receiving address. "amount" : total amount received by the address. "confirmations" : number of confirmations of the most recent transaction included. .TP @@ -180,10 +180,10 @@ Returns a list of the last ['count'] transactions for 'account' \- for all accou *note: requires bitcoin 0.3.20 or later. .TP \fBmove <'fromaccount'> <'toaccount'> <'amount'> ['minconf=1'] ['comment']\fR -Moves funds between accounts. +DEPRECATED. Moves funds between accounts. .TP \fBsendfrom* <'account'> <'bitcoinaddress'> <'amount'> ['minconf=1'] ['comment'] ['comment-to']\fR -Sends amount from account's balance to 'bitcoinaddress'. This method will fail if there is less than amount bitcoins with ['minconf'] confirmations in the account's balance (unless account is the empty-string-named default account; it behaves like the *sendtoaddress* method). Returns transaction ID on success. +DEPRECATED. Sends amount from account's balance to 'bitcoinaddress'. This method will fail if there is less than amount bitcoins with ['minconf'] confirmations in the account's balance (unless account is the empty-string-named default account; it behaves like the *sendtoaddress* method). Returns transaction ID on success. .TP \fBsendtoaddress 'bitcoinaddress' 'amount' ['comment'] ['comment-to']\fR Sends amount from the server's available balance to 'bitcoinaddress'. amount is a real and is rounded to the nearest 0.01. Returns transaction id on success. diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py new file mode 100755 index 0000000000..38aaa00f31 --- /dev/null +++ b/contrib/devtools/optimize-pngs.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +import os +import sys +import subprocess +import hashlib +from PIL import Image + +def file_hash(filename): + '''Return hash of raw file contents''' + with open(filename, 'rb') as f: + return hashlib.sha256(f.read()).hexdigest() + +def content_hash(filename): + '''Return hash of RGBA contents of image''' + i = Image.open(filename) + i = i.convert('RGBA') + data = i.tostring() + return hashlib.sha256(data).hexdigest() + +#optimize png, remove various color profiles, remove ancillary chunks (alla) and text chunks (text) +#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text + +pngcrush = 'pngcrush' +git = 'git' +folders = ["src/qt/res/movies", "src/qt/res/icons", "src/qt/res/images"] +basePath = subprocess.check_output([git, 'rev-parse', '--show-toplevel']).rstrip('\n') +totalSaveBytes = 0 + +outputArray = [] +for folder in folders: + absFolder=os.path.join(basePath, folder) + for file in os.listdir(absFolder): + extension = os.path.splitext(file)[1] + if extension.lower() == '.png': + print("optimizing "+file+"..."), + file_path = os.path.join(absFolder, file) + fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}; + fileMetaMap['contentHashPre'] = content_hash(file_path) + + pngCrushOutput = "" + try: + pngCrushOutput = subprocess.check_output( + [pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path], + stderr=subprocess.STDOUT).rstrip('\n') + except: + print "pngcrush is not installed, aborting..." + sys.exit(0) + + #verify + if "Not a PNG file" in subprocess.check_output([pngcrush, "-n", "-v", file_path], stderr=subprocess.STDOUT): + print "PNG file "+file+" is corrupted after crushing, check out pngcursh version" + sys.exit(1) + + fileMetaMap['sha256New'] = file_hash(file_path) + fileMetaMap['contentHashPost'] = content_hash(file_path) + + if fileMetaMap['contentHashPre'] != fileMetaMap['contentHashPost']: + print "Image contents of PNG file "+file+" before and after crushing don't match" + sys.exit(1) + + fileMetaMap['psize'] = os.path.getsize(file_path) + outputArray.append(fileMetaMap) + print("done\n"), + +print "summary:\n+++++++++++++++++" +for fileDict in outputArray: + oldHash = fileDict['sha256Old'] + newHash = fileDict['sha256New'] + totalSaveBytes += fileDict['osize'] - fileDict['psize'] + print fileDict['file']+"\n size diff from: "+str(fileDict['osize'])+" to: "+str(fileDict['psize'])+"\n old sha256: "+oldHash+"\n new sha256: "+newHash+"\n" + +print "completed. Total reduction: "+str(totalSaveBytes)+" bytes" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 0732d35301..3ca42248d4 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -23,7 +23,7 @@ remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" files: -- "MacOSX10.7.sdk.tar.gz" +- "MacOSX10.9.sdk.tar.gz" script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-apple-darwin11" @@ -72,7 +72,7 @@ script: | BASEPREFIX=`pwd`/depends mkdir -p ${BASEPREFIX}/SDKs - tar -C ${BASEPREFIX}/SDKs -xf ${BUILD_DIR}/MacOSX10.7.sdk.tar.gz + tar -C ${BASEPREFIX}/SDKs -xf ${BUILD_DIR}/MacOSX10.9.sdk.tar.gz # Build dependencies for each host for i in $HOSTS; do diff --git a/contrib/gitian-downloader/jonasschnelli.pgp b/contrib/gitian-downloader/jonasschnelli.pgp Binary files differnew file mode 100644 index 0000000000..96140fe171 --- /dev/null +++ b/contrib/gitian-downloader/jonasschnelli.pgp diff --git a/contrib/macdeploy/DS_Store b/contrib/macdeploy/DS_Store Binary files differindex 7527dc671f..099960712a 100644 --- a/contrib/macdeploy/DS_Store +++ b/contrib/macdeploy/DS_Store diff --git a/contrib/macdeploy/background.png b/contrib/macdeploy/background.png Binary files differindex fce12e3807..f88a2ae74b 100644 --- a/contrib/macdeploy/background.png +++ b/contrib/macdeploy/background.png diff --git a/contrib/macdeploy/background.psd b/contrib/macdeploy/background.psd Binary files differindex 5889676f8e..fdc4f4ca4a 100644 --- a/contrib/macdeploy/background.psd +++ b/contrib/macdeploy/background.psd diff --git a/contrib/macdeploy/background.tiff b/contrib/macdeploy/background.tiff Binary files differnew file mode 100644 index 0000000000..4b44ac672e --- /dev/null +++ b/contrib/macdeploy/background.tiff diff --git a/contrib/macdeploy/background@2x.png b/contrib/macdeploy/background@2x.png Binary files differnew file mode 100644 index 0000000000..4858183f75 --- /dev/null +++ b/contrib/macdeploy/background@2x.png diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist index e73b9b697e..ef277a7f14 100644 --- a/contrib/macdeploy/fancy.plist +++ b/contrib/macdeploy/fancy.plist @@ -10,7 +10,7 @@ <integer>620</integer> </array> <key>background_picture</key> - <string>background.png</string> + <string>background.tiff</string> <key>icon_size</key> <integer>96</integer> <key>applications_symlink</key> diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 541136001f..0eb6b2c84d 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -767,7 +767,7 @@ if config.dmg is not None: for path, dirs, files in os.walk("dist"): for file in files: size += os.path.getsize(os.path.join(path, file)) - size += int(size * 0.1) + size += int(size * 0.15) if verbose >= 3: print "Creating temp image for modification..." @@ -791,7 +791,8 @@ if config.dmg is not None: print "+ Applying fancy settings +" if fancy.has_key("background_picture"): - bg_path = os.path.join(disk_root, os.path.basename(fancy["background_picture"])) + bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"])) + os.mkdir(os.path.dirname(bg_path)) if verbose >= 3: print fancy["background_picture"], "->", bg_path shutil.copy2(fancy["background_picture"], bg_path) @@ -849,8 +850,8 @@ if config.dmg is not None: if bg_path is not None: # Set background file, then call SetFile to make it invisible. # (note: making it invisible first makes set background picture fail) - bgscript = Template("""set background picture of theViewOptions to file "$bgpic" - do shell script "SetFile -a V /Volumes/$disk/$bgpic" """) + bgscript = Template("""set background picture of theViewOptions to file ".background:$bgpic" + do shell script "SetFile -a V /Volumes/$disk/.background/$bgpic" """) params["background_commands"] = bgscript.substitute({"bgpic" : os.path.basename(bg_path), "disk" : params["disk"]}) s = appscript.substitute(params) diff --git a/depends/config.guess b/depends/config.guess index 1f5c50c0d1..dbfb9786cb 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2015 Free Software Foundation, Inc. -timestamp='2014-03-23' +timestamp='2015-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ timestamp='2014-03-23' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to <config-patches@gnu.org>. me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -579,8 +579,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi diff --git a/depends/config.sub b/depends/config.sub index d654d03cdc..6d2e94c8bf 100755 --- a/depends/config.sub +++ b/depends/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2015 Free Software Foundation, Inc. -timestamp='2014-05-01' +timestamp='2015-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ timestamp='2014-05-01' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to <config-patches@gnu.org>. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -68,7 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -260,7 +260,7 @@ case $basic_machine in | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ - | fido | fr30 | frv \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ @@ -302,6 +302,7 @@ case $basic_machine in | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ @@ -312,6 +313,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -326,6 +328,9 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none @@ -436,6 +441,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -773,6 +779,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -828,6 +837,10 @@ case $basic_machine in basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -1373,7 +1386,7 @@ case $os in | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index c1070d8775..2958dc50cc 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,5 +1,5 @@ -OSX_MIN_VERSION=10.6 -OSX_SDK_VERSION=10.7 +OSX_MIN_VERSION=10.7 +OSX_SDK_VERSION=10.9 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk LD64_VERSION=241.9 darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index ad64494c1f..22b1017ffc 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,8 +1,8 @@ package=openssl -$(package)_version=1.0.1j +$(package)_version=1.0.1k $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=1b60ca8789ba6f03e8ef20da2293b8dc131c39d83814e775069f02d26354edf3 +$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" @@ -23,7 +23,7 @@ $(package)_config_opts_i686_mingw32=mingw endef define $(package)_preprocess_cmds - sed -i.old "/define DATE/d" crypto/Makefile && \ + sed -i.old "/define DATE/d" util/mkbuildinf.pl && \ sed -i.old "s|engines apps test|engines|" Makefile.org endef diff --git a/doc/README_osx.txt b/doc/README_osx.txt index d56234f7d9..6c0c21c190 100644 --- a/doc/README_osx.txt +++ b/doc/README_osx.txt @@ -29,14 +29,15 @@ originally done in toolchain4. To complicate things further, all builds must target an Apple SDK. These SDKs are free to download, but not redistributable. -To obtain it, register for a developer account, then download xcode4630916281a.dmg: -https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_4.6.3/xcode4630916281a.dmg +To obtain it, register for a developer account, then download the XCode 6.1.1 dmg: +https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_6.1.1/xcode_6.1.1.dmg + This file is several gigabytes in size, but only a single directory inside is -needed: Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk +needed: Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file. To create a tarball suitable for gitian input, mount the dmg in OSX, then create it with: - $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.7.sdk.tar.gz MacOSX10.7.sdk + $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.9.sdk.tar.gz MacOSX10.9.sdk The gitian descriptors build 2 sets of files: Linux tools, then Apple binaries diff --git a/doc/build-osx.md b/doc/build-osx.md index c41820f2b1..d6e93cb23d 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -21,12 +21,6 @@ Xcode 4.3 or later, you'll need to install its command line tools. This can be done in `Xcode > Preferences > Downloads > Components` and generally must be re-done or updated every time Xcode is updated. -There's also an assumption that you already have `git` installed. If -not, it's the path of least resistance to install [Github for Mac](https://mac.github.com/) -(OS X 10.7+) or -[Git for OS X](https://code.google.com/p/git-osx-installer/). It is also -available via Homebrew. - You will also need to install [Homebrew](http://brew.sh) in order to install library dependencies. @@ -38,7 +32,9 @@ Instructions: Homebrew #### Install dependencies using Homebrew - brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt + brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt5 + +NOTE: Building with Qt4 is still supported, however, could result in a broken UI. As such, building with Qt5 is recommended. #### Installing berkeley-db4 using Homebrew @@ -46,7 +42,7 @@ The homebrew package for berkeley-db4 has been broken for some time. It will in Running this command takes you into brew's interactive mode, which allows you to configure, make, and install by hand: ``` -$ brew install https://raw.github.com/mxcl/homebrew/master/Library/Formula/berkeley-db4.rb -–without-java +$ brew install https://raw.github.com/homebrew/homebrew/master/Library/Formula/berkeley-db4.rb -–without-java ``` The rest of these commands are run inside brew interactive mode: @@ -73,7 +69,7 @@ After exiting, you'll get a warning that the install is keg-only, which means it 2. Build bitcoind: ./autogen.sh - ./configure + ./configure --with-gui=qt5 make 3. It is also a good idea to build and run the unit tests: @@ -115,7 +111,7 @@ All dependencies should be compiled with these flags: -arch x86_64 -isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -Once dependencies are compiled, see release-process.md for how the Bitcoin-Qt.app +Once dependencies are compiled, see [doc/release-process.md](release-process.md) for how the Bitcoin-Qt.app bundle is packaged and signed to create the .dmg disk image that is distributed. Running diff --git a/doc/release-process.md b/doc/release-process.md index eb2eb619bd..363465d827 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -44,11 +44,11 @@ Release Process Register and download the Apple SDK: (see OSX Readme for details) - https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_4.6.3/xcode4630916281a.dmg + https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_6.1.1/xcode_6.1.1.dmg - Using a Mac, create a tarball for the 10.7 SDK and copy it to the inputs directory: + Using a Mac, create a tarball for the 10.9 SDK and copy it to the inputs directory: - tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.7.sdk.tar.gz MacOSX10.7.sdk + tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.9.sdk.tar.gz MacOSX10.9.sdk ###Optional: Seed the Gitian sources cache diff --git a/pkg.m4 b/pkg.m4 deleted file mode 100644 index c5b26b52e6..0000000000 --- a/pkg.m4 +++ /dev/null @@ -1,214 +0,0 @@ -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# serial 1 (pkg-config-0.24) -# -# Copyright © 2004 Scott James Remnant <scott@netsplit.com>. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# PKG_PROG_PKG_CONFIG([MIN-VERSION]) -# ---------------------------------- -AC_DEFUN([PKG_PROG_PKG_CONFIG], -[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) -AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) -AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi -fi[]dnl -])# PKG_PROG_PKG_CONFIG - -# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# -# Check to see whether a particular set of modules exists. Similar -# to PKG_CHECK_MODULES(), but does not set variables or print errors. -# -# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -# only at the first occurence in configure.ac, so if the first place -# it's called might be skipped (such as if it is within an "if", you -# have to call PKG_CHECK_EXISTS manually -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_EXISTS], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_default([$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) - -# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) -# --------------------------------------------- -m4_define([_PKG_CONFIG], -[if test -n "$$1"; then - pkg_cv_[]$1="$$1" - elif test -n "$PKG_CONFIG"; then - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], - [pkg_failed=yes]) - else - pkg_failed=untried -fi[]dnl -])# _PKG_CONFIG - -# _PKG_SHORT_ERRORS_SUPPORTED -# ----------------------------- -AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -])# _PKG_SHORT_ERRORS_SUPPORTED - - -# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -# [ACTION-IF-NOT-FOUND]) -# -# -# Note that if there is a possibility the first call to -# PKG_CHECK_MODULES might not happen, you should be sure to include an -# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac -# -# -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_MODULES], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $1]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - m4_default([$4], [AC_MSG_ERROR( -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT])[]dnl - ]) -elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl - ]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - $3 -fi[]dnl -])# PKG_CHECK_MODULES - - -# PKG_INSTALLDIR(DIRECTORY) -# ------------------------- -# Substitutes the variable pkgconfigdir as the location where a module -# should install pkg-config .pc files. By default the directory is -# $libdir/pkgconfig, but the default can be changed by passing -# DIRECTORY. The user can override through the --with-pkgconfigdir -# parameter. -AC_DEFUN([PKG_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([pkgconfigdir], - [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, - [with_pkgconfigdir=]pkg_default) -AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) dnl PKG_INSTALLDIR - - -# PKG_NOARCH_INSTALLDIR(DIRECTORY) -# ------------------------- -# Substitutes the variable noarch_pkgconfigdir as the location where a -# module should install arch-independent pkg-config .pc files. By -# default the directory is $datadir/pkgconfig, but the default can be -# changed by passing DIRECTORY. The user can override through the -# --with-noarch-pkgconfigdir parameter. -AC_DEFUN([PKG_NOARCH_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([noarch-pkgconfigdir], - [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, - [with_noarch_pkgconfigdir=]pkg_default) -AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) dnl PKG_NOARCH_INSTALLDIR - - -# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, -# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# ------------------------------------------- -# Retrieves the value of the pkg-config variable for the given module. -AC_DEFUN([PKG_CHECK_VAR], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl - -_PKG_CONFIG([$1], [variable="][$3]["], [$2]) -AS_VAR_COPY([$1], [pkg_cv_][$1]) - -AS_VAR_IF([$1], [""], [$5], [$4])dnl -])# PKG_CHECK_VAR diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 15cac14595..efeee45530 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -26,6 +26,7 @@ testScripts=( 'mempool_spendcoinbase.py' 'mempool_coinbase_spends.py' 'httpbasics.py' + 'zapwallettxes.py' # 'forknotify.py' ); if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then @@ -33,7 +34,7 @@ if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then do if [ -z "$1" ] || [ "$1" == "${testScripts[$i]}" ] || [ "$1.py" == "${testScripts[$i]}" ] then - echo -e "running testscript \033[1m${testScripts[$i]}...\033[0m" + echo -e "Running testscript \033[1m${testScripts[$i]}...\033[0m" ${BUILDDIR}/qa/rpc-tests/${testScripts[$i]} --srcdir "${BUILDDIR}/src" fi done diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py index 85e85e7f0f..24533741e5 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/qa/rpc-tests/httpbasics.py @@ -21,6 +21,9 @@ except ImportError: import urlparse class HTTPBasicsTest (BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, extra_args=[['-rpckeepalive=1'], ['-rpckeepalive=0'], [], []]) + def run_test(self): ################################################# @@ -32,13 +35,13 @@ class HTTPBasicsTest (BitcoinTestFramework): conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() - conn.request('GET', '/', '{"method": "getbestblockhash"}', headers) + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! #send 2nd request without closing connection - conn.request('GET', '/', '{"method": "getchaintips"}', headers) + conn.request('POST', '/', '{"method": "getchaintips"}', headers) out2 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! @@ -49,13 +52,13 @@ class HTTPBasicsTest (BitcoinTestFramework): conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() - conn.request('GET', '/', '{"method": "getbestblockhash"}', headers) + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! #send 2nd request without closing connection - conn.request('GET', '/', '{"method": "getchaintips"}', headers) + conn.request('POST', '/', '{"method": "getchaintips"}', headers) out2 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! @@ -66,11 +69,34 @@ class HTTPBasicsTest (BitcoinTestFramework): conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() - conn.request('GET', '/', '{"method": "getbestblockhash"}', headers) + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, False) #now the connection must be closed after the response + #node1 (2nd node) is running with disabled keep-alive option + urlNode1 = urlparse.urlparse(self.nodes[1].url) + authpair = urlNode1.username + ':' + urlNode1.password + headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + + conn = httplib.HTTPConnection(urlNode1.hostname, urlNode1.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, False) #connection must be closed because keep-alive was set to false + + #node2 (third node) is running with standard keep-alive parameters which means keep-alive is off + urlNode2 = urlparse.urlparse(self.nodes[2].url) + authpair = urlNode2.username + ':' + urlNode2.password + headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + + conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, True) #connection must be closed because bitcoind should use keep-alive by default if __name__ == '__main__': HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py index 6c4ec073c2..4c8a11b821 100755 --- a/qa/rpc-tests/test_framework.py +++ b/qa/rpc-tests/test_framework.py @@ -33,8 +33,11 @@ class BitcoinTestFramework(object): print("Initializing test directory "+self.options.tmpdir) initialize_chain(self.options.tmpdir) + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir) + def setup_network(self, split = False): - self.nodes = start_nodes(4, self.options.tmpdir) + self.nodes = self.setup_nodes() # Connect the nodes as a "chain". This allows us # to split the network between nodes 1 and 2 to get diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py new file mode 100755 index 0000000000..a773575906 --- /dev/null +++ b/qa/rpc-tests/zapwallettxes.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python2 +# Copyright (c) 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. + +from test_framework import BitcoinTestFramework +from util import * + + +class ZapWalletTXesTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + def run_test (self): + print "Mining blocks..." + self.nodes[0].setgenerate(True, 1) + self.sync_all() + self.nodes[1].setgenerate(True, 101) + self.sync_all() + + assert_equal(self.nodes[0].getbalance(), 50) + + txid0 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + txid1 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + self.sync_all() + self.nodes[0].setgenerate(True, 1) + self.sync_all() + + txid2 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + txid3 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + + tx0 = self.nodes[0].gettransaction(txid0) + assert_equal(tx0['txid'], txid0) #tx0 must be available (confirmed) + + tx1 = self.nodes[0].gettransaction(txid1) + assert_equal(tx1['txid'], txid1) #tx1 must be available (confirmed) + + tx2 = self.nodes[0].gettransaction(txid2) + assert_equal(tx2['txid'], txid2) #tx2 must be available (unconfirmed) + + tx3 = self.nodes[0].gettransaction(txid3) + assert_equal(tx3['txid'], txid3) #tx3 must be available (unconfirmed) + + #restart bitcoind + self.nodes[0].stop() + bitcoind_processes[0].wait() + self.nodes[0] = start_node(0,self.options.tmpdir) + + tx3 = self.nodes[0].gettransaction(txid3) + assert_equal(tx3['txid'], txid3) #tx must be available (unconfirmed) + + self.nodes[0].stop() + bitcoind_processes[0].wait() + + #restart bitcoind with zapwallettxes + self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"]) + + aException = False + try: + tx3 = self.nodes[0].gettransaction(txid3) + except JSONRPCException,e: + print e + aException = True + + assert_equal(aException, True) #there must be a expection because the unconfirmed wallettx0 must be gone by now + + tx0 = self.nodes[0].gettransaction(txid0) + assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed + + +if __name__ == '__main__': + ZapWalletTXesTest ().main () diff --git a/qa/rpc-tests/zapwallettxes.sh b/qa/rpc-tests/zapwallettxes.sh deleted file mode 100755 index 4312d84e94..0000000000 --- a/qa/rpc-tests/zapwallettxes.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 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. - -# Test -zapwallettxes=<mode> - -if [ $# -lt 1 ]; then - echo "Usage: $0 path_to_binaries" - echo "e.g. $0 ../../src" - echo "Env vars BITCOIND and BITCOINCLI may be used to specify the exact binaries used" - exit 1 -fi - -set -f - -BITCOIND=${BITCOIND:-${1}/bitcoind} -CLI=${BITCOINCLI:-${1}/bitcoin-cli} - -DIR="${BASH_SOURCE%/*}" -SENDANDWAIT="${DIR}/send.sh" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/util.sh" - -D=$(mktemp -d test.XXXXX) - -D1=${D}/node1 -CreateDataDir "$D1" port=11000 rpcport=11001 -B1ARGS="-datadir=$D1" -$BITCOIND $B1ARGS & -B1PID=$! - -D2=${D}/node2 -CreateDataDir "$D2" port=11010 rpcport=11011 -B2ARGS="-datadir=$D2" -$BITCOIND $B2ARGS & -B2PID=$! - -function CleanUp { -$CLI $B2ARGS stop > /dev/null 2>&1 -wait $B2PID -$CLI $B1ARGS stop > /dev/null 2>&1 -wait $B1PID - -rm -rf $D -} - -# 110 blocks, 10 mature == 500 XBT -$CLI $B1ARGS setgenerate true 110 -$CLI $B2ARGS setgenerate true 110 - -CheckBalance "$B1ARGS" 500 -CheckBalance "$B2ARGS" 500 - -# Send 10 XBT -TXID1_DEFAULT=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10) -TXID2_DEFAULT=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10) - -CheckBalance $B1ARGS 490 -CheckBalance $B2ARGS 490 - -# Move 10 XBT to testaccount -TMP=$($CLI $B1ARGS move "" "testaccount" 10) -TMP=$($CLI $B2ARGS move "" "testaccount" 10) - -CheckBalance $B1ARGS 10 "testaccount" -CheckBalance $B2ARGS 10 "testaccount" - -# Send 1 XBT from testaccount -TXID1_TESTACCOUNT=$($CLI $B1ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) -TXID2_TESTACCOUNT=$($CLI $B2ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) - -CheckBalance $B1ARGS 9 "testaccount" -CheckBalance $B2ARGS 9 "testaccount" - -CheckBalance $B1ARGS 489 -CheckBalance $B2ARGS 489 - -# Confirm transactions -$CLI $B1ARGS setgenerate true 1 -$CLI $B2ARGS setgenerate true 1 - -# Create unconfirmed transaction -TXID1_UNCONFIRMED=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) -TXID2_UNCONFIRMED=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) - -# check balance (we created another 50 and spent 1 in the meantime) -CheckBalance $B1ARGS 538 -CheckBalance $B2ARGS 538 - -# Safety check, if unconfirmed transactions are there -$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "gettransaction1_1: $TXID1_UNCONFIRMED failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "gettransaction2_1: $TXID2_UNCONFIRMED failed" - CleanUp - exit 1 -fi - -# stop nodes -$CLI $B2ARGS stop > /dev/null 2>&1 -wait $B2PID -$CLI $B1ARGS stop > /dev/null 2>&1 -wait $B1PID - -# restart nodes with -zapwallettxes -$BITCOIND -zapwallettxes=1 $B1ARGS & -B1PID=$! -$BITCOIND -zapwallettxes=2 $B2ARGS & -B2PID=$! - -# check if confirmed transactions are there -$CLI $B1ARGS gettransaction $TXID1_DEFAULT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 1: $TXID1_DEFAULT failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_DEFAULT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 2: $TXID2_DEFAULT failed" - CleanUp - exit 1 -fi -$CLI $B1ARGS gettransaction $TXID1_TESTACCOUNT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 3: $TXID1_TESTACCOUNT failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_TESTACCOUNT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 4: $TXID2_TESTACCOUNT failed" - CleanUp - exit 1 -fi - -# check if unconfirmed transaction is gone -$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -eq 0 ]] ; then - echoerr "check unconfirmed transaction 1: $TXID1_UNCONFIRMED failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -eq 0 ]] ; then - echoerr "check unconfirmed transaction 2: $TXID2_UNCONFIRMED failed" - CleanUp - exit 1 -fi - -# check zapwallet mode 1, testaccount balance must be 9 (keeping transaction metadata) -CheckBalance $B1ARGS 9 "testaccount" - -# check zapwallet mode 2, testaccount balance must be 10 (dropping transaction metadata) -CheckBalance $B2ARGS 10 "testaccount" - -echo "Tests successful, cleaning up" -CleanUp -exit 0 diff --git a/src/Makefile.am b/src/Makefile.am index 1f9a1621a7..e2ba191e3a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -209,14 +209,12 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha256.cpp \ crypto/sha512.cpp \ crypto/hmac_sha256.cpp \ - crypto/rfc6979_hmac_sha256.cpp \ crypto/hmac_sha512.cpp \ crypto/ripemd160.cpp \ crypto/common.h \ crypto/sha256.h \ crypto/sha512.h \ crypto/hmac_sha256.h \ - crypto/rfc6979_hmac_sha256.h \ crypto/hmac_sha512.h \ crypto/sha1.h \ crypto/ripemd160.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index cdd8f8d08d..31fe3a9f69 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -314,8 +314,7 @@ BITCOIN_QT_CPP += \ qt/walletview.cpp endif -RES_IMAGES = \ - qt/res/images/about.png +RES_IMAGES = RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 2f10702d86..710956a72b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -58,6 +58,7 @@ BITCOIN_TESTS =\ test/netbase_tests.cpp \ test/pmt_tests.cpp \ test/rpc_tests.cpp \ + test/sanity_tests.cpp \ test/script_P2SH_tests.cpp \ test/script_tests.cpp \ test/scriptnum_tests.cpp \ diff --git a/src/crypto/rfc6979_hmac_sha256.cpp b/src/crypto/rfc6979_hmac_sha256.cpp deleted file mode 100644 index a8c971c3ba..0000000000 --- a/src/crypto/rfc6979_hmac_sha256.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 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 "crypto/rfc6979_hmac_sha256.h" - -#include <string.h> - -#include <algorithm> - -static const unsigned char zero[1] = {0x00}; -static const unsigned char one[1] = {0x01}; - -RFC6979_HMAC_SHA256::RFC6979_HMAC_SHA256(const unsigned char* key, size_t keylen, const unsigned char* msg, size_t msglen) : retry(false) -{ - memset(V, 0x01, sizeof(V)); - memset(K, 0x00, sizeof(K)); - - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Write(zero, sizeof(zero)).Write(key, keylen).Write(msg, msglen).Finalize(K); - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V); - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Write(one, sizeof(one)).Write(key, keylen).Write(msg, msglen).Finalize(K); - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V); -} - -RFC6979_HMAC_SHA256::~RFC6979_HMAC_SHA256() -{ - memset(V, 0x01, sizeof(V)); - memset(K, 0x00, sizeof(K)); -} - -void RFC6979_HMAC_SHA256::Generate(unsigned char* output, size_t outputlen) -{ - if (retry) { - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Write(zero, sizeof(zero)).Finalize(K); - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V); - } - - while (outputlen > 0) { - CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V); - size_t len = std::min(outputlen, sizeof(V)); - memcpy(output, V, len); - output += len; - outputlen -= len; - } - - retry = true; -} diff --git a/src/crypto/rfc6979_hmac_sha256.h b/src/crypto/rfc6979_hmac_sha256.h deleted file mode 100644 index f3a54a5d11..0000000000 --- a/src/crypto/rfc6979_hmac_sha256.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 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_RFC6979_HMAC_SHA256_H -#define BITCOIN_RFC6979_HMAC_SHA256_H - -#include "crypto/hmac_sha256.h" - -#include <stdint.h> -#include <stdlib.h> - -/** The RFC 6979 PRNG using HMAC-SHA256. */ -class RFC6979_HMAC_SHA256 -{ -private: - unsigned char V[CHMAC_SHA256::OUTPUT_SIZE]; - unsigned char K[CHMAC_SHA256::OUTPUT_SIZE]; - bool retry; - -public: - /** - * Construct a new RFC6979 PRNG, using the given key and message. - * The message is assumed to be already hashed. - */ - RFC6979_HMAC_SHA256(const unsigned char* key, size_t keylen, const unsigned char* msg, size_t msglen); - - /** - * Generate a byte array. - */ - void Generate(unsigned char* output, size_t outputlen); - - ~RFC6979_HMAC_SHA256(); -}; - -#endif // BITCOIN_RFC6979_HMAC_SHA256_H diff --git a/src/db.cpp b/src/db.cpp index fcc177f1cc..7b51707f60 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -217,10 +217,11 @@ void CDBEnv::CheckpointLSN(const std::string& strFile) } -CDB::CDB(const std::string& strFilename, const char* pszMode) : pdb(NULL), activeTxn(NULL) +CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL) { int ret; fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); + fFlushOnClose = fFlushOnCloseIn; if (strFilename.empty()) return; @@ -297,7 +298,8 @@ void CDB::Close() activeTxn = NULL; pdb = NULL; - Flush(); + if (fFlushOnClose) + Flush(); { LOCK(bitdb.cs_db); @@ -97,8 +97,9 @@ protected: std::string strFile; DbTxn* activeTxn; bool fReadOnly; + bool fFlushOnClose; - explicit CDB(const std::string& strFilename, const char* pszMode = "r+"); + explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true); ~CDB() { Close(); } public: diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp index c29390eb98..5e3aec25ba 100644 --- a/src/ecwrapper.cpp +++ b/src/ecwrapper.cpp @@ -117,10 +117,34 @@ bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) { } bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) { - // -1 = error, 0 = bad sig, 1 = good - if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + if (vchSig.empty()) return false; - return true; + + // 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) diff --git a/src/init.cpp b/src/init.cpp index 03d67f0aa3..aaa5f06c75 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -111,7 +111,28 @@ bool ShutdownRequested() return fRequestShutdown; } +class CCoinsViewErrorCatcher : public CCoinsViewBacked +{ +public: + CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} + bool GetCoins(const uint256 &txid, CCoins &coins) const { + try { + return CCoinsViewBacked::GetCoins(txid, coins); + } catch(const std::runtime_error& e) { + uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR); + LogPrintf("Error reading from database: %s\n", e.what()); + // Starting the shutdown sequence and returning false to the caller would be + // interpreted as 'entry not found' (as opposed to unable to read data), and + // could lead to invalid interpration. Just exit immediately, as we can't + // continue anyway, and all writes should be atomic. + abort(); + } + } + // Writes do not need similar protection, as failure to write is handled by the caller. +}; + static CCoinsViewDB *pcoinsdbview = NULL; +static CCoinsViewErrorCatcher *pcoinscatcher = NULL; void Shutdown() { @@ -154,6 +175,8 @@ void Shutdown() } delete pcoinsTip; pcoinsTip = NULL; + delete pcoinscatcher; + pcoinscatcher = NULL; delete pcoinsdbview; pcoinsdbview = NULL; delete pblocktree; @@ -357,6 +380,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -rpcport=<port> " + strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), 8332, 18332) + "\n"; strUsage += " -rpcallowip=<ip> " + _("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") + "\n"; strUsage += " -rpcthreads=<n> " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n"; + strUsage += " -rpckeepalive " + strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 1) + "\n"; strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n"; strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n"; @@ -990,11 +1014,13 @@ bool AppInit2(boost::thread_group& threadGroup) UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; + delete pcoinscatcher; delete pblocktree; pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); - pcoinsTip = new CCoinsViewCache(pcoinsdbview); + pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); + pcoinsTip = new CCoinsViewCache(pcoinscatcher); if (fReindex) pblocktree->WriteReindexing(true); @@ -1185,6 +1211,8 @@ bool AppInit2(boost::thread_group& threadGroup) // Restore wallet transaction metadata after -zapwallettxes=1 if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") { + CWalletDB walletdb(strWalletFile); + BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) { uint256 hash = wtxOld.GetHash(); @@ -1200,7 +1228,7 @@ bool AppInit2(boost::thread_group& threadGroup) copyTo->fFromMe = copyFrom->fFromMe; copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(); + copyTo->WriteToDisk(&walletdb); } } } @@ -1226,6 +1254,11 @@ bool AppInit2(boost::thread_group& threadGroup) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); + if (chainActive.Tip() == NULL) { + LogPrintf("Waiting for genesis block to be imported...\n"); + while (!fRequestShutdown && chainActive.Tip() == NULL) + MilliSleep(10); + } // ********************************************************* Step 10: start node diff --git a/src/key.cpp b/src/key.cpp index 2235c271d1..d8319db1a3 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -6,7 +6,6 @@ #include "arith_uint256.h" #include "crypto/hmac_sha512.h" -#include "crypto/rfc6979_hmac_sha256.h" #include "eccryptoverify.h" #include "pubkey.h" #include "random.h" @@ -74,23 +73,28 @@ CPubKey CKey::GetPubKey() const { return result; } +extern "C" +{ +static int secp256k1_nonce_function_test_case(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int attempt, const void *data) +{ + const uint32_t *test_case = static_cast<const uint32_t*>(data); + uint256 nonce; + secp256k1_nonce_function_rfc6979(nonce.begin(), msg32, key32, attempt, NULL); + nonce = ArithToUint256(UintToArith256(nonce) + *test_case); + memcpy(nonce32, nonce.begin(), 32); + return 1; +} +} + bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const { if (!fValid) return false; vchSig.resize(72); - RFC6979_HMAC_SHA256 prng(begin(), 32, (unsigned char*)&hash, 32); - do { - uint256 nonce; - prng.Generate((unsigned char*)&nonce, 32); - nonce = ArithToUint256(UintToArith256(nonce) + test_case); - int nSigLen = 72; - int ret = secp256k1_ecdsa_sign((const unsigned char*)&hash, (unsigned char*)&vchSig[0], &nSigLen, begin(), (unsigned char*)&nonce); - nonce = uint256(); - if (ret) { - vchSig.resize(nSigLen); - return true; - } - } while(true); + int nSigLen = 72; + int ret = secp256k1_ecdsa_sign(hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), test_case == 0 ? secp256k1_nonce_function_rfc6979 : secp256k1_nonce_function_test_case, test_case == 0 ? NULL : &test_case); + assert(ret); + vchSig.resize(nSigLen); + return true; } bool CKey::VerifyPubKey(const CPubKey& pubkey) const { @@ -101,7 +105,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const { std::string str = "Bitcoin key verification\n"; GetRandBytes(rnd, sizeof(rnd)); uint256 hash; - CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize((unsigned char*)&hash); + CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin()); std::vector<unsigned char> vchSig; Sign(hash, vchSig); return pubkey.Verify(hash, vchSig); @@ -112,15 +116,8 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) return false; vchSig.resize(65); int rec = -1; - RFC6979_HMAC_SHA256 prng(begin(), 32, (unsigned char*)&hash, 32); - do { - uint256 nonce; - prng.Generate((unsigned char*)&nonce, 32); - int ret = secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, &vchSig[1], begin(), (unsigned char*)&nonce, &rec); - nonce = uint256(); - if (ret) - break; - } while(true); + int ret = secp256k1_ecdsa_sign_compact(hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); + assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); return true; diff --git a/src/main.cpp b/src/main.cpp index e1a0973352..7cc69c318b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -139,9 +139,14 @@ namespace { uint256 hash; CBlockIndex *pindex; //! Optional. int64_t nTime; //! Time of "getdata" request in microseconds. + int nValidatedQueuedBefore; //! Number of blocks queued with validated headers (globally) at the time this one is requested. + bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. }; map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; + /** Number of blocks in flight with validated headers. */ + int nQueuedValidatedHeaders = 0; + /** Number of preferable block download peers. */ int nPreferredDownload = 0; @@ -323,6 +328,7 @@ void MarkBlockAsReceived(const uint256& hash) { map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); if (itInFlight != mapBlocksInFlight.end()) { CNodeState *state = State(itInFlight->second.first); + nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; state->vBlocksInFlight.erase(itInFlight->second.second); state->nBlocksInFlight--; state->nStallingSince = 0; @@ -338,7 +344,8 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex // Make sure it's not listed somewhere already. MarkBlockAsReceived(hash); - QueuedBlock newentry = {hash, pindex, GetTimeMicros()}; + QueuedBlock newentry = {hash, pindex, GetTimeMicros(), nQueuedValidatedHeaders, pindex != NULL}; + nQueuedValidatedHeaders += newentry.fValidatedHeaders; list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); state->nBlocksInFlight++; mapBlocksInFlight[hash] = std::make_pair(nodeid, it); @@ -1002,15 +1009,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction - // itself can contain sigops MAX_TX_SIGOPS is less than + // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. unsigned int nSigOps = GetLegacySigOpCount(tx); nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_TX_SIGOPS) + if (nSigOps > MAX_STANDARD_TX_SIGOPS) return state.DoS(0, error("AcceptToMemoryPool : too many sigops %s, %d > %d", - hash.ToString(), nSigOps, MAX_TX_SIGOPS), + hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS), REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); CAmount nValueOut = tx.GetValueOut(); @@ -4527,6 +4534,15 @@ bool SendMessages(CNode* pto, bool fSendTrickle) LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); pto->fDisconnect = true; } + // In case there is a block that has been in flight from this peer for (1 + 0.5 * N) times the block interval + // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to + // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link + // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes + // to unreasonably increase our timeout. + if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (2 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) { + LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id); + pto->fDisconnect = true; + } // // Message: getdata (blocks) diff --git a/src/main.h b/src/main.h index 1e00114768..a7360d2f70 100644 --- a/src/main.h +++ b/src/main.h @@ -45,7 +45,6 @@ class CScriptCheck; class CValidationInterface; class CValidationState; -struct CBlockTemplate; struct CNodeStateStats; /** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/ @@ -60,7 +59,7 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Maximum number of signature check operations in an IsStandard() P2SH script */ 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_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; +static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** The maximum size of a blk?????.dat file (since 0.8) */ @@ -513,17 +512,6 @@ extern CCoinsViewCache *pcoinsTip; /** Global variable that points to the active block tree (protected by cs_main) */ extern CBlockTreeDB *pblocktree; -struct CBlockTemplate -{ - CBlock block; - std::vector<CAmount> vTxFees; - std::vector<int64_t> vTxSigOps; -}; - - - - - class CValidationInterface { protected: diff --git a/src/miner.cpp b/src/miner.cpp index 87cb158333..5cc4a92791 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -6,7 +6,6 @@ #include "miner.h" #include "amount.h" -#include "primitives/block.h" #include "primitives/transaction.h" #include "hash.h" #include "main.h" @@ -363,8 +362,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& // // Internal miner // -double dHashesPerSec = 0.0; -int64_t nHPSTimerStart = 0; // // ScanHash scans nonces looking for a hash with at least some zero bits. @@ -394,10 +391,8 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas return true; // If nothing found after trying for a while, return -1 - if ((nNonce & 0xffff) == 0) - return false; if ((nNonce & 0xfff) == 0) - boost::this_thread::interruption_point(); + return false; } } @@ -484,14 +479,9 @@ void static BitcoinMiner(CWallet *pwallet) arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); uint256 hash; uint32_t nNonce = 0; - uint32_t nOldNonce = 0; while (true) { - bool fFound = ScanHash(pblock, nNonce, &hash); - uint32_t nHashesDone = nNonce - nOldNonce; - nOldNonce = nNonce; - // Check if something found - if (fFound) + if (ScanHash(pblock, nNonce, &hash)) { if (UintToArith256(hash) <= hashTarget) { @@ -513,35 +503,6 @@ void static BitcoinMiner(CWallet *pwallet) } } - // Meter hashes/sec - static int64_t nHashCounter; - if (nHPSTimerStart == 0) - { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } - else - nHashCounter += nHashesDone; - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - static CCriticalSection cs; - { - LOCK(cs); - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - static int64_t nLogTime; - if (GetTime() - nLogTime > 30 * 60) - { - nLogTime = GetTime(); - LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); - } - } - } - } - // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); // Regtest mode doesn't require peers diff --git a/src/miner.h b/src/miner.h index 3c08b030f6..5d5c9c86c7 100644 --- a/src/miner.h +++ b/src/miner.h @@ -6,16 +6,21 @@ #ifndef BITCOIN_MINER_H #define BITCOIN_MINER_H +#include "primitives/block.h" + #include <stdint.h> -class CBlock; -class CBlockHeader; class CBlockIndex; class CReserveKey; class CScript; class CWallet; -struct CBlockTemplate; +struct CBlockTemplate +{ + CBlock block; + std::vector<CAmount> vTxFees; + std::vector<int64_t> vTxSigOps; +}; /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); @@ -26,7 +31,4 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); -extern double dHashesPerSec; -extern int64_t nHPSTimerStart; - #endif // BITCOIN_MINER_H diff --git a/src/net.cpp b/src/net.cpp index 8cf2d0ffec..bba80535e5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -157,56 +157,6 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer) return ret; } -bool RecvLine(SOCKET hSocket, string& strLine) -{ - strLine = ""; - while (true) - { - char c; - int nBytes = recv(hSocket, &c, 1, 0); - if (nBytes > 0) - { - if (c == '\n') - continue; - if (c == '\r') - return true; - strLine += c; - if (strLine.size() >= 9000) - return true; - } - else if (nBytes <= 0) - { - boost::this_thread::interruption_point(); - if (nBytes < 0) - { - int nErr = WSAGetLastError(); - if (nErr == WSAEMSGSIZE) - continue; - if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS) - { - MilliSleep(10); - continue; - } - } - if (!strLine.empty()) - return true; - if (nBytes == 0) - { - // socket closed - LogPrint("net", "socket closed\n"); - return false; - } - else - { - // socket error - int nErr = WSAGetLastError(); - LogPrint("net", "recv failed: %s\n", NetworkErrorString(nErr)); - return false; - } - } - } -} - int GetnScore(const CService& addr) { LOCK(cs_mapLocalHost); @@ -61,7 +61,6 @@ unsigned int ReceiveFloodSize(); unsigned int SendBufferSize(); void AddOneShot(std::string strDest); -bool RecvLine(SOCKET hSocket, std::string& strLine); void AddressCurrentlyConnected(const CService& addr); CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const std::string& addrName); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 1adf4e00cb..73c684e489 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -89,10 +89,24 @@ static std::string Translate(const char* psz) return QCoreApplication::translate("bitcoin-core", psz).toStdString(); } +static QString GetLangTerritory() +{ + QSettings settings; + // Get desired locale (e.g. "de_DE") + // 1) System default language + QString lang_territory = QLocale::system().name(); + // 2) Language from QSettings + QString lang_territory_qsettings = settings.value("language", "").toString(); + if(!lang_territory_qsettings.isEmpty()) + lang_territory = lang_territory_qsettings; + // 3) -lang command line argument + lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString())); + return lang_territory; +} + /** Set up translations */ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator) { - QSettings settings; // Remove old translators QApplication::removeTranslator(&qtTranslatorBase); @@ -102,13 +116,7 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans // Get desired locale (e.g. "de_DE") // 1) System default language - QString lang_territory = QLocale::system().name(); - // 2) Language from QSettings - QString lang_territory_qsettings = settings.value("language", "").toString(); - if(!lang_territory_qsettings.isEmpty()) - lang_territory = lang_territory_qsettings; - // 3) -lang command line argument - lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString())); + QString lang_territory = GetLangTerritory(); // Convert to "de" only by truncating "_DE" QString lang = lang_territory; @@ -498,8 +506,6 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(bitcoin); Q_INIT_RESOURCE(bitcoin_locale); - GUIUtil::SubstituteFonts(); - BitcoinApplication app(argc, argv); #if QT_VERSION > 0x050100 // Generate high-dpi pixmaps @@ -521,6 +527,7 @@ int main(int argc, char *argv[]) QApplication::setOrganizationName(QAPP_ORG_NAME); QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN); QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT); + GUIUtil::SubstituteFonts(GetLangTerritory()); /// 4. Initialization of translations, so that intro dialog is in user's language // Now that QSettings are accessible, initialize translations diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index bcaf95d91c..63af146fd0 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -46,9 +46,6 @@ <file alias="about_qt">res/icons/about_qt.png</file> <file alias="verify">res/icons/verify.png</file> </qresource> - <qresource prefix="/images"> - <file alias="about">res/images/about.png</file> - </qresource> <qresource prefix="/movies"> <file alias="spinner-000">res/movies/spinner-000.png</file> <file alias="spinner-001">res/movies/spinner-001.png</file> diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index fdb9bcd6d6..4c00aca985 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -20,6 +20,7 @@ class AmountSpinBox: public QAbstractSpinBox { Q_OBJECT + public: explicit AmountSpinBox(QWidget *parent): QAbstractSpinBox(parent), @@ -72,23 +73,6 @@ public: setValue(val); } - StepEnabled stepEnabled() const - { - StepEnabled rv = 0; - if(text().isEmpty()) // Allow step-up with empty field - return StepUpEnabled; - bool valid = false; - CAmount val = value(&valid); - if(valid) - { - if(val > 0) - rv |= StepDownEnabled; - if(val < BitcoinUnits::maxMoney()) - rv |= StepUpEnabled; - } - return rv; - } - void setDisplayUnit(int unit) { bool valid = false; @@ -139,6 +123,7 @@ public: } return cachedMinimumSizeHint; } + private: int currentUnit; CAmount singleStep; @@ -179,6 +164,26 @@ protected: return QAbstractSpinBox::event(event); } + StepEnabled stepEnabled() const + { + if (isReadOnly()) // Disable steps when AmountSpinBox is read-only + return StepNone; + if (text().isEmpty()) // Allow step-up with empty field + return StepUpEnabled; + + StepEnabled rv = 0; + bool valid = false; + CAmount val = value(&valid); + if(valid) + { + if(val > 0) + rv |= StepDownEnabled; + if(val < BitcoinUnits::maxMoney()) + rv |= StepUpEnabled; + } + return rv; + } + signals: void valueChanged(); }; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 2810eae052..09f784387e 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -76,12 +76,14 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : historyAction(0), quitAction(0), sendCoinsAction(0), + sendCoinsMenuAction(0), usedSendingAddressesAction(0), usedReceivingAddressesAction(0), signMessageAction(0), verifyMessageAction(0), aboutAction(0), receiveCoinsAction(0), + receiveCoinsMenuAction(0), optionsAction(0), toggleHideAction(0), encryptWalletAction(0), @@ -162,6 +164,9 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : // Create status bar statusBar(); + + // Disable size grip because it looks ugly and nobody needs it + statusBar()->setSizeGripEnabled(false); // Status bar notification icons QFrame *frameBlocks = new QFrame(); @@ -256,6 +261,10 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); tabGroup->addAction(sendCoinsAction); + sendCoinsMenuAction = new QAction(TextColorIcon(":/icons/send"), sendCoinsAction->text(), this); + sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip()); + sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip()); + receiveCoinsAction = new QAction(SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this); receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)")); receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); @@ -263,6 +272,10 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); tabGroup->addAction(receiveCoinsAction); + receiveCoinsMenuAction = new QAction(TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this); + receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip()); + receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip()); + historyAction = new QAction(SingleColorIcon(":/icons/history"), tr("&Transactions"), this); historyAction->setStatusTip(tr("Browse transaction history")); historyAction->setToolTip(historyAction->statusTip()); @@ -277,8 +290,12 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); + connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); + connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); #endif // ENABLE_WALLET @@ -475,7 +492,9 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) { overviewAction->setEnabled(enabled); sendCoinsAction->setEnabled(enabled); + sendCoinsMenuAction->setEnabled(enabled); receiveCoinsAction->setEnabled(enabled); + receiveCoinsMenuAction->setEnabled(enabled); historyAction->setEnabled(enabled); encryptWalletAction->setEnabled(enabled); backupWalletAction->setEnabled(enabled); @@ -522,8 +541,8 @@ void BitcoinGUI::createTrayIconMenu() // Configuration of the tray icon (or dock icon) icon menu trayIconMenu->addAction(toggleHideAction); trayIconMenu->addSeparator(); - trayIconMenu->addAction(sendCoinsAction); - trayIconMenu->addAction(receiveCoinsAction); + trayIconMenu->addAction(sendCoinsMenuAction); + trayIconMenu->addAction(receiveCoinsMenuAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(signMessageAction); trayIconMenu->addAction(verifyMessageAction); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 7509a00734..3216a7398e 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -90,12 +90,14 @@ private: QAction *historyAction; QAction *quitAction; QAction *sendCoinsAction; + QAction *sendCoinsMenuAction; QAction *usedSendingAddressesAction; QAction *usedReceivingAddressesAction; QAction *signMessageAction; QAction *verifyMessageAction; QAction *aboutAction; QAction *receiveCoinsAction; + QAction *receiveCoinsMenuAction; QAction *optionsAction; QAction *toggleHideAction; QAction *encryptWalletAction; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 8422f316f9..3f4f082b8c 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -117,6 +117,10 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) : // (un)select all connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); + // change coin control first column label due Qt4 bug. + // see https://github.com/bitcoin/bitcoin/issues/5716 + ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString()); + ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84); ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100); ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170); @@ -304,19 +308,19 @@ void CoinControlDialog::clipboardAmount() // copy label "Fee" to clipboard void CoinControlDialog::clipboardFee() { - GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // copy label "After fee" to clipboard void CoinControlDialog::clipboardAfterFee() { - GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // copy label "Bytes" to clipboard void CoinControlDialog::clipboardBytes() { - GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } // copy label "Priority" to clipboard @@ -334,7 +338,7 @@ void CoinControlDialog::clipboardLowOutput() // copy label "Change" to clipboard void CoinControlDialog::clipboardChange() { - GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // treeview: sort @@ -600,16 +604,16 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee - l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes + l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes l6->setText(sPriorityLabel); // Priority l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change if (nPayFee > 0 && !(payTxFee.GetFeePerK() > 0 && fPayAtLeastCustomFee && nBytes < 1000)) { - l3->setText("~" + l3->text()); - l4->setText("~" + l4->text()); + l3->setText(ASYMP_UTF8 + l3->text()); + l4->setText(ASYMP_UTF8 + l4->text()); if (nChange > 0) - l8->setText("~" + l8->text()); + l8->setText(ASYMP_UTF8 + l8->text()); } // turn labels "red" diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 0974443066..5a91876f1f 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -25,6 +25,8 @@ namespace Ui { class CoinControlDialog; } +#define ASYMP_UTF8 "\xE2\x89\x88" + class CoinControlDialog : public QDialog { Q_OBJECT diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp index 6cbcf7128d..5dcbf0c3f1 100644 --- a/src/qt/coincontroltreewidget.cpp +++ b/src/qt/coincontroltreewidget.cpp @@ -17,7 +17,8 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) { event->ignore(); int COLUMN_CHECKBOX = 0; - this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked)); + if(this->currentItem()) + this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked)); } else if (event->key() == Qt::Key_Escape) // press esc -> close dialog { @@ -29,4 +30,4 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) { this->QTreeWidget::keyPressEvent(event); } -}
\ No newline at end of file +} diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index 9ace9afd79..37008f047e 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -6,33 +6,15 @@ <rect> <x>0</x> <y>0</y> - <width>585</width> - <height>225</height> + <width>780</width> + <height>400</height> </rect> </property> - <property name="font"> - <font> - <pointsize>10</pointsize> - </font> - </property> <property name="windowTitle"> <string notr="true">Bitcoin Core - Command-line options</string> </property> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> - <widget class="QLabel" name="graphic"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Ignored"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="pixmap"> - <pixmap resource="../bitcoin.qrc">:/images/about</pixmap> - </property> - </widget> - </item> - <item> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QTextEdit" name="helpMessage"> @@ -50,14 +32,6 @@ <bool>true</bool> </property> <widget class="QWidget" name="scrollAreaWidgetContents"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>447</width> - <height>68</height> - </rect> - </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QLabel" name="aboutMessage"> diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 40b2da3228..92f6430c51 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -30,7 +30,7 @@ <item> <widget class="QLabel" name="infoLabel_SM"> <property name="text"> - <string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string> + <string>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> @@ -237,7 +237,7 @@ <item> <widget class="QLabel" name="infoLabel_VM"> <property name="text"> - <string>Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack.</string> + <string>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 149e0da442..2a13f43ea4 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -67,6 +67,9 @@ static boost::filesystem::detail::utf8_codecvt_facet utf8; #if defined(Q_OS_MAC) extern double NSAppKitVersionNumber; +#if !defined(NSAppKitVersionNumber10_8) +#define NSAppKitVersionNumber10_8 1187 +#endif #if !defined(NSAppKitVersionNumber10_9) #define NSAppKitVersionNumber10_9 1265 #endif @@ -383,7 +386,7 @@ void openDebugLogfile() QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug))); } -void SubstituteFonts() +void SubstituteFonts(const QString& language) { #if defined(Q_OS_MAC) // Background: @@ -393,12 +396,28 @@ void SubstituteFonts() // If this fallback is not properly loaded, some characters may fail to // render correctly. // +// The same thing happened with 10.10. .Helvetica Neue DeskInterface is now default. +// // Solution: If building with the 10.7 SDK or lower and the user's platform // is 10.9 or higher at runtime, substitute the correct font. This needs to // happen before the QApplication is created. #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8 - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_9) - QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8) + { + if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) + /* On a 10.9 - 10.9.x system */ + QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); + else + { + /* 10.10 or later system */ + if (language == "zh_CN" || language == "zh_TW" || language == "zh_HK") // traditional or simplified Chinese + QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Heiti SC"); + else if (language == "ja") // Japanesee + QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Songti SC"); + else + QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Lucida Grande"); + } + } #endif #endif } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index a77036a194..bcbb540c37 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -107,7 +107,7 @@ namespace GUIUtil void openDebugLogfile(); // Replace invalid default fonts with known good ones - void SubstituteFonts(); + void SubstituteFonts(const QString& language); /** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text representation if needed. This assures that Qt can word-wrap long tooltip messages. diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 35846bc153..39171c89eb 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -9,6 +9,8 @@ #include "paymentrequestplus.h" +#include "util.h" + #include <stdexcept> #include <openssl/x509.h> @@ -150,7 +152,13 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c int result = X509_verify_cert(store_ctx); if (result != 1) { int error = X509_STORE_CTX_get_error(store_ctx); - throw SSLVerifyError(X509_verify_cert_error_string(error)); + // For testing payment requests, we allow self signed root certs! + // This option is just shown in the UI options, if -help-debug is enabled. + if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GetBoolArg("-allowselfsignedrootcertificates", false))) { + throw SSLVerifyError(X509_verify_cert_error_string(error)); + } else { + qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true."; + } } X509_NAME *certname = X509_get_subject_name(signing_cert); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 66331ee4b4..46ffd055a5 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -124,19 +124,22 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) // and get 'I don't like X.509 certificates, don't trust anybody' behavior: QString certFile = QString::fromStdString(GetArg("-rootcertificates", "-system-")); - if (certFile.isEmpty()) - return; // Empty store + // Empty store + if (certFile.isEmpty()) { + qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__); + return; + } QList<QSslCertificate> certList; - if (certFile != "-system-") - { + if (certFile != "-system-") { + qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile); + certList = QSslCertificate::fromPath(certFile); // Use those certificates when fetching payment requests, too: QSslSocket::setDefaultCaCertificates(certList); - } - else - certList = QSslSocket::systemCaCertificates (); + } else + certList = QSslSocket::systemCaCertificates(); int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); @@ -518,27 +521,23 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins return false; if (request.IsInitialized()) { - const payments::PaymentDetails& details = request.getDetails(); - // Payment request network matches client network? - if (details.network() != Params().NetworkIDString()) - { + if (!verifyNetwork(request.getDetails())) { emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), CClientUIInterface::MSG_ERROR); return false; } - // Expired payment request? - if (details.has_expires() && (int64_t)details.expires() < GetTime()) - { - emit message(tr("Payment request rejected"), tr("Payment request has expired."), + // Make sure any payment requests involved are still valid. + // This is re-checked just before sending coins in WalletModel::sendCoins(). + if (verifyExpired(request.getDetails())) { + emit message(tr("Payment request rejected"), tr("Payment request expired."), CClientUIInterface::MSG_ERROR); return false; } - } - else { + } else { emit message(tr("Payment request error"), tr("Payment request is not initialized."), CClientUIInterface::MSG_ERROR); @@ -745,3 +744,27 @@ void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) // currently we don't futher process or store the paymentACK message emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); } + +bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails) +{ + bool fVerified = requestDetails.network() == Params().NetworkIDString(); + if (!fVerified) { + qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".") + .arg(__func__) + .arg(QString::fromStdString(requestDetails.network())) + .arg(QString::fromStdString(Params().NetworkIDString())); + } + return fVerified; +} + +bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails) +{ + bool fVerified = (requestDetails.has_expires() && (int64_t)requestDetails.expires() < GetTime()); + if (fVerified) { + const QString requestExpires = QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", (int64_t)requestDetails.expires())); + qWarning() << QString("PaymentServer::%1: Payment request expired \"%2\".") + .arg(__func__) + .arg(requestExpires); + } + return fVerified; +} diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 2fc24395f6..db5f44ff1d 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -91,6 +91,11 @@ public: // This is now public, because we use it in paymentservertests.cpp static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request); + // Verify that the payment request network matches the client network + static bool verifyNetwork(const payments::PaymentDetails& requestDetails); + // Verify if the payment request is expired + static bool verifyExpired(const payments::PaymentDetails& requestDetails); + signals: // Fired when a valid payment request is received void receivedPaymentRequest(SendCoinsRecipient); diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png Binary files differindex eeef943355..83eb3c07ee 100644 --- a/src/qt/res/icons/about.png +++ b/src/qt/res/icons/about.png diff --git a/src/qt/res/icons/about_qt.png b/src/qt/res/icons/about_qt.png Binary files differindex d3665e9892..dd27a99d0a 100644 --- a/src/qt/res/icons/about_qt.png +++ b/src/qt/res/icons/about_qt.png diff --git a/src/qt/res/icons/add.png b/src/qt/res/icons/add.png Binary files differindex ef995cc0b5..1442b4e85e 100644 --- a/src/qt/res/icons/add.png +++ b/src/qt/res/icons/add.png diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png Binary files differindex 0c9238c18e..b11c7d5356 100644 --- a/src/qt/res/icons/address-book.png +++ b/src/qt/res/icons/address-book.png diff --git a/src/qt/res/icons/bitcoin.png b/src/qt/res/icons/bitcoin.png Binary files differindex 705a20260a..435621af23 100644 --- a/src/qt/res/icons/bitcoin.png +++ b/src/qt/res/icons/bitcoin.png diff --git a/src/qt/res/icons/clock1.png b/src/qt/res/icons/clock1.png Binary files differindex 65adba5e21..ceae5ed0d9 100644 --- a/src/qt/res/icons/clock1.png +++ b/src/qt/res/icons/clock1.png diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png Binary files differindex 196a79ce4a..159f69a8fc 100644 --- a/src/qt/res/icons/clock2.png +++ b/src/qt/res/icons/clock2.png diff --git a/src/qt/res/icons/clock3.png b/src/qt/res/icons/clock3.png Binary files differindex 3d04655ed9..d668e35ffc 100644 --- a/src/qt/res/icons/clock3.png +++ b/src/qt/res/icons/clock3.png diff --git a/src/qt/res/icons/clock4.png b/src/qt/res/icons/clock4.png Binary files differindex c3210c5af1..5ebf8ed7ac 100644 --- a/src/qt/res/icons/clock4.png +++ b/src/qt/res/icons/clock4.png diff --git a/src/qt/res/icons/clock5.png b/src/qt/res/icons/clock5.png Binary files differindex 84a9fa2842..96f15ef7d9 100644 --- a/src/qt/res/icons/clock5.png +++ b/src/qt/res/icons/clock5.png diff --git a/src/qt/res/icons/configure.png b/src/qt/res/icons/configure.png Binary files differindex fe9c6ec5ec..5333c83d5e 100644 --- a/src/qt/res/icons/configure.png +++ b/src/qt/res/icons/configure.png diff --git a/src/qt/res/icons/connect0.png b/src/qt/res/icons/connect0.png Binary files differindex 99bb2575d6..58e2c3e965 100644 --- a/src/qt/res/icons/connect0.png +++ b/src/qt/res/icons/connect0.png diff --git a/src/qt/res/icons/connect1.png b/src/qt/res/icons/connect1.png Binary files differindex dffc692c76..949e7a922d 100644 --- a/src/qt/res/icons/connect1.png +++ b/src/qt/res/icons/connect1.png diff --git a/src/qt/res/icons/connect2.png b/src/qt/res/icons/connect2.png Binary files differindex 3594fb117c..143b2054fb 100644 --- a/src/qt/res/icons/connect2.png +++ b/src/qt/res/icons/connect2.png diff --git a/src/qt/res/icons/connect3.png b/src/qt/res/icons/connect3.png Binary files differindex 3594fb117c..143b2054fb 100644 --- a/src/qt/res/icons/connect3.png +++ b/src/qt/res/icons/connect3.png diff --git a/src/qt/res/icons/connect4.png b/src/qt/res/icons/connect4.png Binary files differindex 0c667c7e06..f96e3455ce 100644 --- a/src/qt/res/icons/connect4.png +++ b/src/qt/res/icons/connect4.png diff --git a/src/qt/res/icons/debugwindow.png b/src/qt/res/icons/debugwindow.png Binary files differindex 576e57ab03..290fe60864 100644 --- a/src/qt/res/icons/debugwindow.png +++ b/src/qt/res/icons/debugwindow.png diff --git a/src/qt/res/icons/edit.png b/src/qt/res/icons/edit.png Binary files differindex 4df2229e98..46582716ef 100644 --- a/src/qt/res/icons/edit.png +++ b/src/qt/res/icons/edit.png diff --git a/src/qt/res/icons/editcopy.png b/src/qt/res/icons/editcopy.png Binary files differindex db0c51772c..74ac8b2774 100644 --- a/src/qt/res/icons/editcopy.png +++ b/src/qt/res/icons/editcopy.png diff --git a/src/qt/res/icons/editpaste.png b/src/qt/res/icons/editpaste.png Binary files differindex be8634674d..7b47f4d52b 100644 --- a/src/qt/res/icons/editpaste.png +++ b/src/qt/res/icons/editpaste.png diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png Binary files differindex 18d0596194..ac76cc1eff 100644 --- a/src/qt/res/icons/export.png +++ b/src/qt/res/icons/export.png diff --git a/src/qt/res/icons/eye.png b/src/qt/res/icons/eye.png Binary files differindex 7036708de5..f2f139dbb2 100644 --- a/src/qt/res/icons/eye.png +++ b/src/qt/res/icons/eye.png diff --git a/src/qt/res/icons/eye_minus.png b/src/qt/res/icons/eye_minus.png Binary files differindex bdbe073627..795bf6436a 100644 --- a/src/qt/res/icons/eye_minus.png +++ b/src/qt/res/icons/eye_minus.png diff --git a/src/qt/res/icons/eye_plus.png b/src/qt/res/icons/eye_plus.png Binary files differindex 2ba5e68c76..eaab69297a 100644 --- a/src/qt/res/icons/eye_plus.png +++ b/src/qt/res/icons/eye_plus.png diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png Binary files differindex a53390f594..779cca1d52 100644 --- a/src/qt/res/icons/filesave.png +++ b/src/qt/res/icons/filesave.png diff --git a/src/qt/res/icons/history.png b/src/qt/res/icons/history.png Binary files differindex cb723abc5f..68d841fa85 100644 --- a/src/qt/res/icons/history.png +++ b/src/qt/res/icons/history.png diff --git a/src/qt/res/icons/info.png b/src/qt/res/icons/info.png Binary files differindex 085fa8ea73..692b50c2a9 100644 --- a/src/qt/res/icons/info.png +++ b/src/qt/res/icons/info.png diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png Binary files differindex d21f81364d..f301c4f38c 100644 --- a/src/qt/res/icons/key.png +++ b/src/qt/res/icons/key.png diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png Binary files differindex 77914ab2ce..1bd98b21a6 100644 --- a/src/qt/res/icons/lock_closed.png +++ b/src/qt/res/icons/lock_closed.png diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png Binary files differindex 50615b7336..a7045133b1 100644 --- a/src/qt/res/icons/lock_open.png +++ b/src/qt/res/icons/lock_open.png diff --git a/src/qt/res/icons/open.png b/src/qt/res/icons/open.png Binary files differindex 390d3dab64..4d958f0e18 100644 --- a/src/qt/res/icons/open.png +++ b/src/qt/res/icons/open.png diff --git a/src/qt/res/icons/overview.png b/src/qt/res/icons/overview.png Binary files differindex 36e1003c3c..411595413d 100644 --- a/src/qt/res/icons/overview.png +++ b/src/qt/res/icons/overview.png diff --git a/src/qt/res/icons/quit.png b/src/qt/res/icons/quit.png Binary files differindex 6e44a2d329..55e34de4b8 100644 --- a/src/qt/res/icons/quit.png +++ b/src/qt/res/icons/quit.png diff --git a/src/qt/res/icons/receive.png b/src/qt/res/icons/receive.png Binary files differindex a53390f594..f4e6f58d05 100644 --- a/src/qt/res/icons/receive.png +++ b/src/qt/res/icons/receive.png diff --git a/src/qt/res/icons/remove.png b/src/qt/res/icons/remove.png Binary files differindex 3849cdd6d8..8e738d6301 100644 --- a/src/qt/res/icons/remove.png +++ b/src/qt/res/icons/remove.png diff --git a/src/qt/res/icons/send.png b/src/qt/res/icons/send.png Binary files differindex 18d0596194..ac76cc1eff 100644 --- a/src/qt/res/icons/send.png +++ b/src/qt/res/icons/send.png diff --git a/src/qt/res/icons/synced.png b/src/qt/res/icons/synced.png Binary files differindex d33914f0b4..5ac28d36a3 100644 --- a/src/qt/res/icons/synced.png +++ b/src/qt/res/icons/synced.png diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png Binary files differindex fd41da0680..1091b86e68 100644 --- a/src/qt/res/icons/transaction0.png +++ b/src/qt/res/icons/transaction0.png diff --git a/src/qt/res/icons/transaction2.png b/src/qt/res/icons/transaction2.png Binary files differindex d33914f0b4..5ac28d36a3 100644 --- a/src/qt/res/icons/transaction2.png +++ b/src/qt/res/icons/transaction2.png diff --git a/src/qt/res/icons/transaction_conflicted.png b/src/qt/res/icons/transaction_conflicted.png Binary files differindex 6e44a2d329..55e34de4b8 100644 --- a/src/qt/res/icons/transaction_conflicted.png +++ b/src/qt/res/icons/transaction_conflicted.png diff --git a/src/qt/res/icons/tx_inout.png b/src/qt/res/icons/tx_inout.png Binary files differindex cecd332ad1..0a6e72a898 100644 --- a/src/qt/res/icons/tx_inout.png +++ b/src/qt/res/icons/tx_inout.png diff --git a/src/qt/res/icons/tx_input.png b/src/qt/res/icons/tx_input.png Binary files differindex 1b4cfd967c..9e9ee92932 100644 --- a/src/qt/res/icons/tx_input.png +++ b/src/qt/res/icons/tx_input.png diff --git a/src/qt/res/icons/tx_mined.png b/src/qt/res/icons/tx_mined.png Binary files differindex 421a9cf639..5a6ef521c0 100644 --- a/src/qt/res/icons/tx_mined.png +++ b/src/qt/res/icons/tx_mined.png diff --git a/src/qt/res/icons/tx_output.png b/src/qt/res/icons/tx_output.png Binary files differindex 06d9d0adf2..6f66ab6547 100644 --- a/src/qt/res/icons/tx_output.png +++ b/src/qt/res/icons/tx_output.png diff --git a/src/qt/res/icons/verify.png b/src/qt/res/icons/verify.png Binary files differindex 9ff35c2793..8e2cb2cc14 100644 --- a/src/qt/res/icons/verify.png +++ b/src/qt/res/icons/verify.png diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png Binary files differdeleted file mode 100644 index fdede66172..0000000000 --- a/src/qt/res/images/about.png +++ /dev/null diff --git a/src/qt/res/movies/spinner-000.png b/src/qt/res/movies/spinner-000.png Binary files differindex b296a58481..1e92d859da 100644 --- a/src/qt/res/movies/spinner-000.png +++ b/src/qt/res/movies/spinner-000.png diff --git a/src/qt/res/movies/spinner-001.png b/src/qt/res/movies/spinner-001.png Binary files differindex 4f6f9a487b..d167f20541 100644 --- a/src/qt/res/movies/spinner-001.png +++ b/src/qt/res/movies/spinner-001.png diff --git a/src/qt/res/movies/spinner-002.png b/src/qt/res/movies/spinner-002.png Binary files differindex 4f14e3ca93..4a1f1f8e56 100644 --- a/src/qt/res/movies/spinner-002.png +++ b/src/qt/res/movies/spinner-002.png diff --git a/src/qt/res/movies/spinner-003.png b/src/qt/res/movies/spinner-003.png Binary files differindex d7756e73bf..fb1c2cd4ad 100644 --- a/src/qt/res/movies/spinner-003.png +++ b/src/qt/res/movies/spinner-003.png diff --git a/src/qt/res/movies/spinner-004.png b/src/qt/res/movies/spinner-004.png Binary files differindex 4b381b81b2..4df2132344 100644 --- a/src/qt/res/movies/spinner-004.png +++ b/src/qt/res/movies/spinner-004.png diff --git a/src/qt/res/movies/spinner-005.png b/src/qt/res/movies/spinner-005.png Binary files differindex cbdb5b5797..5d6f41e0dc 100644 --- a/src/qt/res/movies/spinner-005.png +++ b/src/qt/res/movies/spinner-005.png diff --git a/src/qt/res/movies/spinner-006.png b/src/qt/res/movies/spinner-006.png Binary files differindex 55d4540c92..c1f7d18899 100644 --- a/src/qt/res/movies/spinner-006.png +++ b/src/qt/res/movies/spinner-006.png diff --git a/src/qt/res/movies/spinner-007.png b/src/qt/res/movies/spinner-007.png Binary files differindex b25f59a445..1e794b2626 100644 --- a/src/qt/res/movies/spinner-007.png +++ b/src/qt/res/movies/spinner-007.png diff --git a/src/qt/res/movies/spinner-008.png b/src/qt/res/movies/spinner-008.png Binary files differindex 6493184a7a..df12ea8719 100644 --- a/src/qt/res/movies/spinner-008.png +++ b/src/qt/res/movies/spinner-008.png diff --git a/src/qt/res/movies/spinner-009.png b/src/qt/res/movies/spinner-009.png Binary files differindex 938c49f9d3..18fc3a7d16 100644 --- a/src/qt/res/movies/spinner-009.png +++ b/src/qt/res/movies/spinner-009.png diff --git a/src/qt/res/movies/spinner-010.png b/src/qt/res/movies/spinner-010.png Binary files differindex 7eb645eda5..a79c845fe8 100644 --- a/src/qt/res/movies/spinner-010.png +++ b/src/qt/res/movies/spinner-010.png diff --git a/src/qt/res/movies/spinner-011.png b/src/qt/res/movies/spinner-011.png Binary files differindex fd4b63ca5a..57baf66895 100644 --- a/src/qt/res/movies/spinner-011.png +++ b/src/qt/res/movies/spinner-011.png diff --git a/src/qt/res/movies/spinner-012.png b/src/qt/res/movies/spinner-012.png Binary files differindex 10d26a3a53..9deae7853a 100644 --- a/src/qt/res/movies/spinner-012.png +++ b/src/qt/res/movies/spinner-012.png diff --git a/src/qt/res/movies/spinner-013.png b/src/qt/res/movies/spinner-013.png Binary files differindex 863a9d2908..0659d48dec 100644 --- a/src/qt/res/movies/spinner-013.png +++ b/src/qt/res/movies/spinner-013.png diff --git a/src/qt/res/movies/spinner-014.png b/src/qt/res/movies/spinner-014.png Binary files differindex d01086cb98..bc1ef51bde 100644 --- a/src/qt/res/movies/spinner-014.png +++ b/src/qt/res/movies/spinner-014.png diff --git a/src/qt/res/movies/spinner-015.png b/src/qt/res/movies/spinner-015.png Binary files differindex 402dbea693..24b57b62c2 100644 --- a/src/qt/res/movies/spinner-015.png +++ b/src/qt/res/movies/spinner-015.png diff --git a/src/qt/res/movies/spinner-016.png b/src/qt/res/movies/spinner-016.png Binary files differindex 1db20e6078..d622872651 100644 --- a/src/qt/res/movies/spinner-016.png +++ b/src/qt/res/movies/spinner-016.png diff --git a/src/qt/res/movies/spinner-017.png b/src/qt/res/movies/spinner-017.png Binary files differindex e2c2e2ef78..f48f688db2 100644 --- a/src/qt/res/movies/spinner-017.png +++ b/src/qt/res/movies/spinner-017.png diff --git a/src/qt/res/movies/spinner-018.png b/src/qt/res/movies/spinner-018.png Binary files differindex 6f1fe73756..a2c8f38b1d 100644 --- a/src/qt/res/movies/spinner-018.png +++ b/src/qt/res/movies/spinner-018.png diff --git a/src/qt/res/movies/spinner-019.png b/src/qt/res/movies/spinner-019.png Binary files differindex 5f18f65608..9d7cc35d82 100644 --- a/src/qt/res/movies/spinner-019.png +++ b/src/qt/res/movies/spinner-019.png diff --git a/src/qt/res/movies/spinner-020.png b/src/qt/res/movies/spinner-020.png Binary files differindex c12ae20016..1a07acc454 100644 --- a/src/qt/res/movies/spinner-020.png +++ b/src/qt/res/movies/spinner-020.png diff --git a/src/qt/res/movies/spinner-021.png b/src/qt/res/movies/spinner-021.png Binary files differindex d81ceade23..9cea8f2543 100644 --- a/src/qt/res/movies/spinner-021.png +++ b/src/qt/res/movies/spinner-021.png diff --git a/src/qt/res/movies/spinner-022.png b/src/qt/res/movies/spinner-022.png Binary files differindex 69c6657942..60250f6dea 100644 --- a/src/qt/res/movies/spinner-022.png +++ b/src/qt/res/movies/spinner-022.png diff --git a/src/qt/res/movies/spinner-023.png b/src/qt/res/movies/spinner-023.png Binary files differindex 7bed5bae85..fc290a0cf2 100644 --- a/src/qt/res/movies/spinner-023.png +++ b/src/qt/res/movies/spinner-023.png diff --git a/src/qt/res/movies/spinner-024.png b/src/qt/res/movies/spinner-024.png Binary files differindex b3be8d3e8e..c5dcf1eae9 100644 --- a/src/qt/res/movies/spinner-024.png +++ b/src/qt/res/movies/spinner-024.png diff --git a/src/qt/res/movies/spinner-025.png b/src/qt/res/movies/spinner-025.png Binary files differindex 3a7fa9ab0d..7f3577a4de 100644 --- a/src/qt/res/movies/spinner-025.png +++ b/src/qt/res/movies/spinner-025.png diff --git a/src/qt/res/movies/spinner-026.png b/src/qt/res/movies/spinner-026.png Binary files differindex dd92fc4fc1..1663ddf44c 100644 --- a/src/qt/res/movies/spinner-026.png +++ b/src/qt/res/movies/spinner-026.png diff --git a/src/qt/res/movies/spinner-027.png b/src/qt/res/movies/spinner-027.png Binary files differindex 9adefee268..d0e6da4503 100644 --- a/src/qt/res/movies/spinner-027.png +++ b/src/qt/res/movies/spinner-027.png diff --git a/src/qt/res/movies/spinner-028.png b/src/qt/res/movies/spinner-028.png Binary files differindex 83e7cdd583..2a7aba50e2 100644 --- a/src/qt/res/movies/spinner-028.png +++ b/src/qt/res/movies/spinner-028.png diff --git a/src/qt/res/movies/spinner-029.png b/src/qt/res/movies/spinner-029.png Binary files differindex 6cbdbb0fe1..c8ca15c1e1 100644 --- a/src/qt/res/movies/spinner-029.png +++ b/src/qt/res/movies/spinner-029.png diff --git a/src/qt/res/movies/spinner-030.png b/src/qt/res/movies/spinner-030.png Binary files differindex e4a09a44bc..c847c99a93 100644 --- a/src/qt/res/movies/spinner-030.png +++ b/src/qt/res/movies/spinner-030.png diff --git a/src/qt/res/movies/spinner-031.png b/src/qt/res/movies/spinner-031.png Binary files differindex 3c3d505741..403443144e 100644 --- a/src/qt/res/movies/spinner-031.png +++ b/src/qt/res/movies/spinner-031.png diff --git a/src/qt/res/movies/spinner-032.png b/src/qt/res/movies/spinner-032.png Binary files differindex 7460f80da3..f9db080567 100644 --- a/src/qt/res/movies/spinner-032.png +++ b/src/qt/res/movies/spinner-032.png diff --git a/src/qt/res/movies/spinner-033.png b/src/qt/res/movies/spinner-033.png Binary files differindex d327e8fb08..43f57719e7 100644 --- a/src/qt/res/movies/spinner-033.png +++ b/src/qt/res/movies/spinner-033.png diff --git a/src/qt/res/movies/spinner-034.png b/src/qt/res/movies/spinner-034.png Binary files differindex d8432751da..c26656ff17 100644 --- a/src/qt/res/movies/spinner-034.png +++ b/src/qt/res/movies/spinner-034.png diff --git a/src/qt/res/movies/spinner-035.png b/src/qt/res/movies/spinner-035.png Binary files differindex c89c959c94..e471f950a3 100644 --- a/src/qt/res/movies/spinner-035.png +++ b/src/qt/res/movies/spinner-035.png diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index ffee56131d..9e8743d805 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -529,6 +529,10 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn case WalletModel::InsaneFee: msgParams.first = tr("A fee higher than %1 is considered an insanely high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); break; + case WalletModel::PaymentRequestExpired: + msgParams.first = tr("Payment request expired!"); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; // included to prevent a compiler warning. case WalletModel::OK: default: @@ -657,19 +661,19 @@ void SendCoinsDialog::coinControlClipboardAmount() // Coin Control: copy label "Fee" to clipboard void SendCoinsDialog::coinControlClipboardFee() { - GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // Coin Control: copy label "After fee" to clipboard void SendCoinsDialog::coinControlClipboardAfterFee() { - GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // Coin Control: copy label "Bytes" to clipboard void SendCoinsDialog::coinControlClipboardBytes() { - GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } // Coin Control: copy label "Priority" to clipboard @@ -687,7 +691,7 @@ void SendCoinsDialog::coinControlClipboardLowOutput() // Coin Control: copy label "Change" to clipboard void SendCoinsDialog::coinControlClipboardChange() { - GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // Coin Control: settings menu - coin control enabled/disabled by user diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 366ed3df3d..e6a7fcaec5 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -42,7 +42,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) QString copyrightText = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); QString titleAddText = networkStyle->getTitleAddText(); - QString font = "Arial"; + QString font = QApplication::font().toString(); // create a bitmap according to device pixelratio QSize splashSize(480*devicePixelRatio,320*devicePixelRatio); diff --git a/src/qt/test/paymentrequestdata.h b/src/qt/test/paymentrequestdata.h index 37544cdebb..50636d7c67 100644 --- a/src/qt/test/paymentrequestdata.h +++ b/src/qt/test/paymentrequestdata.h @@ -6,16 +6,16 @@ // Data for paymentservertests.cpp // -// Base64/DER-encoded fake certificate authority certificate. +// Base64/DER-encoded fake certificate authority certificates. // Convert pem to base64/der with: -// cat file.pem | openssl x509 -inform PEM -outform DER | openssl enc -base64 -// +// openssl x509 -in cert.pem -inform PEM -outform DER | openssl enc -base64 + // Serial Number: 10302349811211485352 (0x8ef94c91b112c0a8) // Issuer: CN=PaymentRequest Test CA // Subject: CN=PaymentRequest Test CA // Not Valid After : Dec 8 16:37:24 2022 GMT // -const char* caCert_BASE64 = +const char* caCert1_BASE64 = "\ MIIB0DCCATmgAwIBAgIJAI75TJGxEsCoMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\ BAMTFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTIxMjEwMTYzNzI0WhcNMjIx\ @@ -29,11 +29,36 @@ RtQcf0AJ9olzUMY4syehxbzUJP6aeXhZEYiMvdvcv9D55clq6+WLLlNT3jBgAaVn\ p3waRjPD4bUX3nv+ojz5s4puw7Qq5QUZlhGsMzPvwDGCmZkL\ "; +// Serial Number: f0:da:97:e4:38:d7:64:16 +// Issuer: CN=PaymentRequest Test CA +// Subject: CN=PaymentRequest Test CA +// Not Valid After : Jan 8 18:21:06 2025 GMT +// +const char* caCert2_BASE64 = +"\ +MIIC1TCCAb2gAwIBAgIJAPDal+Q412QWMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\ +BAMMFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTUwMTExMTgyMTA2WhcNMjUw\ +MTA4MTgyMTA2WjAhMR8wHQYDVQQDDBZQYXltZW50UmVxdWVzdCBUZXN0IENBMIIB\ +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1S9wVLfTplJuT/1OaaBgl/Mb\ +I392v8S9kHbzYz7B4OTMslaO7piz0v3SO3TKMh0dswjiRdHrIgpO7XdIUQiU/ugg\ +xDw0kuNehfz1ycaGedlFFtFHTNXqLyIUF3dlwHhQwaomM6RXoJmxLny5BhYHEcmk\ +yWwr3Cdjd9gAZpblugVJB9C1e40uyL8ao4PHdLzOqO27iSe6riP8SwwisJZEbMaz\ +AZpgNEEMbIXPJEFvm5HTRXSMtQCOTSZYMFF0M2yrtmlECnz7hWP19b9bcoDzZQB4\ +ylIsFG/7q2jV7MC/e2STZv+niJiHL08RUdoFpAgzaxMgqj63C7B55HgNDNHJYQID\ +AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBGejPxLxj9\ ++crv6gUeEBMZPiUx7pUgcI22Wm5yymP96B4fwI3Y0DBehq20d76vbWGPN17Z6pH3\ +ge7PVY1SYqXtS6hXTo4olCm/BZADli+2Bs2xCiaa+Ltve4ufVej+bKJXN/YnrhvO\ +Kq+klQkuuHywU+GJV/NQeBqToIrSOBgi477NgLFCCCmmx2QWsxHoCFGfuRCBVseT\ +z2k/tMuALCDXGeZBRPTsGHu1y4cj84swAeoDK5QSQcI+Ub7GKc+zkoj02sdDLiMo\ +3wokYPcIy47oclhmb4xubHc+y7nF610yZBoC/zgbhbawnZ65hDDWkdQ/SVAnWZD7\ +9PFfmNnYPTQH\ +"; + // // This payment request validates directly against the -// above certificate authority. +// caCert1 certificate authority. // -const char* paymentrequest1_BASE64 = +const char* paymentrequest1_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMjEyMTAx\ @@ -55,7 +80,7 @@ SiWVbw0tX/68iSQEGGfh9n6ee/8Myb3ICdw=\ // // Signed, but expired, merchant cert in the request // -const char* paymentrequest2_BASE64 = +const char* paymentrequest2_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhrsAwrpAzCCAeUwggFOoAMCAQICAQMwDQYJKoZIhvcNAQEL\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzAyMjMy\ @@ -75,9 +100,9 @@ tejrSPOBNSJ3Mi/q5u2Yl4gJZY2b\ "; // -// 10-long chain, all intermediates valid +// 10-long certificate chain, all intermediates valid // -const char* paymentrequest3_BASE64 = +const char* paymentrequest3_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1Nhq8JAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\ @@ -184,9 +209,9 @@ chhR/aHOuEMTxmc12K4rNlgYtHCsxLP9zd+6u0cva3TucZ6EzS8PKEib/+r12/52\ "; // -// Long chain, with an invalid (expired) cert in the middle +// Long certificate chain, with an expired certificate in the middle // -const char* paymentrequest4_BASE64 = +const char* paymentrequest4_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhqeJAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\ @@ -291,7 +316,10 @@ HXQjsfdR58qZQS9CS5DAtRUf0R8+43/wijO/hb49VNaNXmY+/cPHMkahP2aV3tZi\ FAyZblLik9A7ZvF+UsjeFQiHB5wzWQvbqk5wQ4yabHIXoYv/E0q+eQ==\ "; -const char* paymentrequest5_BASE64 = +// +// Validly signed, but by a CA not in our root CA list +// +const char* paymentrequest5_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzA0MTkx\ @@ -309,3 +337,99 @@ ssymvca1S/1KeM3n8Ydi2fi1JUzAAr59xPvNJRUeqCLP9upHn5z7br3P12Oz9A20\ 5/4wL4ClPRPVnOHgij0bEg+y0tGESqmF1rfOfXDszlo2U92wCxS07kq79YAZJ1Zo\ XYh860/Q4wvc7lfiTe+dXBzPKAKhMy91yETY\ "; + +// +// Contains a testnet paytoaddress, so payment request network doesn't match client network +// +const char* paymentrequest1_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iPQoEdGVzdBIhCIDWwowE\ +Ehl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGNeMy6UFKgxKdXN0IFRlc3Rpbmcq\ +gAFwThsozZxkZxzCn4R8WxNiLFV6m0ye9fEtSbolfaW+EjBMpO03lr/dwNnrclhg\ +ew+A05xfZztrAt16XKEY7qKJ/eY2nLd0fVAIu/nIt+7/VYVXT83zLrWc150aRS7W\ +AdJbL3JOJLs6Eyp5zrPbfI8faRttFAdONKDrJgIpuW1E3g==\ +"; + +// +// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01) +// +const char* paymentrequest2_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iQgoEdGVzdBIgCICt4gQS\ +GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYiNLUpQUgASoQVGVzdGluZyB0ZXN0\ +bmV0ISqAATXq9A5nmJgtmee/bQTeHeif4w1YYFPBlKghwx6qbVgXTWnwBJtOQhhV\ +sZdzbTl95ENR7/Y7VJupW9kDWobCK7zUUhLAzUlwmLlcx6itHw8LTUF5HK+AwsZm\ +Zs85lISGvOS0NZW/ENa6l+oQRnL87oqVZr/EDGiuqjz6T0ThQi0l\ +"; + +// +// Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t) +// +const char* paymentrequest3_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iSgoEdGVzdBIgCICt4gQS\ +GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYyNfZpQUg//////////9/KhBUZXN0\ +aW5nIHRlc3RuZXQhKoABNwi8WnMW4aMvbmvorTiiWJLFhofLFnsoWCJnj3rWLnLh\ +n3w6q/fZ26p50ERL/noxdTUfeFsKnlECkUu/fOcOrqyYDiwvxI0SZ034DleVyFU1\ +Z3T+X0zcL8oe7bX01Yf+s2V+5JXQXarKnKBrZCGgv2ARjFNSZe7E7vGg5K4Q6Q8=\ +"; + +// +// Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64) +// +const char* paymentrequest4_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iSwoEdGVzdBIgCICt4gQS\ +GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYt+HZpQUggICAgICAgICAASoQVGVz\ +dGluZyB0ZXN0bmV0ISqAAXSQG8+GFA18VaKarlYrOz293rNMIub0swKGcQm8jAGX\ +HSLaRgHfUDeEPr4hydy4dtfu59KNwe2xsHOHu/SpO4L8SrA4Dm9A7SlNBVWdcLbw\ +d2hj739GDLz0b5KuJ2SG6VknMRQM976w/m2qlq0ccVGaaZ2zMIGfpzL3p6adwx/5\ +"; diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index 70254cd75d..04935192c8 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -65,38 +65,44 @@ void PaymentServerTests::paymentServerTests() OptionsModel optionsModel; PaymentServer* server = new PaymentServer(NULL, false); X509_STORE* caStore = X509_STORE_new(); - X509_STORE_add_cert(caStore, parse_b64der_cert(caCert_BASE64)); + X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64)); PaymentServer::LoadRootCAs(caStore); server->setOptionsModel(&optionsModel); server->uiReady(); - // Now feed PaymentRequests to server, and observe signals it produces: - std::vector<unsigned char> data = DecodeBase64(paymentrequest1_BASE64); - SendCoinsRecipient r = handleRequest(server, data); + std::vector<unsigned char> data; + SendCoinsRecipient r; QString merchant; + + // Now feed PaymentRequests to server, and observe signals it produces + + // This payment request validates directly against the + // caCert1 certificate authority: + data = DecodeBase64(paymentrequest1_cert1_BASE64); + r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("testmerchant.org")); - // Version of the above, with an expired certificate: - data = DecodeBase64(paymentrequest2_BASE64); + // Signed, but expired, merchant cert in the request: + data = DecodeBase64(paymentrequest2_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); - // Long certificate chain: - data = DecodeBase64(paymentrequest3_BASE64); + // 10-long certificate chain, all intermediates valid: + data = DecodeBase64(paymentrequest3_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("testmerchant8.org")); // Long certificate chain, with an expired certificate in the middle: - data = DecodeBase64(paymentrequest4_BASE64); + data = DecodeBase64(paymentrequest4_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); // Validly signed, but by a CA not in our root CA list: - data = DecodeBase64(paymentrequest5_BASE64); + data = DecodeBase64(paymentrequest5_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); @@ -104,12 +110,71 @@ void PaymentServerTests::paymentServerTests() // Try again with no root CA's, verifiedMerchant should be empty: caStore = X509_STORE_new(); PaymentServer::LoadRootCAs(caStore); - data = DecodeBase64(paymentrequest1_BASE64); + data = DecodeBase64(paymentrequest1_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); - // Just get some random data big enough to trigger BIP70 DoS protection + // Load second root certificate + caStore = X509_STORE_new(); + X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64)); + PaymentServer::LoadRootCAs(caStore); + + QByteArray byteArray; + + // For the tests below we just need the payment request data from + // paymentrequestdata.h parsed + stored in r.paymentRequest. + // + // These tests require us to bypass the following normal client execution flow + // shown below to be able to explicitly just trigger a certain condition! + // + // handleRequest() + // -> PaymentServer::eventFilter() + // -> PaymentServer::handleURIOrFile() + // -> PaymentServer::readPaymentRequestFromFile() + // -> PaymentServer::processPaymentRequest() + + // Contains a testnet paytoaddress, so payment request network doesn't match client network: + data = DecodeBase64(paymentrequest1_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized, because network "main" is default, even for + // uninizialized payment requests and that will fail our test here. + QVERIFY(r.paymentRequest.IsInitialized()); + QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false); + + // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01): + data = DecodeBase64(paymentrequest2_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // compares 1 < GetTime() == false (treated as expired payment request) + QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true); + + // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t): + // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t) + // -1 is 1969-12-31 23:59:59 (for a 32 bit time values) + data = DecodeBase64(paymentrequest3_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request) + QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false); + + // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64): + // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t) + // 0 is 1970-01-01 00:00:00 (for a 32 bit time values) + data = DecodeBase64(paymentrequest4_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // compares -9223372036854775808 < GetTime() == true (treated as expired payment request) + QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true); + + // Test BIP70 DoS protection: unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1]; GetRandBytes(randData, sizeof(randData)); // Write data to a temp file: @@ -117,7 +182,6 @@ void PaymentServerTests::paymentServerTests() tempFile.open(); tempFile.write((const char*)randData, sizeof(randData)); tempFile.close(); - // Trigger BIP70 DoS protection QCOMPARE(PaymentServer::readPaymentRequestFromFile(tempFile.fileName(), r.paymentRequest), false); delete server; diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 2858982f09..092d919042 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -49,10 +49,10 @@ public: }; enum ColumnWidths { - STATUS_COLUMN_WIDTH = 23, + STATUS_COLUMN_WIDTH = 30, WATCHONLY_COLUMN_WIDTH = 23, DATE_COLUMN_WIDTH = 120, - TYPE_COLUMN_WIDTH = 120, + TYPE_COLUMN_WIDTH = 113, AMOUNT_MINIMUM_COLUMN_WIDTH = 120, MINIMUM_COLUMN_WIDTH = 23 }; diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 9ee408179d..4ef42b927e 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -12,6 +12,7 @@ #include "clientversion.h" #include "init.h" +#include "util.h" #include <stdio.h> @@ -73,8 +74,8 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : tf.setBorderStyle(QTextFrameFormat::BorderStyle_None); tf.setCellPadding(2); QVector<QTextLength> widths; - widths << QTextLength(QTextLength::PercentageLength, 20); - widths << QTextLength(QTextLength::PercentageLength, 80); + widths << QTextLength(QTextLength::PercentageLength, 35); + widths << QTextLength(QTextLength::PercentageLength, 65); tf.setColumnWidthConstraints(widths); QTextTable *table = cursor.insertTable(2, 2, tf); @@ -108,6 +109,12 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : cursor.movePosition(QTextCursor::NextRow); cursor.insertText(tr("UI options") + ":", bold); cursor.movePosition(QTextCursor::NextRow); + if (GetBoolArg("-help-debug", false)) { + cursor.insertText("-allowselfsignedrootcertificates"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Allow self signed root certificates (default: 0)")); + cursor.movePosition(QTextCursor::NextCell); + } cursor.insertText("-choosedatadir"); cursor.movePosition(QTextCursor::NextCell); cursor.insertText(tr("Choose data directory on startup (default: 0)")); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 6006a7bd7b..57596b77bd 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -6,6 +6,7 @@ #include "addresstablemodel.h" #include "guiconstants.h" +#include "paymentserver.h" #include "recentrequeststablemodel.h" #include "transactiontablemodel.h" @@ -294,11 +295,16 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); - // Store PaymentRequests in wtx.vOrderForm in wallet. foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) { if (rcp.paymentRequest.IsInitialized()) { + // Make sure any payment requests involved are still valid. + if (PaymentServer::verifyExpired(rcp.paymentRequest.getDetails())) { + return PaymentRequestExpired; + } + + // Store PaymentRequests in wtx.vOrderForm in wallet. std::string key("PaymentRequest"); std::string value; rcp.paymentRequest.SerializeToString(&value); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index d8df25f660..9916d11f93 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -40,7 +40,7 @@ public: explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message): address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} - // If from an insecure payment request, this is used for storing + // If from an unauthenticated payment request, this is used for storing // the addresses, e.g. address-A<br />address-B<br />address-C. // Info: As we don't need to process addresses in here when using // payment requests, we can abuse it for displaying an address list. @@ -111,7 +111,8 @@ public: DuplicateAddress, TransactionCreationFailed, // Error returned when wallet is still locked TransactionCommitFailed, - InsaneFee + InsaneFee, + PaymentRequestExpired }; enum EncryptionStatus diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 603e2935dd..5df5de66d9 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -201,24 +201,6 @@ Value setgenerate(const Array& params, bool fHelp) return Value::null; } -Value gethashespersec(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "gethashespersec\n" - "\nReturns a recent hashes per second performance measurement while generating.\n" - "See the getgenerate and setgenerate calls to turn generation on and off.\n" - "\nResult:\n" - "n (numeric) The recent hashes per second when generation is on (will return 0 if generation is off)\n" - "\nExamples:\n" - + HelpExampleCli("gethashespersec", "") - + HelpExampleRpc("gethashespersec", "") - ); - - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (int64_t)0; - return (int64_t)dHashesPerSec; -} #endif @@ -237,7 +219,6 @@ Value getmininginfo(const Array& params, bool fHelp) " \"errors\": \"...\" (string) Current errors\n" " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" - " \"hashespersec\": n (numeric) The hashes per second of the generation, or 0 if no generation.\n" " \"pooledtx\": n (numeric) The size of the mem pool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -260,7 +241,6 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("chain", Params().NetworkIDString())); #ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); #endif return obj; } diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 184aacf5a8..3d647a0d2d 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -165,7 +165,7 @@ Value validateaddress(const Array& params, bool fHelp) " \"isscript\" : true|false, (boolean) If the key is a script\n" " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" - " \"account\" : \"account\" (string) The account associated with the address, \"\" is the default account\n" + " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n" "}\n" "\nExamples:\n" + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 9bd8233992..2b108bf588 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -216,7 +216,7 @@ Value listunspent(const Array& params, bool fHelp) " \"txid\" : \"txid\", (string) the transaction id \n" " \"vout\" : n, (numeric) the vout value\n" " \"address\" : \"address\", (string) the bitcoin address\n" - " \"account\" : \"account\", (string) The associated account, or \"\" for the default account\n" + " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n" " \"scriptPubKey\" : \"key\", (string) the script key\n" " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" " \"confirmations\" : n (numeric) The number of confirmations\n" diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index a070ab5bbe..e4f23d56d2 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -281,7 +281,6 @@ static const CRPCCommand vRPCCommands[] = #ifdef ENABLE_WALLET /* Coin generation */ { "generating", "getgenerate", &getgenerate, true, false, false }, - { "generating", "gethashespersec", &gethashespersec, true, false, false }, { "generating", "setgenerate", &setgenerate, true, true, false }, #endif @@ -953,7 +952,7 @@ void ServiceConnection(AcceptedConnection *conn) ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto, MAX_SIZE); // HTTP Keep-Alive is false; close connection immediately - if (mapHeaders["connection"] == "close") + if ((mapHeaders["connection"] == "close") || (!GetBoolArg("-rpckeepalive", true))) fRun = false; // Process via JSON-RPC API diff --git a/src/rpcserver.h b/src/rpcserver.h index fb561ab939..1b94b758f2 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -154,7 +154,6 @@ extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fH extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 7a4d685717..6ad3ee54d5 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -79,17 +79,15 @@ Value getnewaddress(const Array& params, bool fHelp) throw runtime_error( "getnewaddress ( \"account\" )\n" "\nReturns a new Bitcoin address for receiving payments.\n" - "If 'account' is specified (recommended), it is added to the address book \n" + "If 'account' is specified (DEPRECATED), it is added to the address book \n" "so payments received with the address will be credited to 'account'.\n" "\nArguments:\n" - "1. \"account\" (string, optional) The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" + "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" "\nResult:\n" "\"bitcoinaddress\" (string) The new bitcoin address\n" "\nExamples:\n" + HelpExampleCli("getnewaddress", "") - + HelpExampleCli("getnewaddress", "\"\"") - + HelpExampleCli("getnewaddress", "\"myaccount\"") - + HelpExampleRpc("getnewaddress", "\"myaccount\"") + + HelpExampleRpc("getnewaddress", "") ); // Parse the account first so we don't generate a key if there's an error @@ -154,7 +152,7 @@ Value getaccountaddress(const Array& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "getaccountaddress \"account\"\n" - "\nReturns the current Bitcoin address for receiving payments to this account.\n" + "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n" "\nArguments:\n" "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n" "\nResult:\n" @@ -212,7 +210,7 @@ Value setaccount(const Array& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "setaccount \"bitcoinaddress\" \"account\"\n" - "\nSets the account associated with the given address.\n" + "\nDEPRECATED. Sets the account associated with the given address.\n" "\nArguments:\n" "1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\n" "2. \"account\" (string, required) The account to assign the address to.\n" @@ -254,7 +252,7 @@ Value getaccount(const Array& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "getaccount \"bitcoinaddress\"\n" - "\nReturns the account associated with the given address.\n" + "\nDEPRECATED. Returns the account associated with the given address.\n" "\nArguments:\n" "1. \"bitcoinaddress\" (string, required) The bitcoin address for account lookup.\n" "\nResult:\n" @@ -281,7 +279,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "getaddressesbyaccount \"account\"\n" - "\nReturns the list of addresses for the given account.\n" + "\nDEPRECATED. Returns the list of addresses for the given account.\n" "\nArguments:\n" "1. \"account\" (string, required) The account name.\n" "\nResult:\n" @@ -400,7 +398,7 @@ Value listaddressgroupings(const Array& params, bool fHelp) " [\n" " \"bitcoinaddress\", (string) The bitcoin address\n" " amount, (numeric) The amount in btc\n" - " \"account\" (string, optional) The account\n" + " \"account\" (string, optional) The account (DEPRECATED)\n" " ]\n" " ,...\n" " ]\n" @@ -542,7 +540,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getreceivedbyaccount \"account\" ( minconf )\n" - "\nReturns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n" + "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n" "\nArguments:\n" "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -627,26 +625,22 @@ Value getbalance(const Array& params, bool fHelp) throw runtime_error( "getbalance ( \"account\" minconf includeWatchonly )\n" "\nIf account is not specified, returns the server's total available balance.\n" - "If account is specified, returns the balance in the account.\n" + "If account is specified (DEPRECATED), returns the balance in the account.\n" "Note that the account \"\" is not the same as leaving the parameter out.\n" "The server total may be different to the balance in the default \"\" account.\n" "\nArguments:\n" - "1. \"account\" (string, optional) The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n" + "1. \"account\" (string, optional) DEPRECATED. The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n" "\nResult:\n" "amount (numeric) The total amount in btc received for this account.\n" "\nExamples:\n" - "\nThe total amount in the server across all accounts\n" + "\nThe total amount in the wallet\n" + HelpExampleCli("getbalance", "") + - "\nThe total amount in the server across all accounts, with at least 5 confirmations\n" + "\nThe total amount in the wallet at least 5 blocks confirmed\n" + HelpExampleCli("getbalance", "\"*\" 6") + - "\nThe total amount in the default account with at least 1 confirmation\n" - + HelpExampleCli("getbalance", "\"\"") + - "\nThe total amount in the account named tabby with at least 6 confirmations\n" - + HelpExampleCli("getbalance", "\"tabby\" 6") + "\nAs a json rpc call\n" - + HelpExampleRpc("getbalance", "\"tabby\", 6") + + HelpExampleRpc("getbalance", "\"*\", 6") ); if (params.size() == 0) @@ -710,7 +704,7 @@ Value movecmd(const Array& params, bool fHelp) if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" - "\nMove a specified amount from one account in your wallet to another.\n" + "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n" "\nArguments:\n" "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n" "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n" @@ -775,7 +769,7 @@ Value sendfrom(const Array& params, bool fHelp) if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" - "\nSent an amount from an account to a bitcoin address.\n" + "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address.\n" "The amount is a real and is rounded to the nearest 0.00000001." + HelpRequiringPassphrase() + "\n" "\nArguments:\n" @@ -836,7 +830,7 @@ Value sendmany(const Array& params, bool fHelp) "\nSend multiple times. Amounts are double-precision floating point numbers." + HelpRequiringPassphrase() + "\n" "\nArguments:\n" - "1. \"fromaccount\" (string, required) The account to send the funds from, can be \"\" for the default account\n" + "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n" "2. \"amounts\" (string, required) A json object with addresses and amounts\n" " {\n" " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n" @@ -849,11 +843,11 @@ Value sendmany(const Array& params, bool fHelp) " the number of addresses.\n" "\nExamples:\n" "\nSend two amounts to two different addresses:\n" - + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") + + + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") + "\nSend two amounts to two different addresses setting the confirmation and comment:\n" - + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") + + + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") + "\nAs a json rpc call\n" - + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"") + + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"") ); string strAccount = AccountFromValue(params[0]); @@ -918,7 +912,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" "\nAdd a nrequired-to-sign multisignature address to the wallet.\n" "Each key is a Bitcoin address or hex-encoded public key.\n" - "If 'account' is specified, assign address to that account.\n" + "If 'account' is specified (DEPRECATED), assign address to that account.\n" "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" @@ -927,7 +921,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) " \"address\" (string) bitcoin address or hex-encoded public key\n" " ...,\n" " ]\n" - "3. \"account\" (string, optional) An account to assign the addresses to.\n" + "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n" "\nResult:\n" "\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n" @@ -1103,7 +1097,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" " \"address\" : \"receivingaddress\", (string) The receiving address\n" - " \"account\" : \"accountname\", (string) The account of the receiving address. The default account is \"\".\n" + " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n" " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n" " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" " }\n" @@ -1124,7 +1118,7 @@ Value listreceivedbyaccount(const Array& params, bool fHelp) if (fHelp || params.size() > 3) throw runtime_error( "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n" - "\nList balances by account.\n" + "\nDEPRECATED. List balances by account.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n" @@ -1251,15 +1245,14 @@ Value listtransactions(const Array& params, bool fHelp) "listtransactions ( \"account\" count from includeWatchonly)\n" "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" "\nArguments:\n" - "1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n" - " If \"\" is set, it will list transactions for the default account.\n" + "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n" "2. count (numeric, optional, default=10) The number of transactions to return\n" "3. from (numeric, optional, default=0) The number of transactions to skip\n" "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n" "\nResult:\n" "[\n" " {\n" - " \"account\":\"accountname\", (string) The account name associated with the transaction. \n" + " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n" " It will be \"\" for the default account.\n" " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n" " move transactions (category = move).\n" @@ -1293,12 +1286,10 @@ Value listtransactions(const Array& params, bool fHelp) "\nExamples:\n" "\nList the most recent 10 transactions in the systems\n" + HelpExampleCli("listtransactions", "") + - "\nList the most recent 10 transactions for the tabby account\n" - + HelpExampleCli("listtransactions", "\"tabby\"") + - "\nList transactions 100 to 120 from the tabby account\n" - + HelpExampleCli("listtransactions", "\"tabby\" 20 100") + + "\nList transactions 100 to 120\n" + + HelpExampleCli("listtransactions", "\"*\" 20 100") + "\nAs a json rpc call\n" - + HelpExampleRpc("listtransactions", "\"tabby\", 20, 100") + + HelpExampleRpc("listtransactions", "\"*\", 20, 100") ); string strAccount = "*"; @@ -1361,7 +1352,7 @@ Value listaccounts(const Array& params, bool fHelp) if (fHelp || params.size() > 2) throw runtime_error( "listaccounts ( minconf includeWatchonly)\n" - "\nReturns Object that has account names as keys, account balances as values.\n" + "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n" "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n" @@ -1444,7 +1435,7 @@ Value listsinceblock(const Array& params, bool fHelp) "\nResult:\n" "{\n" " \"transactions\": [\n" - " \"account\":\"accountname\", (string) The account name associated with the transaction. Will be \"\" for the default account.\n" + " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n" " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n" " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n" " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n" @@ -1538,7 +1529,7 @@ Value gettransaction(const Array& params, bool fHelp) " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n" " \"details\" : [\n" " {\n" - " \"account\" : \"accountname\", (string) The account name involved in the transaction, can be \"\" for the default account.\n" + " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n" " \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n" " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n" " \"amount\" : x.xxx (numeric) The amount in btc\n" diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e979f61f6e..8a06f3d118 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -189,6 +189,11 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) { } bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { + // Empty signature. Not strictly DER encoded, but allowed to provide a + // compact way to provide an invalid signature for use with CHECK(MULTI)SIG + if (vchSig.size() == 0) { + return true; + } if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { @@ -1098,7 +1103,6 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne return false; if (stack.empty()) return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - if (CastToBool(stack.back()) == false) return set_error(serror, SCRIPT_ERR_EVAL_FALSE); @@ -1109,24 +1113,37 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne if (!scriptSig.IsPushOnly()) return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); - // stackCopy cannot be empty here, because if it was the + // Restore stack. + swap(stack, stackCopy); + + // stack cannot be empty here, because if it was the // P2SH HASH <> EQUAL scriptPubKey would be evaluated with // an empty stack and the EvalScript above would return false. - assert(!stackCopy.empty()); + assert(!stack.empty()); - const valtype& pubKeySerialized = stackCopy.back(); + const valtype& pubKeySerialized = stack.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); - popstack(stackCopy); + popstack(stack); - if (!EvalScript(stackCopy, pubKey2, flags, checker, serror)) + if (!EvalScript(stack, pubKey2, flags, checker, serror)) // serror is set return false; - if (stackCopy.empty()) + if (stack.empty()) return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - if (!CastToBool(stackCopy.back())) + if (!CastToBool(stack.back())) return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - else - return set_success(serror); + } + + // The CLEANSTACK check is only performed after potential P2SH evaluation, + // as the non-P2SH evaluation of a P2SH script will obviously not result in + // a clean stack (the P2SH inputs remain). + if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { + // Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK + // would be possible, which is not a softfork (and P2SH should be one). + assert((flags & SCRIPT_VERIFY_P2SH) != 0); + if (stack.size() != 1) { + return set_error(serror, SCRIPT_ERR_CLEANSTACK); + } } return set_success(serror); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 3c4e7d466a..8bf379ed89 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -67,8 +67,14 @@ enum // discouraged NOPs fails the script. This verification flag will never be // a mandatory flag applied to scripts in a block. NOPs that are not // executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7) - + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7), + + // Require that only a single stack element remains after evaluation. This changes the success criterion from + // "At least one stack element must remain, and when interpreted as a boolean, it must be true" to + // "Exactly one stack element must remain, and when interpreted as a boolean, it must be true". + // (softfork safe, BIP62 rule 6) + // Note: CLEANSTACK should never be used without P2SH. + SCRIPT_VERIFY_CLEANSTACK = (1U << 8), }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); diff --git a/src/script/script_error.h b/src/script/script_error.h index 5c260327b6..6365680b29 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -43,6 +43,7 @@ typedef enum ScriptError_t SCRIPT_ERR_SIG_HIGH_S, SCRIPT_ERR_SIG_NULLDUMMY, SCRIPT_ERR_PUBKEYTYPE, + SCRIPT_ERR_CLEANSTACK, /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, diff --git a/src/script/standard.h b/src/script/standard.h index dbeeace4d9..ac80193773 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -48,7 +48,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_NULLDUMMY | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS; + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | + SCRIPT_VERIFY_CLEANSTACK; /** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index f0a54077a5..b9f7d243ec 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -1,6 +1,7 @@ bench_inv bench_sign bench_verify +bench_recover tests *.exe *.so diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index 28cd61dbc9..40f8dae23f 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -4,24 +4,22 @@ compiler: - gcc install: - sudo apt-get install -qq libssl-dev - - if [ "$BIGNUM" = "gmp" -o "$BIGNUM" = "auto" -o "$FIELD" = "gmp" ]; then sudo apt-get install --no-install-recommends --no-upgrade -qq libgmp-dev; fi + - if [ "$BIGNUM" = "gmp" -o "$BIGNUM" = "auto" ]; then sudo apt-get install --no-install-recommends --no-upgrade -qq libgmp-dev; fi - if [ -n "$EXTRAPACKAGES" ]; then sudo apt-get update && sudo apt-get install --no-install-recommends --no-upgrade $EXTRAPACKAGES; fi env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no BUILD=check EXTRAFLAGS= HOST= EXTRAPACKAGES= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= EXTRAPACKAGES= matrix: - SCALAR=32bit - SCALAR=64bit - - FIELD=gmp - - FIELD=gmp ENDOMORPHISM=yes - - FIELD=64bit_asm - - FIELD=64bit_asm ENDOMORPHISM=yes - FIELD=64bit - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ASM=x86_64 + - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - FIELD=32bit - FIELD=32bit ENDOMORPHISM=yes - - BIGNUM=none - - BIGNUM=none ENDOMORPHISM=yes + - BIGNUM=no + - BIGNUM=no ENDOMORPHISM=yes - BUILD=distcheck - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC - HOST=i686-linux-gnu EXTRAPACKAGES="gcc-multilib" diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index 390d2c9ffa..985c172eba 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -33,8 +33,8 @@ noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h noinst_HEADERS += src/util.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h -noinst_HEADERS += src/field_gmp.h -noinst_HEADERS += src/field_gmp_impl.h +noinst_HEADERS += src/hash.h +noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 index 1373478c9c..4a398d6c93 100644 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -1,12 +1,6 @@ dnl libsecp25k1 helper checks AC_DEFUN([SECP_INT128_CHECK],[ has_int128=$ac_cv_type___int128 -if test x"$has_int128" != x"yes" && test x"$set_field" = x"64bit"; then - AC_MSG_ERROR([$set_field field support explicitly requested but is not compatible with this host]) -fi -if test x"$has_int128" != x"yes" && test x"$set_scalar" = x"64bit"; then - AC_MSG_ERROR([$set_scalar scalar support explicitly requested but is not compatible with this host]) -fi ]) dnl @@ -18,11 +12,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ __asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) AC_MSG_RESULT([$has_64bit_asm]) -if test x"$set_field" == x"64bit_asm"; then - if test x"$has_64bit_asm" == x"no"; then - AC_MSG_ERROR([$set_field field support explicitly requested but no x86_64 assembly available]) - fi -fi ]) dnl @@ -43,7 +32,7 @@ else )]) LIBS= fi -if test x"$has_libcrypto" == x"yes" && test x"$has_openssl_ec" = x; then +if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then AC_MSG_CHECKING(for EC functions in libcrypto) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <openssl/ec.h> @@ -69,11 +58,4 @@ if test x"$has_gmp" != x"yes"; then CPPFLAGS="$CPPFLAGS_TEMP" LIBS="$LIBS_TEMP" fi -if test x"$set_field" = x"gmp" && test x"$has_gmp" != x"yes"; then - AC_MSG_ERROR([$set_field field support explicitly requested but libgmp was not found]) -fi -if test x"$set_bignum" = x"gmp" && test x"$has_gmp" != x"yes"; then - AC_MSG_ERROR([$set_bignum field support explicitly requested but libgmp was not found]) -fi ]) - diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 40e121e806..f691156ff7 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -6,7 +6,7 @@ AC_CANONICAL_HOST AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) AH_TOP([#define LIBSECP256K1_CONFIG_H]) AH_BOTTOM([#endif //LIBSECP256K1_CONFIG_H]) -AM_INIT_AUTOMAKE([foreign]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT dnl make the compilation flags quiet unless V=1 is used @@ -23,7 +23,7 @@ if test "x$CFLAGS" = "x"; then fi AC_PROG_CC_C99 -if test x"$ac_cv_prog_cc_c99" == x"no"; then +if test x"$ac_cv_prog_cc_c99" = x"no"; then AC_MSG_ERROR([c99 compiler support required]) fi @@ -82,9 +82,9 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], AC_ARG_ENABLE(benchmark, - AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is yes)]), + AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), [use_benchmark=$enableval], - [use_benchmark=yes]) + [use_benchmark=no]) AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), @@ -96,15 +96,18 @@ AC_ARG_ENABLE(endomorphism, [use_endomorphism=$enableval], [use_endomorphism=no]) -AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=gmp|64bit|64bit_asm|32bit|auto], +AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) -AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|none|auto], +AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], [Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], [Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto] +[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto]) + AC_CHECK_TYPES([__int128]) AC_MSG_CHECKING([for __builtin_expect]) @@ -113,40 +116,54 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], [ AC_MSG_RESULT([no]) ]) -if test x"$req_field" = x"auto"; then +if test x"$req_asm" = x"auto"; then SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" = x"yes"; then - set_field=64bit_asm + set_asm=x86_64 + fi + if test x"$set_asm" = x; then + set_asm=no fi +else + set_asm=$req_asm + case $set_asm in + x86_64) + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid assembly optimization selection]) + ;; + esac +fi +if test x"$req_field" = x"auto"; then + if test x"set_asm" = x"x86_64"; then + set_field=64bit + fi if test x"$set_field" = x; then SECP_INT128_CHECK if test x"$has_int128" = x"yes"; then set_field=64bit fi fi - - if test x"$set_field" = x; then - SECP_GMP_CHECK - if test x"$has_gmp" = x"yes"; then - set_field=gmp - fi - fi - if test x"$set_field" = x; then set_field=32bit fi else set_field=$req_field case $set_field in - 64bit_asm) - SECP_64BIT_ASM_CHECK - ;; 64bit) - SECP_INT128_CHECK - ;; - gmp) - SECP_GMP_CHECK + if test x"$set_asm" != x"x86_64"; then + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) + fi + fi ;; 32bit) ;; @@ -157,11 +174,9 @@ else fi if test x"$req_scalar" = x"auto"; then - if test x"$set_scalar" = x; then - SECP_INT128_CHECK - if test x"$has_int128" = x"yes"; then - set_scalar=64bit - fi + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_scalar=64bit fi if test x"$set_scalar" = x; then set_scalar=32bit @@ -171,6 +186,9 @@ else case $set_scalar in 64bit) SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) + fi ;; 32bit) ;; @@ -187,15 +205,18 @@ if test x"$req_bignum" = x"auto"; then fi if test x"$set_bignum" = x; then - set_bignum=none + set_bignum=no fi else set_bignum=$req_bignum case $set_bignum in gmp) SECP_GMP_CHECK + if test x"$has_gmp" != x"yes"; then + AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) + fi ;; - none) + no) ;; *) AC_MSG_ERROR([invalid bignum implementation selection]) @@ -203,20 +224,23 @@ else esac fi +# select assembly optimization +case $set_asm in +x86_64) + AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) + ;; +no) + ;; +*) + AC_MSG_ERROR([invalid assembly optimizations]) + ;; +esac + # select field implementation case $set_field in -64bit_asm) - AC_DEFINE(USE_FIELD_5X52_ASM, 1, [Define this symbol to use the assembly version for the 5x52 field implementation]) - AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) - ;; 64bit) - AC_DEFINE(USE_FIELD_5X52_INT128, 1, [Define this symbol to use the __int128 version for the 5x52 field implementation]) AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) ;; -gmp) - AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed]) - AC_DEFINE(USE_FIELD_GMP, 1, [Define this symbol to use the FIELD_GMP implementation]) - ;; 32bit) AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) ;; @@ -233,7 +257,7 @@ gmp) AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) ;; -none) +no) AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) @@ -258,7 +282,7 @@ esac if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK - if test x"$has_openssl_ec" == x"yes"; then + if test x"$has_openssl_ec" = x"yes"; then AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" SECP_TEST_LIBS="$CRYPTO_LIBS" @@ -272,7 +296,7 @@ if test x"$use_tests" = x"yes"; then fi fi -if test x"$set_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then +if test x"$set_bignum" = x"gmp"; then SECP_LIBS="$SECP_LIBS $GMP_LIBS" SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" fi @@ -281,9 +305,11 @@ if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi +AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) +AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) @@ -291,9 +317,8 @@ AC_SUBST(SECP_INCLUDES) AC_SUBST(SECP_LIBS) AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) -AM_CONDITIONAL([USE_ASM], [test x"$set_field" == x"64bit_asm"]) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) -AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = 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/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index dca7ca00e7..cfdae31eaf 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -77,42 +77,73 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( int pubkeylen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +/** A pointer to a function to deterministically generate a nonce. + * Returns: 1 if a nonce was succesfully 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. + */ +typedef int (*secp256k1_nonce_function_t)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + unsigned int attempt, + const void *data +); + +/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. */ +extern const secp256k1_nonce_function_t 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; + + /** Create an ECDSA signature. * Returns: 1: signature created - * 0: nonce invalid, try another one + * 0: the nonce generation function failed * In: msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid) - * nonce: pointer to a 32-byte nonce (cannot be NULL, generated with a cryptographic PRNG) + * 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 an array where the signature will be placed (cannot be NULL) * In/Out: siglen: pointer to an int with the length of sig, which will be updated * to contain the actual signature length (<=72). * Requires starting using SECP256K1_START_SIGN. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_sign( +int secp256k1_ecdsa_sign( const unsigned char *msg32, unsigned char *sig, int *siglen, const unsigned char *seckey, - const unsigned char *nonce -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + secp256k1_nonce_function_t noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Create a compact ECDSA signature (64 byte + recovery id). * Returns: 1: signature created - * 0: nonce invalid, try another one + * 0: the nonce generation function failed * In: msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid) - * nonce: pointer to a 32-byte nonce (cannot be NULL, generated with a cryptographic PRNG) + * 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) * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) * Requires starting using SECP256K1_START_SIGN. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_sign_compact( +int secp256k1_ecdsa_sign_compact( const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, - const unsigned char *nonce, + secp256k1_nonce_function_t noncefp, + const void *ndata, int *recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Recover an ECDSA public key from a compact signature. * Returns: 1: public key successfully recovered (which guarantees a correct signature). diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c index 66e71e1ac4..2276f00b9a 100644 --- a/src/secp256k1/src/bench_sign.c +++ b/src/secp256k1/src/bench_sign.c @@ -10,7 +10,6 @@ typedef struct { unsigned char msg[32]; - unsigned char nonce[32]; unsigned char key[32]; } bench_sign_t; @@ -18,7 +17,6 @@ static void bench_sign_setup(void* arg) { bench_sign_t *data = (bench_sign_t*)arg; for (int i = 0; i < 32; i++) data->msg[i] = i + 1; - for (int i = 0; i < 32; i++) data->nonce[i] = i + 33; for (int i = 0; i < 32; i++) data->key[i] = i + 65; } @@ -28,9 +26,8 @@ static void bench_sign(void* arg) { unsigned char sig[64]; for (int i=0; i<20000; i++) { int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, data->nonce, &recid)); + CHECK(secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, NULL, NULL, &recid)); for (int j = 0; j < 32; j++) { - data->nonce[j] = data->key[j]; /* Move former key to nonce */ data->msg[j] = sig[j]; /* Move former R to message. */ data->key[j] = sig[j + 32]; /* Move former S to key. */ } diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c index b123c4087d..a58ca84347 100644 --- a/src/secp256k1/src/bench_verify.c +++ b/src/secp256k1/src/bench_verify.c @@ -14,7 +14,6 @@ typedef struct { unsigned char msg[32]; unsigned char key[32]; - unsigned char nonce[32]; unsigned char sig[72]; int siglen; unsigned char pubkey[33]; @@ -42,9 +41,8 @@ int main(void) { for (int i = 0; i < 32; i++) data.msg[i] = 1 + i; for (int i = 0; i < 32; i++) data.key[i] = 33 + i; - for (int i = 0; i < 32; i++) data.nonce[i] = 65 + i; data.siglen = 72; - CHECK(secp256k1_ecdsa_sign(data.msg, data.sig, &data.siglen, data.key, data.nonce)); + secp256k1_ecdsa_sign(data.msg, data.sig, &data.siglen, data.key, NULL, NULL); data.pubkeylen = 33; CHECK(secp256k1_ec_pubkey_create(data.pubkey, &data.pubkeylen, data.key, 1)); diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index 8825d05fed..674650c1e9 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -109,25 +109,53 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_recompute(secp256k1_scalar_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) return 0; - int ret = 0; secp256k1_scalar_t sn, u1, u2; secp256k1_scalar_inverse_var(&sn, &sig->s); secp256k1_scalar_mul(&u1, &sn, message); secp256k1_scalar_mul(&u2, &sn, &sig->r); secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey); secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); - if (!secp256k1_gej_is_infinity(&pr)) { - secp256k1_fe_t xr; secp256k1_gej_get_x_var(&xr, &pr); - secp256k1_fe_normalize_var(&xr); - unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr); - secp256k1_scalar_set_b32(r2, xrb, NULL); - ret = 1; + if (secp256k1_gej_is_infinity(&pr)) { + return 0; + } + unsigned char c[32]; + secp256k1_scalar_get_b32(c, &sig->r); + secp256k1_fe_t xr; + secp256k1_fe_set_b32(&xr, c); + + // We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) + // in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), + // compute the remainder modulo n, and compare it to xr. However: + // + // xr == X(pr) mod n + // <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) + // [Since 2 * n > p, h can only be 0 or 1] + // <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) + // [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] + // <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) + // [Multiplying both sides of the equations by pr.z^2 mod p] + // <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) + // + // Thus, we can avoid the inversion, but we have to check both cases separately. + // secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + // xr.x == xr * xr.z^2 mod p, so the signature is valid. + return 1; + } + if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_consts->p_minus_order) >= 0) { + // xr + p >= n, so we can skip testing the second case. + return 0; + } + secp256k1_fe_add(&xr, &secp256k1_ecdsa_consts->order_as_fe); + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + // (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. + return 1; } - return ret; + return 0; } static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { @@ -159,13 +187,6 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256 return !secp256k1_gej_is_infinity(&qj); } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { - secp256k1_scalar_t r2; - int ret = 0; - ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_scalar_eq(&sig->r, &r2); - return ret; -} - static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { secp256k1_gej_t rp; secp256k1_ecmult_gen(&rp, nonce); @@ -177,6 +198,12 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_ secp256k1_fe_get_b32(b, &r.x); int overflow = 0; 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_gej_clear(&rp); + secp256k1_ge_clear(&r); + return 0; + } if (recid) *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); secp256k1_scalar_t n; diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 5a5b16ce14..48436316e1 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -73,7 +73,7 @@ static void secp256k1_ecmult_gen_start(void) { secp256k1_gej_double_var(&numsbase, &numsbase); if (j == 62) { /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ - secp256k1_gej_neg_var(&numsbase, &numsbase); + secp256k1_gej_neg(&numsbase, &numsbase); secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej); } } diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index 6536771046..345cfae733 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -70,8 +70,8 @@ static void secp256k1_ecmult_table_precomp_ge_var(secp256k1_ge_t *pre, const sec (neg)((r), &(pre)[(-(n)-1)/2]); \ } while(0) -#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg_var) -#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg_var) +#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg) +#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg) typedef struct { /* For accelerating the computation of a*P + b*G: */ diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h index 53aa29e13f..14e2b813c1 100644 --- a/src/secp256k1/src/field.h +++ b/src/secp256k1/src/field.h @@ -22,9 +22,7 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_FIELD_GMP) -#include "field_gmp.h" -#elif defined(USE_FIELD_10X26) +#if defined(USE_FIELD_10X26) #include "field_10x26.h" #elif defined(USE_FIELD_5X52) #include "field_5x52.h" @@ -50,9 +48,20 @@ static void secp256k1_fe_stop(void); /** Normalize a field element. */ static void secp256k1_fe_normalize(secp256k1_fe_t *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); + /** Normalize a field element, without constant-time guarantee. */ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r); +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *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); @@ -62,8 +71,8 @@ static int secp256k1_fe_is_zero(const secp256k1_fe_t *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); -/** Compare two field elements. Requires both inputs to be normalized */ -static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +/** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *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); diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h index d20229cda6..9ef60a807a 100644 --- a/src/secp256k1/src/field_10x26_impl.h +++ b/src/secp256k1/src/field_10x26_impl.h @@ -31,6 +31,7 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { r &= (d[8] <= 0x3FFFFFFUL * m); r &= (d[9] <= 0x03FFFFFUL * m); r &= (a->magnitude >= 0); + r &= (a->magnitude <= 32); if (a->normalized) { r &= (a->magnitude <= 1); if (r && (d[9] == 0x03FFFFFUL)) { @@ -103,6 +104,37 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } +static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + static void secp256k1_fe_normalize_var(secp256k1_fe_t *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]; @@ -159,6 +191,73 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0, z1; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0 = t0 & 0x3FFFFFFUL, z1 = z0 ^ 0x3D0UL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) + return 0; + + uint32_t t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8]; + t9 &= 0x03FFFFFUL; + t1 += (x << 6); + + t1 += (t0 >> 26); t0 = z0; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *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; @@ -196,18 +295,6 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif - const uint32_t *t = a->n, *u = b->n; - return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4]) - | (t[5]^u[5]) | (t[6]^u[6]) | (t[7]^u[7]) | (t[8]^u[8]) | (t[9]^u[9])) == 0; -} - static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { #ifdef VERIFY VERIFY_CHECK(a->normalized); diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h index 63176d6de4..4db9e6f5ff 100644 --- a/src/secp256k1/src/field_5x52_impl.h +++ b/src/secp256k1/src/field_5x52_impl.h @@ -16,12 +16,10 @@ #include "num.h" #include "field.h" -#if defined(USE_FIELD_5X52_ASM) +#if defined(USE_ASM_X86_64) #include "field_5x52_asm_impl.h" -#elif defined(USE_FIELD_5X52_INT128) -#include "field_5x52_int128_impl.h" #else -#error "Please select field_5x52 implementation" +#include "field_5x52_int128_impl.h" #endif /** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, @@ -45,6 +43,7 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); r &= (a->magnitude >= 0); + r &= (a->magnitude <= 2048); if (a->normalized) { r &= (a->magnitude <= 1); if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { @@ -102,6 +101,30 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } +static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; @@ -146,6 +169,60 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0 = t0 & 0xFFFFFFFFFFFFFULL, z1 = z0 ^ 0x1000003D0ULL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) + return 0; + + uint64_t t1 = r->n[1], t2 = r->n[2], t3 = r->n[3]; + t4 &= 0x0FFFFFFFFFFFFULL; + + t1 += (t0 >> 52); t0 = z0; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; @@ -183,17 +260,6 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif - const uint64_t *t = a->n, *u = b->n; - return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4])) == 0; -} - static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { #ifdef VERIFY VERIFY_CHECK(a->normalized); diff --git a/src/secp256k1/src/field_gmp.h b/src/secp256k1/src/field_gmp.h deleted file mode 100644 index b390fd9de8..0000000000 --- a/src/secp256k1/src/field_gmp.h +++ /dev/null @@ -1,18 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ - -#include <gmp.h> - -#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS) - -typedef struct { - mp_limb_t n[FIELD_LIMBS+1]; -} secp256k1_fe_t; - -#endif diff --git a/src/secp256k1/src/field_gmp_impl.h b/src/secp256k1/src/field_gmp_impl.h deleted file mode 100644 index 73a55c4f00..0000000000 --- a/src/secp256k1/src/field_gmp_impl.h +++ /dev/null @@ -1,184 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ - -#include <stdio.h> -#include <string.h> -#include "num.h" -#include "field.h" - -static mp_limb_t secp256k1_field_p[FIELD_LIMBS]; -static mp_limb_t secp256k1_field_pc[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS]; - -static void secp256k1_fe_inner_start(void) { - for (int i=0; i<(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; i++) - secp256k1_field_pc[i] = 0; - secp256k1_field_pc[0] += 0x3D1UL; - secp256k1_field_pc[32/GMP_NUMB_BITS] += (((mp_limb_t)1) << (32 % GMP_NUMB_BITS)); - for (int i=0; i<FIELD_LIMBS; i++) { - secp256k1_field_p[i] = 0; - } - mpn_sub(secp256k1_field_p, secp256k1_field_p, FIELD_LIMBS, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS); -} - -static void secp256k1_fe_inner_stop(void) { -} - -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { - if (r->n[FIELD_LIMBS] != 0) { -#if (GMP_NUMB_BITS >= 40) - mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * r->n[FIELD_LIMBS]); - mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * carry); -#else - mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * r->n[FIELD_LIMBS]) + - mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), r->n[FIELD_LIMBS] << (32 % GMP_NUMB_BITS)); - mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * carry); - mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), carry << (32%GMP_NUMB_BITS)); -#endif - r->n[FIELD_LIMBS] = 0; - } - if (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) >= 0) - mpn_sub(r->n, r->n, FIELD_LIMBS, secp256k1_field_p, FIELD_LIMBS); -} - -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { - secp256k1_fe_normalize(r); -} - -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { - r->n[0] = a; - for (int i=1; i<FIELD_LIMBS+1; i++) - r->n[i] = 0; -} - -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *r) { - for (int i=0; i<FIELD_LIMBS+1; i++) - r->n[i] = 0; -} - -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { - int ret = 1; - for (int i=0; i<FIELD_LIMBS+1; i++) - ret &= (a->n[i] == 0); - return ret; -} - -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { - return a->n[0] & 1; -} - -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - int ret = 1; - for (int i=0; i<FIELD_LIMBS+1; i++) - ret &= (a->n[i] == b->n[i]); - return ret; -} - -SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - for (int i=FIELD_LIMBS; i>=0; i--) { - if (a->n[i] > b->n[i]) return 1; - if (a->n[i] < b->n[i]) return -1; - } - return 0; -} - -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { - for (int i=0; i<FIELD_LIMBS+1; i++) - r->n[i] = 0; - for (int i=0; i<256; i++) { - int limb = i/GMP_NUMB_BITS; - int shift = i%GMP_NUMB_BITS; - r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift; - } - return (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) < 0); -} - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { - for (int i=0; i<32; i++) { - int c = 0; - for (int j=0; j<8; j++) { - int limb = (8*i+j)/GMP_NUMB_BITS; - int shift = (8*i+j)%GMP_NUMB_BITS; - c |= ((a->n[limb] >> shift) & 0x1) << j; - } - r[31-i] = c; - } -} - -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { - (void)m; - *r = *a; - secp256k1_fe_normalize(r); - for (int i=0; i<FIELD_LIMBS; i++) - r->n[i] = ~(r->n[i]); -#if (GMP_NUMB_BITS >= 33) - mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x1000003D0ULL); -#else - mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x3D0UL); - mpn_sub_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS)); -#endif -} - -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { - mpn_mul_1(r->n, r->n, FIELD_LIMBS+1, a); -} - -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - mpn_add(r->n, r->n, FIELD_LIMBS+1, a->n, FIELD_LIMBS+1); -} - -static void secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) { - /** <A1 A2 A3 A4> <B1 B2 B3 B4> - * B1 B2 B3 B4 - * + C * A1 A2 A3 A4 - * + A1 A2 A3 A4 - */ - -#if (GMP_NUMB_BITS >= 33) - mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x1000003D1ULL); -#else - mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x3D1UL) + - mpn_addmul_1(tmp+(32/GMP_NUMB_BITS), tmp+FIELD_LIMBS, FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS)); -#endif - mp_limb_t q[1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS]; - q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] = mpn_mul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o); -#if (GMP_NUMB_BITS <= 32) - mp_limb_t o2 = tmp[2*FIELD_LIMBS-(32/GMP_NUMB_BITS)] << (32%GMP_NUMB_BITS); - q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] += mpn_addmul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o2); -#endif - r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS); -} - -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { - VERIFY_CHECK(r != b); - secp256k1_fe_t ac = *a; - secp256k1_fe_t bc = *b; - secp256k1_fe_normalize(&ac); - secp256k1_fe_normalize(&bc); - mp_limb_t tmp[2*FIELD_LIMBS]; - mpn_mul_n(tmp, ac.n, bc.n, FIELD_LIMBS); - secp256k1_fe_reduce(r, tmp); -} - -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t ac = *a; - secp256k1_fe_normalize(&ac); - mp_limb_t tmp[2*FIELD_LIMBS]; - mpn_sqr(tmp, ac.n, FIELD_LIMBS); - secp256k1_fe_reduce(r, tmp); -} - -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { - mp_limb_t mask0 = flag + ~((mp_limb_t)0), mask1 = ~mask0; - for (int i = 0; i <= FIELD_LIMBS; i++) { - r->n[i] = (r->n[i] & mask0) | (a->n[i] & mask1); - } -} - -#endif diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index 24d3104ed1..4e2c24aa15 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/src/field_impl.h @@ -13,9 +13,7 @@ #include "util.h" -#if defined(USE_FIELD_GMP) -#include "field_gmp_impl.h" -#elif defined(USE_FIELD_10X26) +#if defined(USE_FIELD_10X26) #include "field_10x26_impl.h" #elif defined(USE_FIELD_5X52) #include "field_5x52_impl.h" @@ -66,6 +64,13 @@ static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) { return secp256k1_fe_set_b32(r, tmp); } +SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { + secp256k1_fe_t 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) { /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in @@ -130,10 +135,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - secp256k1_fe_negate(&t1, &t1, 1); - secp256k1_fe_add(&t1, a); - secp256k1_fe_normalize_var(&t1); - return secp256k1_fe_is_zero(&t1); + return secp256k1_fe_equal_var(&t1, a); } static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h index ecfebcdc0c..6dea6bb5ac 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -60,7 +60,6 @@ static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a); static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a); static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a); -static void secp256k1_ge_neg_var(secp256k1_ge_t *r, const secp256k1_ge_t *a); /** Get a hex representation of a point. *rlen will be overwritten with the real length. */ static void secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a); @@ -81,11 +80,11 @@ static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, co /** 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); -/** Get the X coordinate of a group element (jacobian). */ -static void secp256k1_gej_get_x_var(secp256k1_fe_t *r, const secp256k1_gej_t *a); +/** Compare the X coordinate of a group element (jacobian). */ +static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a); /** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void secp256k1_gej_neg_var(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a); /** Check whether a group element is the point at infinity. */ static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a); diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index 1ab5d5fe7b..fef06df289 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -29,13 +29,7 @@ static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a) { static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) { *r = *a; - secp256k1_fe_normalize(&r->y); - secp256k1_fe_negate(&r->y, &r->y, 1); -} - -static void secp256k1_ge_neg_var(secp256k1_ge_t *r, const secp256k1_ge_t *a) { - *r = *a; - secp256k1_fe_normalize_var(&r->y); + secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); } @@ -163,17 +157,19 @@ static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) { secp256k1_fe_set_int(&r->z, 1); } -static void secp256k1_gej_get_x_var(secp256k1_fe_t *r, const secp256k1_gej_t *a) { - secp256k1_fe_t zi2; secp256k1_fe_inv_var(&zi2, &a->z); secp256k1_fe_sqr(&zi2, &zi2); - secp256k1_fe_mul(r, &a->x, &zi2); +static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) { + VERIFY_CHECK(!a->infinity); + secp256k1_fe_t r; secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); + secp256k1_fe_t r2 = a->x; secp256k1_fe_normalize_weak(&r2); + return secp256k1_fe_equal_var(&r, &r2); } -static void secp256k1_gej_neg_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { +static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; r->z = a->z; - secp256k1_fe_normalize_var(&r->y); + secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); } @@ -195,9 +191,8 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); secp256k1_fe_mul_int(&z6, 7); secp256k1_fe_add(&x3, &z6); - secp256k1_fe_normalize_var(&y2); - secp256k1_fe_normalize_var(&x3); - return secp256k1_fe_equal(&y2, &x3); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); } static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { @@ -208,9 +203,8 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7); secp256k1_fe_add(&x3, &c); - secp256k1_fe_normalize_var(&y2); - secp256k1_fe_normalize_var(&x3); - return secp256k1_fe_equal(&y2, &x3); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); } static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { @@ -261,20 +255,16 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12); secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_normalize_var(&u1); - secp256k1_fe_normalize_var(&u2); - if (secp256k1_fe_equal(&u1, &u2)) { - secp256k1_fe_normalize_var(&s1); - secp256k1_fe_normalize_var(&s2); - if (secp256k1_fe_equal(&s1, &s2)) { + secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { secp256k1_gej_double_var(r, a); } else { r->infinity = 1; } return; } - secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i); secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); @@ -300,23 +290,20 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * } r->infinity = 0; secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z); - secp256k1_fe_t u1 = a->x; + secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize_weak(&u1); secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12); - secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize_var(&s1); + secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize_weak(&s1); secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_normalize_var(&u1); - secp256k1_fe_normalize_var(&u2); - if (secp256k1_fe_equal(&u1, &u2)) { - secp256k1_fe_normalize_var(&s2); - if (secp256k1_fe_equal(&s1, &s2)) { + secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { secp256k1_gej_double_var(r, a); } else { r->infinity = 1; } return; } - secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i); secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); @@ -355,9 +342,9 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c */ secp256k1_fe_t zz; secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */ secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ secp256k1_fe_t z = a->z; /* z = Z = Z1*Z2 (8) */ @@ -371,8 +358,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */ secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */ secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */ - secp256k1_fe_normalize(&r->z); - int infinity = secp256k1_fe_is_zero(&r->z) * (1 - a->infinity); + int 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_negate(&q, &q, 1); /* q = -Q (2) */ @@ -384,7 +370,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */ secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */ secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */ - secp256k1_fe_normalize(&r->y); + secp256k1_fe_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) */ diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h new file mode 100644 index 0000000000..d1e65b968a --- /dev/null +++ b/src/secp256k1/src/hash.h @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_HASH_ +#define _SECP256K1_HASH_ + +#include <stdlib.h> +#include <stdint.h> + +typedef struct { + uint32_t s[32]; + unsigned char buf[64]; + size_t bytes; +} secp256k1_sha256_t; + +static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); +static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); + +typedef struct { + secp256k1_sha256_t inner, outer; +} secp256k1_hmac_sha256_t; + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + 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); +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); + +#endif diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h new file mode 100644 index 0000000000..f35c5f7a82 --- /dev/null +++ b/src/secp256k1/src/hash_impl.h @@ -0,0 +1,291 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_HASH_IMPL_H_ +#define _SECP256K1_HASH_IMPL_H_ + +#include "hash.h" + +#include <stdlib.h> +#include <stdint.h> + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +#define ReadBE32(p) (((uint32_t)((p)[0])) << 24 | ((uint32_t)((p)[1])) << 16 | ((uint32_t)((p)[2])) << 8 | ((uint32_t)((p)[3]))) +#define WriteBE32(p, v) do { (p)[0] = (v) >> 24; (p)[1] = (v) >> 16; (p)[2] = (v) >> 8; (p)[3] = (v); } while(0) + +static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { + hash->s[0] = 0x6a09e667ul; + hash->s[1] = 0xbb67ae85ul; + hash->s[2] = 0x3c6ef372ul; + hash->s[3] = 0xa54ff53aul; + hash->s[4] = 0x510e527ful; + hash->s[5] = 0x9b05688cul; + hash->s[6] = 0x1f83d9abul; + hash->s[7] = 0x5be0cd19ul; + hash->bytes = 0; +} + +/** Perform one SHA-256 transformation, processing a 64-byte chunk. */ +static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* chunk) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0)); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4)); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8)); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12)); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16)); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20)); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24)); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28)); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32)); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36)); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40)); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44)); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48)); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = ReadBE32(chunk + 52)); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56)); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60)); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { + const unsigned char* end = data + len; + size_t bufsize = hash->bytes % 64; + if (bufsize && bufsize + len >= 64) { + // Fill the buffer, and process it. + memcpy(hash->buf + bufsize, data, 64 - bufsize); + hash->bytes += 64 - bufsize; + data += 64 - bufsize; + secp256k1_sha256_transform(hash->s, hash->buf); + bufsize = 0; + } + while (end >= data + 64) { + // Process full chunks directly from the source. + secp256k1_sha256_transform(hash->s, data); + hash->bytes += 64; + data += 64; + } + if (end > data) { + // Fill the buffer with what remains. + memcpy(hash->buf + bufsize, data, end - data); + hash->bytes += end - data; + } +} + +static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { + static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char sizedesc[8]; + WriteBE32(sizedesc, hash->bytes >> 29); + WriteBE32(sizedesc + 4, hash->bytes << 3); + secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_sha256_write(hash, sizedesc, 8); + WriteBE32(out32, hash->s[0]); + hash->s[0] = 0; + WriteBE32(out32 + 4, hash->s[1]); + hash->s[1] = 0; + WriteBE32(out32 + 8, hash->s[2]); + hash->s[2] = 0; + WriteBE32(out32 + 12, hash->s[3]); + hash->s[3] = 0; + WriteBE32(out32 + 16, hash->s[4]); + hash->s[4] = 0; + WriteBE32(out32 + 20, hash->s[5]); + hash->s[5] = 0; + WriteBE32(out32 + 24, hash->s[6]); + hash->s[6] = 0; + WriteBE32(out32 + 28, hash->s[7]); + hash->s[7] = 0; +} + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { + unsigned char rkey[64]; + if (keylen <= 64) { + memcpy(rkey, key, keylen); + memset(rkey + keylen, 0, 64 - keylen); + } else { + secp256k1_sha256_t sha256; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, key, keylen); + secp256k1_sha256_finalize(&sha256, rkey); + memset(rkey + 32, 0, 32); + } + + secp256k1_sha256_initialize(&hash->outer); + for (int n = 0; n < 64; n++) + rkey[n] ^= 0x5c; + secp256k1_sha256_write(&hash->outer, rkey, 64); + + secp256k1_sha256_initialize(&hash->inner); + for (int n = 0; n < 64; n++) + rkey[n] ^= 0x5c ^ 0x36; + secp256k1_sha256_write(&hash->inner, rkey, 64); + memset(rkey, 0, 64); +} + +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(&hash->inner, data, size); +} + +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { + unsigned char temp[32]; + secp256k1_sha256_finalize(&hash->inner, temp); + secp256k1_sha256_write(&hash->outer, temp, 32); + memset(temp, 0, 32); + secp256k1_sha256_finalize(&hash->outer, out32); +} + + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen) { + static const unsigned char zero[1] = {0x00}; + static const unsigned char one[1] = {0x01}; + + memset(rng->v, 0x01, 32); + memset(rng->k, 0x00, 32); + + secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_write(&hmac, msg, msglen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, one, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_write(&hmac, msg, msglen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + rng->retry = 0; +} + +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + } + + while (outlen > 0) { + secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + int now = outlen; + if (now > 32) { + now = 32; + } + memcpy(out, rng->v, now); + out += now; + outlen -= now; + } + + rng->retry = 1; +} + +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { + memset(rng->k, 0, 32); + memset(rng->v, 0, 32); + rng->retry = 0; +} + + +#undef Round +#undef sigma0 +#undef sigma1 +#undef Sigma0 +#undef Sigma1 +#undef Ch +#undef Maj +#undef ReadBE32 +#undef WriteBE32 + +#endif diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index 0328db88fc..58bcd8d009 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -17,6 +17,7 @@ #include "ecmult_gen_impl.h" #include "ecdsa_impl.h" #include "eckey_impl.h" +#include "hash_impl.h" void secp256k1_start(unsigned int flags) { secp256k1_fe_start(); @@ -69,26 +70,54 @@ end: return ret; } -int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) { +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { + (void)data; + secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32); + for (unsigned int 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_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; + +int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(signature != NULL); DEBUG_CHECK(signaturelen != NULL); DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(nonce != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } secp256k1_scalar_t sec, non, msg; secp256k1_scalar_set_b32(&sec, seckey, NULL); - int overflow = 0; - secp256k1_scalar_set_b32(&non, nonce, &overflow); secp256k1_scalar_set_b32(&msg, msg32, NULL); - int ret = !secp256k1_scalar_is_zero(&non) && !overflow; + int overflow = 0; + int ret = 0; + unsigned int count = 0; secp256k1_ecdsa_sig_t sig; - if (ret) { - ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, 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(&sig, &sec, &msg, &non, NULL)) { + break; + } + } + count++; } if (ret) { - secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); + ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); } secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); @@ -96,22 +125,36 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i return ret; } -int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) { +int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(sig64 != NULL); DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(nonce != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } secp256k1_scalar_t sec, non, msg; secp256k1_scalar_set_b32(&sec, seckey, NULL); - int overflow = 0; - secp256k1_scalar_set_b32(&non, nonce, &overflow); secp256k1_scalar_set_b32(&msg, msg32, NULL); - int ret = !secp256k1_scalar_is_zero(&non) && !overflow; + int overflow = 0; + int ret = 0; + unsigned int count = 0; secp256k1_ecdsa_sig_t sig; - if (ret) { - ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid); + 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(&sig, &sec, &msg, &non, recid)) { + break; + } + } + count++; } if (ret) { secp256k1_scalar_get_b32(sig64, &sig.r); diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 7ebb19ff99..cff32f1d06 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -36,12 +36,19 @@ void random_field_element_test(secp256k1_fe_t *fe) { } void random_field_element_magnitude(secp256k1_fe_t *fe) { + int n = secp256k1_rand32() % 9; secp256k1_fe_normalize(fe); - int n = secp256k1_rand32() % 4; - for (int i = 0; i < n; i++) { - secp256k1_fe_negate(fe, fe, 1 + 2*i); - secp256k1_fe_negate(fe, fe, 2 + 2*i); + if (n == 0) { + return; } + secp256k1_fe_t zero; + secp256k1_fe_clear(&zero); + 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 } void random_group_element_test(secp256k1_ge_t *ge) { @@ -91,6 +98,121 @@ void random_scalar_order(secp256k1_scalar_t *num) { } while(1); } +/***** HASH TESTS *****/ + +void run_sha256_tests(void) { + static const char *inputs[8] = { + "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "For this sample, this 63-byte string will be used as input data", + "This is exactly 64 bytes long, not counting the terminating byte" + }; + static const unsigned char outputs[8][32] = { + {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, + {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, + {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, + {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, + {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, + {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} + }; + for (int i = 0; i < 8; i++) { + secp256k1_sha256_t hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + unsigned char out[32]; + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + secp256k1_sha256_initialize(&hasher); + int split = secp256k1_rand32() % strlen(inputs[i]); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_hmac_sha256_tests(void) { + static const char *keys[6] = { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "\x4a\x65\x66\x65", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + }; + static const char *inputs[6] = { + "\x48\x69\x20\x54\x68\x65\x72\x65", + "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" + }; + static const unsigned char outputs[6][32] = { + {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, + {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, + {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, + {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, + {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, + {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} + }; + for (int i = 0; i < 6; i++) { + secp256k1_hmac_sha256_t hasher; + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + unsigned char out[32]; + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + int split = secp256k1_rand32() % strlen(inputs[i]); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_rfc6979_hmac_sha256_tests(void) { + static const unsigned char key1[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 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 out2[3][32] = { + {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, + {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, + {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} + }; + + secp256k1_rfc6979_hmac_sha256_t rng; + unsigned char out[32]; + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32); + for (int 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); + for (int i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out2[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); +} + /***** NUM TESTS *****/ #ifndef USE_NUM_NONE @@ -494,9 +616,9 @@ void random_fe_non_square(secp256k1_fe_t *ns) { } int check_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t an = *a; secp256k1_fe_normalize(&an); + secp256k1_fe_t an = *a; secp256k1_fe_normalize_weak(&an); secp256k1_fe_t bn = *b; secp256k1_fe_normalize_var(&bn); - return secp256k1_fe_equal(&an, &bn); + return secp256k1_fe_equal_var(&an, &bn); } int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) { @@ -523,16 +645,16 @@ void run_field_misc(void) { random_fe_non_zero(&y); /* Test the fe equality and comparison operations. */ CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); - CHECK(secp256k1_fe_equal(&x, &x)); + CHECK(secp256k1_fe_equal_var(&x, &x)); z = x; secp256k1_fe_add(&z,&y); secp256k1_fe_normalize(&z); /* Test the conditional move. */ secp256k1_fe_cmov(&z, &x, 0); - CHECK(secp256k1_fe_equal(&x, &z) == 0); + CHECK(secp256k1_fe_equal_var(&x, &z) == 0); CHECK(secp256k1_fe_cmp_var(&x, &z) != 0); secp256k1_fe_cmov(&y, &x, 1); - CHECK(secp256k1_fe_equal(&x, &y)); + CHECK(secp256k1_fe_equal_var(&x, &y)); /* Test that mul_int, mul, and add agree. */ secp256k1_fe_add(&y, &x); secp256k1_fe_add(&y, &x); @@ -656,108 +778,148 @@ void run_sqrt(void) { /***** GROUP TESTS *****/ -int ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { - if (a->infinity && b->infinity) - return 1; - return check_fe_equal(&a->x, &b->x) && check_fe_equal(&a->y, &b->y); +void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *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)); } void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { - secp256k1_ge_t bb; - secp256k1_gej_t bj = *b; - secp256k1_ge_set_gej_var(&bb, &bj); - CHECK(ge_equals_ge(a, &bb)); -} - -void gej_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { - secp256k1_ge_t aa, bb; - secp256k1_gej_t aj = *a, bj = *b; - secp256k1_ge_set_gej_var(&aa, &aj); - secp256k1_ge_set_gej_var(&bb, &bj); - CHECK(ge_equals_ge(&aa, &bb)); + CHECK(a->infinity == b->infinity); + if (a->infinity) + return; + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_t z2s; + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_t u1, u2, s1, s2; + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); } void test_ge(void) { - char ca[135]; - char cb[68]; - int rlen; - secp256k1_ge_t a, b, i, n; - random_group_element_test(&a); - random_group_element_test(&b); - rlen = sizeof(ca); - secp256k1_ge_get_hex(ca,&rlen,&a); - CHECK(rlen > 4 && rlen <= (int)sizeof(ca)); - rlen = sizeof(cb); - secp256k1_ge_get_hex(cb,&rlen,&b); /* Intentionally undersized buffer. */ - n = a; - secp256k1_fe_normalize(&a.y); - secp256k1_fe_negate(&n.y, &a.y, 1); - secp256k1_ge_set_infinity(&i); - random_field_element_magnitude(&a.x); - random_field_element_magnitude(&a.y); - random_field_element_magnitude(&b.x); - random_field_element_magnitude(&b.y); - random_field_element_magnitude(&n.x); - random_field_element_magnitude(&n.y); - - secp256k1_gej_t aj, bj, ij, nj; - random_group_element_jacobian_test(&aj, &a); - random_group_element_jacobian_test(&bj, &b); - secp256k1_gej_set_infinity(&ij); - random_group_element_jacobian_test(&nj, &n); - random_field_element_magnitude(&aj.x); - random_field_element_magnitude(&aj.y); - random_field_element_magnitude(&aj.z); - random_field_element_magnitude(&bj.x); - random_field_element_magnitude(&bj.y); - random_field_element_magnitude(&bj.z); - random_field_element_magnitude(&nj.x); - random_field_element_magnitude(&nj.y); - random_field_element_magnitude(&nj.z); - - /* gej + gej adds */ - secp256k1_gej_t aaj; secp256k1_gej_add_var(&aaj, &aj, &aj); - secp256k1_gej_t abj; secp256k1_gej_add_var(&abj, &aj, &bj); - secp256k1_gej_t aij; secp256k1_gej_add_var(&aij, &aj, &ij); - secp256k1_gej_t anj; secp256k1_gej_add_var(&anj, &aj, &nj); - secp256k1_gej_t iaj; secp256k1_gej_add_var(&iaj, &ij, &aj); - secp256k1_gej_t iij; secp256k1_gej_add_var(&iij, &ij, &ij); - - /* gej + ge adds */ - secp256k1_gej_t aa; secp256k1_gej_add_ge_var(&aa, &aj, &a); - secp256k1_gej_t ab; secp256k1_gej_add_ge_var(&ab, &aj, &b); - secp256k1_gej_t ai; secp256k1_gej_add_ge_var(&ai, &aj, &i); - secp256k1_gej_t an; secp256k1_gej_add_ge_var(&an, &aj, &n); - secp256k1_gej_t ia; secp256k1_gej_add_ge_var(&ia, &ij, &a); - secp256k1_gej_t ii; secp256k1_gej_add_ge_var(&ii, &ij, &i); - - /* const gej + ge adds */ - secp256k1_gej_t aac; secp256k1_gej_add_ge(&aac, &aj, &a); - secp256k1_gej_t abc; secp256k1_gej_add_ge(&abc, &aj, &b); - secp256k1_gej_t anc; secp256k1_gej_add_ge(&anc, &aj, &n); - secp256k1_gej_t iac; secp256k1_gej_add_ge(&iac, &ij, &a); - - CHECK(secp256k1_gej_is_infinity(&an)); - CHECK(secp256k1_gej_is_infinity(&anj)); - CHECK(secp256k1_gej_is_infinity(&anc)); - gej_equals_gej(&aa, &aaj); - gej_equals_gej(&aa, &aac); - gej_equals_gej(&ab, &abj); - gej_equals_gej(&ab, &abc); - gej_equals_gej(&an, &anj); - gej_equals_gej(&an, &anc); - gej_equals_gej(&ia, &iaj); - gej_equals_gej(&ai, &aij); - gej_equals_gej(&ii, &iij); - ge_equals_gej(&a, &ai); - ge_equals_gej(&a, &ai); - ge_equals_gej(&a, &iaj); - ge_equals_gej(&a, &iaj); - ge_equals_gej(&a, &iac); + int runs = 4; + /* 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. + */ + secp256k1_ge_t *ge = malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); + secp256k1_gej_t *gej = malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); + secp256k1_gej_set_infinity(&gej[0]); + secp256k1_ge_clear(&ge[0]); + secp256k1_ge_set_gej_var(&ge[0], &gej[0]); + for (int i = 0; i < runs; i++) { + secp256k1_ge_t g; + random_group_element_test(&g); + ge[1 + 4 * i] = g; + ge[2 + 4 * i] = g; + secp256k1_ge_neg(&ge[3 + 4 * i], &g); + secp256k1_ge_neg(&ge[4 + 4 * i], &g); + secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + for (int j = 0; j < 4; j++) { + random_field_element_magnitude(&ge[1 + j + 4 * i].x); + random_field_element_magnitude(&ge[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].x); + random_field_element_magnitude(&gej[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].z); + } + } + + for (int i1 = 0; i1 < 1 + 4 * runs; i1++) { + for (int 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_ge_set_gej_var(&ref, &refj); + + /* Test gej + ge (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + + /* Test gej + ge (const). */ + if (i2 != 0) { + /* secp256k1_gej_add_ge does not support its second argument being infinity. */ + secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test doubling (var). */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i1]); + ge_equals_gej(&ref, &resj); + secp256k1_gej_double_var(&resj, &gej[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test adding opposites. */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { + CHECK(secp256k1_ge_is_infinity(&ref)); + } + + /* Test adding infinity. */ + if (i1 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i1])); + CHECK(secp256k1_gej_is_infinity(&gej[i1])); + ge_equals_gej(&ref, &gej[i2]); + } + if (i2 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i2])); + CHECK(secp256k1_gej_is_infinity(&gej[i2])); + ge_equals_gej(&ref, &gej[i1]); + } + } + } + + /* Test adding all points together in random order equals infinity. */ + { + secp256k1_gej_t *gej_shuffled = malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); + for (int i = 0; i < 4 * runs + 1; i++) { + gej_shuffled[i] = gej[i]; + } + for (int i = 0; i < 4 * runs + 1; i++) { + int swap = i + secp256k1_rand32() % (4 * runs + 1 - i); + if (swap != i) { + secp256k1_gej_t t = gej_shuffled[i]; + gej_shuffled[i] = gej_shuffled[swap]; + gej_shuffled[swap] = t; + } + } + secp256k1_gej_t sum; + secp256k1_gej_set_infinity(&sum); + for (int i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i]); + } + CHECK(secp256k1_gej_is_infinity(&sum)); + free(gej_shuffled); + } + + /* Test batch gej -> ge conversion. */ + { + secp256k1_ge_t *ge_set_all = malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); + secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej); + for (int i = 0; i < 4 * runs + 1; i++) { + ge_equals_gej(&ge_set_all[i], &gej[i]); + } + free(ge_set_all); + } + + free(ge); + free(gej); } void run_ge(void) { - for (int i = 0; i < 2000*count; i++) { + for (int i = 0; i < count * 32; i++) { test_ge(); } } @@ -949,6 +1111,44 @@ 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) { + (void)msg32; + (void)key32; + 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) { + /* 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); +} + +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { + /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ + if (counter < 3) { + memset(nonce32, counter==0 ? 0 : 255, 32); + if (counter == 2) nonce32[31]--; + return 1; + } + if (counter < 5) { + static const unsigned char order[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + memcpy(nonce32, order, 32); + if (counter == 4) nonce32[31]++; + return 1; + } + /* Retry rate of 6979 is negligible esp. as we only call this in determinstic 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); +} + void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; @@ -1006,13 +1206,7 @@ void test_ecdsa_end_to_end(void) { /* Sign. */ unsigned char signature[72]; int signaturelen = 72; - while(1) { - unsigned char rnd[32]; - secp256k1_rand256_test(rnd); - if (secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, rnd) == 1) { - break; - } - } + CHECK(secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, NULL, NULL) == 1); /* Verify. */ CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) == 1); /* Destroy signature and verify again. */ @@ -1021,13 +1215,7 @@ void test_ecdsa_end_to_end(void) { /* Compact sign. */ unsigned char csignature[64]; int recid = 0; - while(1) { - unsigned char rnd[32]; - secp256k1_rand256_test(rnd); - if (secp256k1_ecdsa_sign_compact(message, csignature, privkey, rnd, &recid) == 1) { - break; - } - } + CHECK(secp256k1_ecdsa_sign_compact(message, csignature, privkey, NULL, NULL, &recid) == 1); /* Recover. */ unsigned char recpubkey[65]; int recpubkeylen = 0; CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); @@ -1077,7 +1265,7 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); CHECK(size == 65); CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); - CHECK(ge_equals_ge(&elem,&elem2)); + ge_equals_ge(&elem,&elem2); /* Check that the X9.62 hybrid type is checked. */ in[0] = (r & 1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); @@ -1086,7 +1274,7 @@ void test_random_pubkeys(void) { else CHECK(!res); } if (res) { - CHECK(ge_equals_ge(&elem,&elem2)); + ge_equals_ge(&elem,&elem2); CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); CHECK(memcmp(&in[1], &out[1], 64) == 0); } @@ -1280,6 +1468,12 @@ void test_ecdsa_edge_cases(void) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }; + static const unsigned char nonce2[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; const unsigned char key[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1294,10 +1488,74 @@ void test_ecdsa_edge_cases(void) { }; unsigned char sig[72]; int siglen = 72; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; siglen = 72; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce) == 1); + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); + siglen = 10; + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); + } + + /* Nonce function corner cases. */ + { + unsigned char key[32]; + unsigned char msg[32]; + unsigned char sig[72]; + memset(key, 0, 32); + memset(msg, 0, 32); + key[31] = 1; + msg[31] = 1; + int siglen = 72; + int recid; + /* Nonce function failure results in signature failure. */ + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_fail, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_fail, NULL, &recid) == 0); + /* The retry loop successfully makes its way to the first good value. */ + unsigned char sig2[72]; + int siglen2 = 72; + siglen = 72; + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_retry, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, nonce_function_rfc6979, NULL) == 1); + CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); + int recid2; + CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_retry, NULL, &recid) == 1); + CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, nonce_function_rfc6979, NULL, &recid2) == 1); + CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + /* The default nonce function is determinstic. */ + siglen = 72; + siglen2 = 72; + CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1); + CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); + CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, NULL, NULL, &recid) == 1); + CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, NULL, NULL, &recid2) == 1); + CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + /* The default nonce function changes output with different messages. */ + secp256k1_ecdsa_sig_t s[512]; + for(int i=0; i<256; i++) { + siglen2 = 72; + msg[0] = i; + CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + for (int j=0; j<i; j++) { + CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(int i=256; i<512; i++) { + siglen2 = 72; + key[0] = i - 256; + CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + for (int j=0; j<i; j++) { + CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + } + } + key[0] = 0; } /* Privkey export where pubkey is the point at infinity. */ @@ -1405,6 +1663,10 @@ int main(int argc, char **argv) { secp256k1_scalar_start(); secp256k1_ecdsa_start(); + run_sha256_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); + #ifndef USE_NUM_NONE /* num tests */ run_num_smalltests(); diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index bed63991e6..da07b8c7a6 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) walletdb.WriteAccountingEntry(ae); wtx.mapValue["comment"] = "z"; - pwalletMain->AddToWallet(wtx); + pwalletMain->AddToWallet(wtx, false, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[0]->nTimeReceived = (unsigned int)1333333335; vpwtx[0]->nOrderPos = -1; @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) --tx.nLockTime; // Just to change the hash :) *static_cast<CTransaction*>(&wtx) = CTransaction(tx); } - pwalletMain->AddToWallet(wtx); + pwalletMain->AddToWallet(wtx, false, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[1]->nTimeReceived = (unsigned int)1333333336; @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) --tx.nLockTime; // Just to change the hash :) *static_cast<CTransaction*>(&wtx) = CTransaction(tx); } - pwalletMain->AddToWallet(wtx); + pwalletMain->AddToWallet(wtx, false, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nOrderPos = -1; diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 47bfd710cd..d5e595cd8a 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "crypto/rfc6979_hmac_sha256.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" @@ -248,38 +247,4 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) { "b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"); } -void TestRFC6979(const std::string& hexkey, const std::string& hexmsg, const std::vector<std::string>& hexout) -{ - std::vector<unsigned char> key = ParseHex(hexkey); - std::vector<unsigned char> msg = ParseHex(hexmsg); - RFC6979_HMAC_SHA256 rng(&key[0], key.size(), &msg[0], msg.size()); - - for (unsigned int i = 0; i < hexout.size(); i++) { - std::vector<unsigned char> out = ParseHex(hexout[i]); - std::vector<unsigned char> gen; - gen.resize(out.size()); - rng.Generate(&gen[0], gen.size()); - BOOST_CHECK(out == gen); - } -} - -BOOST_AUTO_TEST_CASE(rfc6979_hmac_sha256) -{ - TestRFC6979( - "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f00", - "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", - boost::assign::list_of - ("4fe29525b2086809159acdf0506efb86b0ec932c7ba44256ab321e421e67e9fb") - ("2bf0fff1d3c378a22dc5de1d856522325c65b504491a0cbd01cb8f3aa67ffd4a") - ("f528b410cb541f77000d7afb6c5b53c5c471eab43e466d9ac5190c39c82fd82e")); - - TestRFC6979( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - boost::assign::list_of - ("9c236c165b82ae0cd590659e100b6bab3036e7ba8b06749baf6981e16f1a2b95") - ("df471061625bc0ea14b682feee2c9c02f235da04204c1d62a1536c6e17aed7a9") - ("7597887cbd76321f32e30440679a22cf7f8d9d2eac390e581fea091ce202ba94")); -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 44e0dca8be..9a8fe1ee88 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -504,7 +504,7 @@ "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded." ], [ - "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0", + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1", "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", "STRICTENC", "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid." @@ -667,6 +667,18 @@ "SIGPUSHONLY", "P2SH(P2PK) with non-push scriptSig" ], +[ + "11 0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "CLEANSTACK,P2SH", + "P2PK with unnecessary input" +], +[ + "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "CLEANSTACK,P2SH", + "P2SH with unnecessary input" +], ["The End"] ] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index a1b7b119ef..a187401cd4 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -662,6 +662,11 @@ ["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", ""], ["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", ""], +["While not really correctly DER encoded, the empty signature is allowed by"], +["STRICTENC to provide a compact way to provide a delibrately invalid signature."], +["0", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "STRICTENC"], +["0 0", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "STRICTENC"], + ["CHECKMULTISIG evaluation order tests. CHECKMULTISIG evaluates signatures and"], ["pubkeys in a specific order, and will exit early if the number of signatures"], ["left to check is greater than the number of keys left. As STRICTENC fails the"], @@ -816,6 +821,24 @@ "SIGPUSHONLY", "2-of-2 with two identical keys and sigs pushed" ], +[ + "11 0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "P2SH", + "P2PK with unnecessary input but no CLEANSTACK" +], +[ + "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "P2SH", + "P2SH with unnecessary input but no CLEANSTACK" +], +[ + "0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "CLEANSTACK,P2SH", + "P2SH with CLEANSTACK" +], ["The End"] ] diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 69d8522188..9501169943 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -116,10 +116,6 @@ BOOST_AUTO_TEST_CASE(multisig_verify) } } s.clear(); - s << OP_0 << OP_0; - BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err)); - BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); - s.clear(); s << OP_0 << OP_1; BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp new file mode 100644 index 0000000000..464a8fbb8c --- /dev/null +++ b/src/test/sanity_tests.cpp @@ -0,0 +1,18 @@ +// Copyright (c) 2012-2013 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "compat/sanity.h" +#include "key.h" + +#include <boost/test/unit_test.hpp> +BOOST_AUTO_TEST_SUITE(sanity_tests) + +BOOST_AUTO_TEST_CASE(basic_sanity) +{ + BOOST_CHECK_MESSAGE(glibc_sanity_test() == true, "libc sanity test"); + BOOST_CHECK_MESSAGE(glibcxx_sanity_test() == true, "stdlib sanity test"); + BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "openssl ECC test"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 9a7f40820a..4db8942fa1 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -483,6 +483,22 @@ BOOST_AUTO_TEST_CASE(script_build) "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY ).Num(0).PushSig(keys.key1).PushSig(keys.key1)); + good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH + ).Num(11).PushSig(keys.key0)); + bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH + ).Num(11).PushSig(keys.key0)); + good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true + ).Num(11).PushSig(keys.key0).PushRedeem()); + bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true + ).Num(11).PushSig(keys.key0).PushRedeem()); + good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem()); + std::set<std::string> tests_good; std::set<std::string> tests_bad; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index bc32d504ec..96134cd72e 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -37,7 +37,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY) (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA) (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) - (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS); + (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) + (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK); unsigned int ParseScriptFlags(string strFlags) { diff --git a/src/wallet.cpp b/src/wallet.cpp index 6c5af3bdc7..1fe0552109 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -555,7 +555,7 @@ void CWallet::MarkDirty() } } -bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) +bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb) { uint256 hash = wtxIn.GetHash(); @@ -576,7 +576,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) if (fInsertedNew) { wtx.nTimeReceived = GetAdjustedTime(); - wtx.nOrderPos = IncOrderPosNext(); + wtx.nOrderPos = IncOrderPosNext(pwalletdb); wtx.nTimeSmart = wtx.nTimeReceived; if (!wtxIn.hashBlock.IsNull()) @@ -653,7 +653,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) // Write to disk if (fInsertedNew || fUpdated) - if (!wtx.WriteToDisk()) + if (!wtx.WriteToDisk(pwalletdb)) return false; // Break debit/credit balance caches: @@ -689,10 +689,16 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl if (fExisted || IsMine(tx) || IsFromMe(tx)) { CWalletTx wtx(this,tx); + // Get merkle branch if transaction was found in a block if (pblock) wtx.SetMerkleBranch(*pblock); - return AddToWallet(wtx); + + // Do not flush the wallet here for performance reasons + // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism + CWalletDB walletdb(strWalletFile, "r+", false); + + return AddToWallet(wtx, false, &walletdb); } } return false; @@ -916,9 +922,9 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, } -bool CWalletTx::WriteToDisk() +bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb) { - return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); + return pwalletdb->WriteTx(GetHash(), *this); } /** @@ -1581,14 +1587,14 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // This is only to keep the database open to defeat the auto-flush for the // duration of this scope. This is the only place where this optimization // maybe makes sense; please don't do it anywhere else. - CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL; + CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r+") : NULL; // Take key pair from key pool so it won't be used again reservekey.KeepKey(); // Add tx to wallet, because if it has change it's also ours, // otherwise just for transaction history. - AddToWallet(wtxNew); + AddToWallet(wtxNew, false, pwalletdb); // Notify that old coins are spent set<CWalletTx*> setCoins; diff --git a/src/wallet.h b/src/wallet.h index 1d0dc97c6c..f9cbd3a849 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -275,7 +275,7 @@ public: TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = ""); void MarkDirty(); - bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet=false); + bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); void SyncTransaction(const CTransaction& tx, const CBlock* pblock); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); void EraseFromWallet(const uint256 &hash); @@ -903,7 +903,7 @@ public: return true; } - bool WriteToDisk(); + bool WriteToDisk(CWalletDB *pwalletdb); int64_t GetTxTime() const; int GetRequestCount() const; diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 054473e7cc..d4d2e16740 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -395,7 +395,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, if (wtx.nOrderPos == -1) wss.fAnyUnordered = true; - pwallet->AddToWallet(wtx, true); + pwallet->AddToWallet(wtx, true, NULL); } else if (strType == "acentry") { diff --git a/src/walletdb.h b/src/walletdb.h index 45c00328a4..2627ef71a6 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -76,7 +76,7 @@ public: class CWalletDB : public CDB { public: - CWalletDB(const std::string& strFilename, const char* pszMode = "r+") : CDB(strFilename, pszMode) + CWalletDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose) { } |