aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac8
-rwxr-xr-xcontrib/devtools/github-merge.sh3
-rw-r--r--depends/packages/gmp.mk30
-rw-r--r--depends/packages/packages.mk2
-rw-r--r--depends/patches/gmp/arm_gmp_build_fix.patch21
-rw-r--r--depends/patches/gmp/darwin_gmp_build_fix.patch29
-rw-r--r--doc/REST-interface.md24
-rw-r--r--doc/build-osx.md2
-rw-r--r--doc/build-unix.md5
-rw-r--r--doc/release-notes.md29
-rwxr-xr-xqa/pull-tester/rpc-tests.sh4
-rwxr-xr-xqa/rpc-tests/httpbasics.py76
-rwxr-xr-xqa/rpc-tests/mempool_resurrect_test.py88
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py69
-rwxr-xr-xqa/rpc-tests/rest.py62
-rw-r--r--qa/rpc-tests/util.py16
-rwxr-xr-xqa/rpc-tests/walletbackup.py200
-rwxr-xr-xqa/rpc-tests/walletbackup.sh297
-rw-r--r--src/Makefile.am12
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp16
-rw-r--r--src/bloom.cpp2
-rw-r--r--src/chain.h2
-rw-r--r--src/chainparams.h2
-rw-r--r--src/coincontrol.h2
-rw-r--r--src/compressor.h2
-rw-r--r--src/core_read.cpp4
-rw-r--r--src/core_write.cpp4
-rw-r--r--src/init.cpp10
-rw-r--r--src/init.h6
-rw-r--r--src/main.cpp322
-rw-r--r--src/main.h282
-rw-r--r--src/merkleblock.cpp152
-rw-r--r--src/merkleblock.h151
-rw-r--r--src/miner.cpp4
-rw-r--r--src/net.cpp10
-rw-r--r--src/net.h11
-rw-r--r--src/netbase.cpp20
-rw-r--r--src/netbase.h4
-rw-r--r--src/pow.cpp2
-rw-r--r--src/primitives/block.cpp (renamed from src/core/block.cpp)2
-rw-r--r--src/primitives/block.h (renamed from src/core/block.h)11
-rw-r--r--src/primitives/transaction.cpp (renamed from src/core/transaction.cpp)2
-rw-r--r--src/primitives/transaction.h (renamed from src/core/transaction.h)6
-rw-r--r--src/qt/bitcoin.cpp4
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/guiconstants.h3
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/paymentrequestplus.cpp4
-rw-r--r--src/qt/paymentrequestplus.h4
-rw-r--r--src/qt/paymentserver.cpp91
-rw-r--r--src/qt/paymentserver.h13
-rw-r--r--src/qt/test/paymentservertests.cpp12
-rw-r--r--src/rest.cpp93
-rw-r--r--src/rpcblockchain.cpp6
-rw-r--r--src/rpcmining.cpp11
-rw-r--r--src/rpcrawtransaction.cpp2
-rw-r--r--src/rpcserver.cpp4
-rw-r--r--src/script/bitcoinconsensus.cpp2
-rw-r--r--src/script/interpreter.cpp2
-rw-r--r--src/script/script_error.h6
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/secp256k1/.travis.yml2
-rw-r--r--src/secp256k1/Makefile.am3
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m48
-rw-r--r--src/secp256k1/configure.ac61
-rw-r--r--src/secp256k1/include/secp256k1.h12
-rw-r--r--src/secp256k1/src/ecdsa.h14
-rw-r--r--src/secp256k1/src/ecdsa_impl.h180
-rw-r--r--src/secp256k1/src/eckey.h5
-rw-r--r--src/secp256k1/src/eckey_impl.h33
-rw-r--r--src/secp256k1/src/ecmult.h2
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h19
-rw-r--r--src/secp256k1/src/ecmult_impl.h99
-rw-r--r--src/secp256k1/src/field.h18
-rw-r--r--src/secp256k1/src/field_10x26_impl.h45
-rw-r--r--src/secp256k1/src/field_5x52_impl.h38
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h84
-rw-r--r--src/secp256k1/src/field_gmp_impl.h21
-rw-r--r--src/secp256k1/src/field_impl.h12
-rw-r--r--src/secp256k1/src/group.h8
-rw-r--r--src/secp256k1/src/group_impl.h86
-rw-r--r--src/secp256k1/src/num.h42
-rw-r--r--src/secp256k1/src/num_gmp_impl.h184
-rw-r--r--src/secp256k1/src/num_impl.h2
-rw-r--r--src/secp256k1/src/scalar.h41
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h102
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h126
-rw-r--r--src/secp256k1/src/scalar_impl.h152
-rw-r--r--src/secp256k1/src/secp256k1.c47
-rw-r--r--src/secp256k1/src/tests.c551
-rw-r--r--src/secp256k1/src/util.h17
-rw-r--r--src/test/bloom_tests.cpp4
-rw-r--r--src/test/data/script_invalid.json110
-rw-r--r--src/test/data/script_valid.json106
-rw-r--r--src/test/main_tests.cpp2
-rw-r--r--src/test/pmt_tests.cpp4
-rw-r--r--src/test/script_tests.cpp34
-rw-r--r--src/test/util_tests.cpp3
-rw-r--r--src/txmempool.h2
-rw-r--r--src/undo.h2
-rw-r--r--src/utilmoneystr.cpp2
-rw-r--r--src/utilstrencodings.cpp2
-rw-r--r--src/wallet.h4
104 files changed, 2689 insertions, 1871 deletions
diff --git a/configure.ac b/configure.ac
index 9814197af3..c4c21eaf4f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -244,8 +244,12 @@ case $host in
AC_CHECK_PROG([PORT],port, port)
if test x$PORT = xport; then
dnl add default macports paths
- CPPFLAGS="$CPPFLAGS -isystem /opt/local/include -I/opt/local/include/db48"
- LIBS="$LIBS -L/opt/local/lib -L/opt/local/lib/db48"
+ CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
+ LIBS="$LIBS -L/opt/local/lib"
+ if test -d /opt/local/include/db48; then
+ CPPFLAGS="$CPPFLAGS -I/opt/local/include/db48"
+ LIBS="$LIBS -L/opt/local/lib/db48"
+ fi
fi
AC_CHECK_PROG([BREW],brew, brew)
diff --git a/contrib/devtools/github-merge.sh b/contrib/devtools/github-merge.sh
index 3217a06195..6f68496ed8 100755
--- a/contrib/devtools/github-merge.sh
+++ b/contrib/devtools/github-merge.sh
@@ -136,6 +136,9 @@ else
echo "Dropping you on a shell so you can try building/testing the merged source." >&2
echo "Run 'git diff HEAD~' to show the changes being merged." >&2
echo "Type 'exit' when done." >&2
+ if [[ -f /etc/debian_version ]]; then # Show pull number in prompt on Debian default prompt
+ export debian_chroot="$PULL"
+ fi
bash -i
read -p "Press 'm' to accept the merge. " -n 1 -r >&2
echo
diff --git a/depends/packages/gmp.mk b/depends/packages/gmp.mk
deleted file mode 100644
index bcbf50ceae..0000000000
--- a/depends/packages/gmp.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-package=gmp
-$(package)_version=6.0.0a
-$(package)_download_path=https://gmplib.org/download/gmp
-$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=7f8e9a804b9c6d07164cf754207be838ece1219425d64e28cfa3e70d5c759aaf
-$(package)_patches=arm_gmp_build_fix.patch darwin_gmp_build_fix.patch
-
-define $(package)_preprocess_cmds
- patch -p1 < $($(package)_patch_dir)/arm_gmp_build_fix.patch && \
- patch -p1 < $($(package)_patch_dir)/darwin_gmp_build_fix.patch
-endef
-
-define $(package)_set_vars
- $(package)_config_opts=--disable-shared CC_FOR_BUILD=$(build_CC)
- $(package)_config_opts_x86_64_darwin=--with-pic
- $(package)_config_opts_x86_64_linux=--with-pic
- $(package)_config_opts_arm_linux=--with-pic
-endef
-
-define $(package)_config_cmds
- $($(package)_autoconf)
-endef
-
-define $(package)_build_cmds
- $(MAKE)
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 305d21cb2d..bbf53cc2dc 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,4 +1,4 @@
-packages:=boost openssl gmp
+packages:=boost openssl
native_packages := native_ccache native_comparisontool
qt_native_packages = native_protobuf
diff --git a/depends/patches/gmp/arm_gmp_build_fix.patch b/depends/patches/gmp/arm_gmp_build_fix.patch
deleted file mode 100644
index 666cf58cf6..0000000000
--- a/depends/patches/gmp/arm_gmp_build_fix.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-
-# HG changeset patch
-# User Torbjorn Granlund <tege@gmplib.org>
-# Date 1396602422 -7200
-# Node ID 676e2d0f0e4dd301a7066079d2c9326c25c34a40
-# Parent 0194a75b56b21a9196626430af86c5bd9110c42d
-Conditionalise ARM asm on !__thumb__.
-
-diff -r 0194a75b56b2 -r 676e2d0f0e4d mpn/generic/div_qr_1n_pi1.c
---- a/mpn/generic/div_qr_1n_pi1.c Thu Apr 03 23:58:51 2014 +0200
-+++ b/mpn/generic/div_qr_1n_pi1.c Fri Apr 04 11:07:02 2014 +0200
-@@ -130,7 +130,7 @@
- "%2" ((UDItype)(a0)), "r" ((UDItype)(b0)) __CLOBBER_CC)
- #endif
-
--#if defined (__arm__) && W_TYPE_SIZE == 32
-+#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32
- #define add_mssaaaa(m, sh, sl, ah, al, bh, bl) \
- __asm__ ( "adds %2, %5, %6\n\t" \
- "adcs %1, %3, %4\n\t" \
-
diff --git a/depends/patches/gmp/darwin_gmp_build_fix.patch b/depends/patches/gmp/darwin_gmp_build_fix.patch
deleted file mode 100644
index b9cfd80e77..0000000000
--- a/depends/patches/gmp/darwin_gmp_build_fix.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-
-# HG changeset patch
-# User Torbjorn Granlund <tege@gmplib.org>
-# Date 1396470504 -7200
-# Node ID 1fab0adc5ff7d9ecddcbda96f407da58347bb49c
-# Parent db645603dcdb41afcf78b19b551ecd5a01c3841c
-Workaround for Darwin assembler quirk.
-
-diff -r db645603dcdb -r 1fab0adc5ff7 mpn/x86_64/k8/redc_1.asm
---- a/mpn/x86_64/k8/redc_1.asm Mon Mar 31 23:04:32 2014 +0200
-+++ b/mpn/x86_64/k8/redc_1.asm Wed Apr 02 22:28:24 2014 +0200
-@@ -114,7 +114,7 @@
-
- JUMPTABSECT
- ALIGN(8)
--L(tab): JMPENT( L(0m4), L(tab))
-+L(tab): JMPENT( L(0), L(tab))
- JMPENT( L(1), L(tab))
- JMPENT( L(2), L(tab))
- JMPENT( L(3), L(tab))
-@@ -397,6 +397,7 @@
-
-
- ALIGN(16)
-+L(0):
- L(0m4):
- L(lo0): mov (mp,nneg,8), %rax
- mov nneg, i
-
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
new file mode 100644
index 0000000000..05c532be54
--- /dev/null
+++ b/doc/REST-interface.md
@@ -0,0 +1,24 @@
+Unauthenticated REST Interface
+==============================
+
+The REST API can be enabled with the `-rest` option.
+
+Supported API
+-------------
+`GET /rest/tx/TX-HASH.{bin|hex|json}`
+
+Given a transaction hash,
+Returns a transaction, in binary, hex-encoded binary or JSON formats.
+
+`GET /rest/block/BLOCK-HASH.{bin|hex|json}`
+
+Given a block hash,
+Returns a block, in binary, hex-encoded binary or JSON formats.
+
+The HTTP request and response are both handled entirely in-memory, thus making maximum memory usage at least 2.66MB (1 MB max block, plus hex encoding) per request.
+
+For full TX query capability, one must enable the transaction index via "txindex=1" command line / configuration option.
+
+Risks
+-------------
+Running a webbrowser on the same node with a REST enabled bitcoind can be a risk. Accessing prepared XSS websites could read out tx/block data of your node by placing links like `<script src="http://127.0.0.1:1234/tx/json/1234567890">` which might break the nodes privacy. \ No newline at end of file
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 491c5c4683..c41820f2b1 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -38,7 +38,7 @@ Instructions: Homebrew
#### Install dependencies using Homebrew
- brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt gmp
+ brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt
#### Installing berkeley-db4 using Homebrew
diff --git a/doc/build-unix.md b/doc/build-unix.md
index e03dc8181a..8ddee3b757 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -33,7 +33,6 @@ These dependencies are required:
------------|------------------|----------------------
libssl | SSL Support | Secure communications
libboost | Boost | C++ Library
- libgmp | secp256k1 | Arbitrary-precision arithmetic (version >= 3.1)
Optional dependencies:
@@ -58,7 +57,7 @@ Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
- sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libgmp-dev
+ sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev
for Ubuntu 12.04 and later or Debian 7 and later libboost-all-dev has to be installed:
@@ -106,7 +105,7 @@ To build with Qt 4 you need the following:
For Qt 5 you need the following:
- sudo apt-get install libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
+ sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
libqrencode (optional) can be installed with:
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 6aaea67790..f804e8c11b 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -95,3 +95,32 @@ are done, it always returns an immediate error with code -28 to all calls.
This new behaviour can be useful for clients to know that a server is already
started and will be available soon (for instance, so that they do not
have to start it themselves).
+
+Improved signing security
+=========================
+
+For 0.10 the security of signing against unusual attacks has been
+improved by making the signatures constant time and deterministic.
+
+This change is a result of switching signing to use libsecp256k1
+instead of OpenSSL. Libsecp256k1 is a cryptographic library
+optimized for the curve Bitcoin uses which was created by Bitcoin
+Core developer Pieter Wuille.
+
+There exist attacks[1] against most ECC implementations where an
+attacker on shared virtual machine hardware could extract a private
+key if they could cause a target to sign using the same key hundreds
+of times. While using shared hosts and reusing keys are inadvisable
+for other reasons, it's a better practice to avoid the exposure.
+
+OpenSSL has code in their source repository for derandomization
+and reduction in timing leaks, and we've eagerly wanted to use
+it for a long time but this functionality has still not made its
+way into a released version of OpenSSL. Libsecp256k1 achieves
+significantly stronger protection: As far as we're aware this is
+the only deployed implementation of constant time signing for
+the curve Bitcoin uses and we have reason to believe that
+libsecp256k1 is better tested and more thoroughly reviewed
+than the implementation in OpenSSL.
+
+[1] https://eprint.iacr.org/2014/161.pdf
diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh
index 2f1e24b78d..071935759b 100755
--- a/qa/pull-tester/rpc-tests.sh
+++ b/qa/pull-tester/rpc-tests.sh
@@ -18,9 +18,13 @@ fi
if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
${BUILDDIR}/qa/rpc-tests/wallet.py --srcdir "${BUILDDIR}/src"
${BUILDDIR}/qa/rpc-tests/listtransactions.py --srcdir "${BUILDDIR}/src"
+ ${BUILDDIR}/qa/rpc-tests/mempool_resurrect_test.py --srcdir "${BUILDDIR}/src"
${BUILDDIR}/qa/rpc-tests/txn_doublespend.py --srcdir "${BUILDDIR}/src"
${BUILDDIR}/qa/rpc-tests/txn_doublespend.py --mineblock --srcdir "${BUILDDIR}/src"
${BUILDDIR}/qa/rpc-tests/getchaintips.py --srcdir "${BUILDDIR}/src"
+ ${BUILDDIR}/qa/rpc-tests/rest.py --srcdir "${BUILDDIR}/src"
+ ${BUILDDIR}/qa/rpc-tests/mempool_spendcoinbase.py --srcdir "${BUILDDIR}/src"
+ ${BUILDDIR}/qa/rpc-tests/httpbasics.py --srcdir "${BUILDDIR}/src"
#${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src"
else
echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
new file mode 100755
index 0000000000..a94edaffa5
--- /dev/null
+++ b/qa/rpc-tests/httpbasics.py
@@ -0,0 +1,76 @@
+#!/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.
+
+#
+# Test REST interface
+#
+
+from test_framework import BitcoinTestFramework
+from util import *
+import base64
+
+try:
+ import http.client as httplib
+except ImportError:
+ import httplib
+try:
+ import urllib.parse as urlparse
+except ImportError:
+ import urlparse
+
+class RESTTest (BitcoinTestFramework):
+ def run_test(self):
+
+ #################################################
+ # lowlevel check for http persistent connection #
+ #################################################
+ url = urlparse.urlparse(self.nodes[0].url)
+ authpair = url.username + ':' + url.password
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('GET', '/', '{"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)
+ 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!
+ conn.close()
+
+ #same should be if we add keep-alive because this should be the std. behaviour
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection": "keep-alive"}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('GET', '/', '{"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)
+ 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!
+ conn.close()
+
+ #now do the same with "Connection: close"
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection":"close"}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('GET', '/', '{"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
+
+
+if __name__ == '__main__':
+ RESTTest ().main ()
diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py
new file mode 100755
index 0000000000..81db812bfc
--- /dev/null
+++ b/qa/rpc-tests/mempool_resurrect_test.py
@@ -0,0 +1,88 @@
+#!/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.
+
+#
+# Test resurrection of mined transactions when
+# the blockchain is re-organized.
+#
+
+from test_framework import BitcoinTestFramework
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+import os
+import shutil
+
+# Create one-input, one-output, no-fee transaction:
+class MempoolCoinbaseTest(BitcoinTestFramework):
+
+ def setup_network(self):
+ # Just need one node for this test
+ args = ["-checkmempool", "-debug=mempool"]
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, args))
+ self.is_network_split = False
+
+ def create_tx(self, from_txid, to_address, amount):
+ inputs = [{ "txid" : from_txid, "vout" : 0}]
+ outputs = { to_address : amount }
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ signresult = self.nodes[0].signrawtransaction(rawtx)
+ assert_equal(signresult["complete"], True)
+ return signresult["hex"]
+
+ def run_test(self):
+ node0_address = self.nodes[0].getnewaddress()
+
+ # Spend block 1/2/3's coinbase transactions
+ # Mine a block.
+ # Create three more transactions, spending the spends
+ # Mine another block.
+ # ... make sure all the transactions are confirmed
+ # Invalidate both blocks
+ # ... make sure all the transactions are put back in the mempool
+ # Mine a new block
+ # ... make sure all the transactions are confirmed again.
+
+ b = [ self.nodes[0].getblockhash(n) for n in range(1, 4) ]
+ coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
+ spends1_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ]
+ spends1_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw ]
+
+ blocks = []
+ blocks.extend(self.nodes[0].setgenerate(True, 1))
+
+ spends2_raw = [ self.create_tx(txid, node0_address, 49.99) for txid in spends1_id ]
+ spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ]
+
+ blocks.extend(self.nodes[0].setgenerate(True, 1))
+
+ # mempool should be empty, all txns confirmed
+ assert_equal(set(self.nodes[0].getrawmempool()), set())
+ for txid in spends1_id+spends2_id:
+ tx = self.nodes[0].gettransaction(txid)
+ assert(tx["confirmations"] > 0)
+
+ # Use invalidateblock to re-org back; all transactions should
+ # end up unconfirmed and back in the mempool
+ for node in self.nodes:
+ node.invalidateblock(blocks[0])
+
+ # mempool should be empty, all txns confirmed
+ assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))
+ for txid in spends1_id+spends2_id:
+ tx = self.nodes[0].gettransaction(txid)
+ assert(tx["confirmations"] == 0)
+
+ # Generate another block, they should all get mined
+ self.nodes[0].setgenerate(True, 1)
+ # mempool should be empty, all txns confirmed
+ assert_equal(set(self.nodes[0].getrawmempool()), set())
+ for txid in spends1_id+spends2_id:
+ tx = self.nodes[0].gettransaction(txid)
+ assert(tx["confirmations"] > 0)
+
+
+if __name__ == '__main__':
+ MempoolCoinbaseTest().main()
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
new file mode 100755
index 0000000000..f0b34f2904
--- /dev/null
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -0,0 +1,69 @@
+#!/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.
+
+#
+# Test spending coinbase transactions.
+# The coinbase transaction in block N can appear in block
+# N+100... so is valid in the mempool when the best block
+# height is N+99.
+# This test makes sure coinbase spends that will be mature
+# in the next block are accepted into the memory pool,
+# but less mature coinbase spends are NOT.
+#
+
+from test_framework import BitcoinTestFramework
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+import os
+import shutil
+
+# Create one-input, one-output, no-fee transaction:
+class MempoolSpendCoinbaseTest(BitcoinTestFramework):
+
+ def setup_network(self):
+ # Just need one node for this test
+ args = ["-checkmempool", "-debug=mempool"]
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, args))
+ self.is_network_split = False
+
+ def create_tx(self, from_txid, to_address, amount):
+ inputs = [{ "txid" : from_txid, "vout" : 0}]
+ outputs = { to_address : amount }
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ signresult = self.nodes[0].signrawtransaction(rawtx)
+ assert_equal(signresult["complete"], True)
+ return signresult["hex"]
+
+ def run_test(self):
+ chain_height = self.nodes[0].getblockcount()
+ assert_equal(chain_height, 200)
+ node0_address = self.nodes[0].getnewaddress()
+
+ # Coinbase at height chain_height-100+1 ok in mempool, should
+ # get mined. Coinbase at height chain_height-100+2 is
+ # is too immature to spend.
+ b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ]
+ coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
+ spends_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ]
+
+ spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
+
+ # coinbase at height 102 should be too immature to spend
+ assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1])
+
+ # mempool should have just spend_101:
+ assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])
+
+ # mine a block, spend_101 should get confirmed
+ self.nodes[0].setgenerate(True, 1)
+ assert_equal(set(self.nodes[0].getrawmempool()), set())
+
+ # ... and now height 102 can be spent:
+ spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
+ assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])
+
+if __name__ == '__main__':
+ MempoolSpendCoinbaseTest().main()
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
new file mode 100755
index 0000000000..c62a96fbb8
--- /dev/null
+++ b/qa/rpc-tests/rest.py
@@ -0,0 +1,62 @@
+#!/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.
+
+#
+# Test REST interface
+#
+
+from test_framework import BitcoinTestFramework
+from util import *
+import json
+
+try:
+ import http.client as httplib
+except ImportError:
+ import httplib
+try:
+ import urllib.parse as urlparse
+except ImportError:
+ import urlparse
+
+def http_get_call(host, port, path, response_object = 0):
+ conn = httplib.HTTPConnection(host, port)
+ conn.request('GET', path)
+
+ if response_object:
+ return conn.getresponse()
+
+ return conn.getresponse().read()
+
+
+class RESTTest (BitcoinTestFramework):
+ FORMAT_SEPARATOR = "."
+
+ def run_test(self):
+ url = urlparse.urlparse(self.nodes[0].url)
+ bb_hash = self.nodes[0].getbestblockhash()
+
+ # check binary format
+ response = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True)
+ assert_equal(response.status, 200)
+ assert_greater_than(int(response.getheader('content-length')), 10)
+
+ # check json format
+ json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json')
+ json_obj = json.loads(json_string)
+ assert_equal(json_obj['hash'], bb_hash)
+
+ # do tx test
+ tx_hash = json_obj['tx'][0];
+ json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json")
+ json_obj = json.loads(json_string)
+ assert_equal(json_obj['txid'], tx_hash)
+
+ # check hex format response
+ hex_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"hex", True)
+ assert_equal(response.status, 200)
+ assert_greater_than(int(response.getheader('content-length')), 10)
+
+if __name__ == '__main__':
+ RESTTest ().main ()
diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py
index bed7fed8ca..ec65f783e8 100644
--- a/qa/rpc-tests/util.py
+++ b/qa/rpc-tests/util.py
@@ -163,7 +163,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None):
Start a bitcoind and return RPC connection to it
"""
datadir = os.path.join(dirname, "node"+str(i))
- args = [ os.getenv("BITCOIND", "bitcoind"), "-datadir="+datadir, "-keypool=1", "-discover=0" ]
+ args = [ os.getenv("BITCOIND", "bitcoind"), "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ]
if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args)
devnull = open("/dev/null", "w+")
@@ -327,3 +327,17 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
def assert_equal(thing1, thing2):
if thing1 != thing2:
raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
+
+def assert_greater_than(thing1, thing2):
+ if thing1 <= thing2:
+ raise AssertionError("%s <= %s"%(str(thing1),str(thing2)))
+
+def assert_raises(exc, fun, *args, **kwds):
+ try:
+ fun(*args, **kwds)
+ except exc:
+ pass
+ except Exception as e:
+ raise AssertionError("Unexpected exception raised: "+type(e).__name__)
+ else:
+ raise AssertionError("No exception raised")
diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
new file mode 100755
index 0000000000..6a42d9dfa4
--- /dev/null
+++ b/qa/rpc-tests/walletbackup.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python2
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+"""
+Exercise the wallet backup code. Ported from walletbackup.sh.
+
+Test case is:
+4 nodes. 1 2 and 3 send transactions between each other,
+fourth node is a miner.
+1 2 3 each mine a block to start, then
+Miner creates 100 blocks so 1 2 3 each have 50 mature
+coins to spend.
+Then 5 iterations of 1/2/3 sending coins amongst
+themselves to get transactions in the wallets,
+and the miner mining one block.
+
+Wallets are backed up using dumpwallet/backupwallet.
+Then 5 more iterations of transactions and mining a block.
+
+Miner then generates 101 more blocks, so any
+transaction fees paid mature.
+
+Sanity check:
+ Sum(1,2,3,4 balances) == 114*50
+
+1/2/3 are shutdown, and their wallets erased.
+Then restore using wallet.dat backup. And
+confirm 1/2/3/4 balances are same as before.
+
+Shutdown again, restore using importwallet,
+and confirm again balances are correct.
+"""
+
+from test_framework import BitcoinTestFramework
+from util import *
+from random import randint
+import logging
+logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
+
+class WalletBackupTest(BitcoinTestFramework):
+
+ def setup_chain(self):
+ logging.info("Initializing test directory "+self.options.tmpdir)
+ initialize_chain_clean(self.options.tmpdir, 4)
+
+ # This mirrors how the network was setup in the bash test
+ def setup_network(self, split=False):
+ # nodes 1, 2,3 are spenders, let's give them a keypool=100
+ extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
+ self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
+ connect_nodes(self.nodes[0], 3)
+ connect_nodes(self.nodes[1], 3)
+ connect_nodes(self.nodes[2], 3)
+ connect_nodes(self.nodes[2], 0)
+ self.is_network_split=False
+ self.sync_all()
+
+ def one_send(self, from_node, to_address):
+ if (randint(1,2) == 1):
+ amount = Decimal(randint(1,10)) / Decimal(10)
+ self.nodes[from_node].sendtoaddress(to_address, amount)
+
+ def do_one_round(self):
+ a0 = self.nodes[0].getnewaddress()
+ a1 = self.nodes[1].getnewaddress()
+ a2 = self.nodes[2].getnewaddress()
+
+ self.one_send(0, a1)
+ self.one_send(0, a2)
+ self.one_send(1, a0)
+ self.one_send(1, a2)
+ self.one_send(2, a0)
+ self.one_send(2, a1)
+
+ # Have the miner (node3) mine a block.
+ # Must sync mempools before mining.
+ sync_mempools(self.nodes)
+ self.nodes[3].setgenerate(True, 1)
+
+ # As above, this mirrors the original bash test.
+ def start_three(self):
+ self.nodes[0] = start_node(0, self.options.tmpdir)
+ self.nodes[1] = start_node(1, self.options.tmpdir)
+ self.nodes[2] = start_node(2, self.options.tmpdir)
+ connect_nodes(self.nodes[0], 3)
+ connect_nodes(self.nodes[1], 3)
+ connect_nodes(self.nodes[2], 3)
+ connect_nodes(self.nodes[2], 0)
+
+ def stop_three(self):
+ stop_node(self.nodes[0], 0)
+ stop_node(self.nodes[1], 1)
+ stop_node(self.nodes[2], 2)
+
+ def erase_three(self):
+ os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat")
+ os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
+ os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat")
+
+ def run_test(self):
+ logging.info("Generating initial blockchain")
+ self.nodes[0].setgenerate(True, 1)
+ sync_blocks(self.nodes)
+ self.nodes[1].setgenerate(True, 1)
+ sync_blocks(self.nodes)
+ self.nodes[2].setgenerate(True, 1)
+ sync_blocks(self.nodes)
+ self.nodes[3].setgenerate(True, 100)
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getbalance(), 50)
+ assert_equal(self.nodes[1].getbalance(), 50)
+ assert_equal(self.nodes[2].getbalance(), 50)
+ assert_equal(self.nodes[3].getbalance(), 0)
+
+ logging.info("Creating transactions")
+ # Five rounds of sending each other transactions.
+ for i in range(5):
+ self.do_one_round()
+
+ logging.info("Backing up")
+ tmpdir = self.options.tmpdir
+ self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
+ self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
+ self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak")
+ self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump")
+ self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
+ self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
+
+ logging.info("More transactions")
+ for i in range(5):
+ self.do_one_round()
+
+ # Generate 101 more blocks, so any fees paid mature
+ self.nodes[3].setgenerate(True, 101)
+ self.sync_all()
+
+ balance0 = self.nodes[0].getbalance()
+ balance1 = self.nodes[1].getbalance()
+ balance2 = self.nodes[2].getbalance()
+ balance3 = self.nodes[3].getbalance()
+ total = balance0 + balance1 + balance2 + balance3
+
+ # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.)
+ # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700.
+ assert_equal(total, 5700)
+
+ ##
+ # Test restoring spender wallets from backups
+ ##
+ logging.info("Restoring using wallet.dat")
+ self.stop_three()
+ self.erase_three()
+
+ # Start node2 with no chain
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
+
+ # Restore wallets from backup
+ shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat")
+ shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat")
+ shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat")
+
+ logging.info("Re-starting nodes")
+ self.start_three()
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getbalance(), balance0)
+ assert_equal(self.nodes[1].getbalance(), balance1)
+ assert_equal(self.nodes[2].getbalance(), balance2)
+
+ logging.info("Restoring using dumped wallet")
+ self.stop_three()
+ self.erase_three()
+
+ #start node2 with no chain
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
+
+ self.start_three()
+
+ assert_equal(self.nodes[0].getbalance(), 0)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ assert_equal(self.nodes[2].getbalance(), 0)
+
+ self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump")
+ self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump")
+ self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump")
+
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getbalance(), balance0)
+ assert_equal(self.nodes[1].getbalance(), balance1)
+ assert_equal(self.nodes[2].getbalance(), balance2)
+
+
+if __name__ == '__main__':
+ WalletBackupTest().main()
diff --git a/qa/rpc-tests/walletbackup.sh b/qa/rpc-tests/walletbackup.sh
deleted file mode 100755
index 4af3d97f35..0000000000
--- a/qa/rpc-tests/walletbackup.sh
+++ /dev/null
@@ -1,297 +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 wallet backup / dump / restore functionality
-
-# Test case is:
-# 4 nodes. 1 2 3 and send transactions between each other,
-# fourth node is a miner.
-# 1 2 3 and each mine a block to start, then
-# miner creates 100 blocks so 1 2 3 each have 50 mature
-# coins to spend.
-# Then 5 iterations of 1/2/3 sending coins amongst
-# themselves to get transactions in the wallets,
-# and the miner mining one block.
-#
-# Wallets are backed up using dumpwallet/backupwallet.
-# Then 5 more iterations of transactions, then block.
-#
-# Miner then generates 101 more blocks, so any
-# transaction fees paid mature.
-#
-# Sanity checks done:
-# Miner balance >= 150*50
-# Sum(1,2,3,4 balances) == 153*150
-#
-# 1/2/3 are shutdown, and their wallets erased.
-# Then restore using wallet.dat backup. And
-# confirm 1/2/3/4 balances are same as before.
-#
-# Shutdown again, restore using importwallet,
-# and confirm again balances are correct.
-#
-
-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
-
-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)
-
-echo "Starting nodes..."
-
-# "Miner":
-D4=${D}/node4
-CreateDataDir $D4 port=11030 rpcport=11031
-B4ARGS="-datadir=$D4"
-$BITCOIND $BITCOINDARGS $B4ARGS &
-B4PID=$!
-
-# Want default keypool for 1/2/3, and
-# don't need send-and-wait functionality,
-# so don't use CreateDataDir:
-function CreateConfDir {
- DIR=$1
- mkdir -p $DIR
- CONF=$DIR/bitcoin.conf
- echo "regtest=1" >> $CONF
- echo "rpcuser=rt" >> $CONF
- echo "rpcpassword=rt" >> $CONF
- echo "rpcwait=1" >> $CONF
- shift
- while (( "$#" )); do
- echo $1 >> $CONF
- shift
- done
-}
-
-# "Spenders" 1/2/3
-D1=${D}/node1
-CreateConfDir $D1 port=11000 rpcport=11001 addnode=127.0.0.1:11030
-B1ARGS="-datadir=$D1"
-$BITCOIND $B1ARGS &
-B1PID=$!
-D2=${D}/node2
-CreateConfDir $D2 port=11010 rpcport=11011 addnode=127.0.0.1:11030
-B2ARGS="-datadir=$D2"
-$BITCOIND $B2ARGS &
-B2PID=$!
-D3=${D}/node3
-CreateConfDir $D3 port=11020 rpcport=11021 addnode=127.0.0.1:11030 addnode=127.0.0.1:11000
-B3ARGS="-datadir=$D3"
-$BITCOIND $BITCOINDARGS $B3ARGS &
-B3PID=$!
-
-# Wait until all nodes are at the same block number
-function WaitBlocks {
- while :
- do
- sleep 1
- BLOCKS1=$( GetBlocks "$B1ARGS" )
- BLOCKS2=$( GetBlocks "$B2ARGS" )
- BLOCKS3=$( GetBlocks "$B3ARGS" )
- BLOCKS4=$( GetBlocks "$B4ARGS" )
- if (( BLOCKS1 == BLOCKS4 && BLOCKS2 == BLOCKS4 && BLOCKS3 == BLOCKS4 ))
- then
- break
- fi
- done
-}
-
-# Wait until all nodes have the same txns in
-# their memory pools
-function WaitMemPools {
- while :
- do
- sleep 1
- MEMPOOL1=$( $CLI "$B1ARGS" getrawmempool | sort | shasum )
- MEMPOOL2=$( $CLI "$B2ARGS" getrawmempool | sort | shasum )
- MEMPOOL3=$( $CLI "$B3ARGS" getrawmempool | sort | shasum )
- MEMPOOL4=$( $CLI "$B4ARGS" getrawmempool | sort | shasum )
- if [[ $MEMPOOL1 = $MEMPOOL4 && $MEMPOOL2 = $MEMPOOL4 && $MEMPOOL3 = $MEMPOOL4 ]]
- then
- break
- fi
- done
-}
-
-echo "Generating initial blockchain..."
-
-# 1 block, 50 XBT each == 50 BTC
-$CLI $B1ARGS setgenerate true 1
-WaitBlocks
-$CLI $B2ARGS setgenerate true 1
-WaitBlocks
-$CLI $B3ARGS setgenerate true 1
-WaitBlocks
-
-# 100 blocks, 0 mature
-$CLI $B4ARGS setgenerate true 100
-WaitBlocks
-
-CheckBalance "$B1ARGS" 50
-CheckBalance "$B2ARGS" 50
-CheckBalance "$B3ARGS" 50
-CheckBalance "$B4ARGS" 0
-
-echo "Creating transactions..."
-
-function S {
- TXID=$( $CLI -datadir=${D}/node${1} sendtoaddress ${2} "${3}" 0 )
- if [ x$TXID = x ] ; then
- echoerr "node${1}: error sending ${3} btc"
- echo -n "node${1} balance: "
- $CLI -datadir=${D}/node${1} getbalance "*" 0
- exit 1
- fi
-}
-
-function OneRound {
- A1=$( $CLI $B1ARGS getnewaddress )
- A2=$( $CLI $B2ARGS getnewaddress )
- A3=$( $CLI $B3ARGS getnewaddress )
- if [[ $(( $RANDOM%2 )) < 1 ]] ; then
- N=$(( $RANDOM % 9 + 1 ))
- S 1 $A2 "0.$N"
- fi
- if [[ $(( $RANDOM%2 )) < 1 ]] ; then
- N=$(( $RANDOM % 9 + 1 ))
- S 1 $A3 "0.0$N"
- fi
- if [[ $(( $RANDOM%2 )) < 1 ]] ; then
- N=$(( $RANDOM % 9 + 1 ))
- S 2 $A1 "0.$N"
- fi
- if [[ $(( $RANDOM%2 )) < 1 ]] ; then
- N=$(( $RANDOM % 9 + 1 ))
- S 2 $A3 "0.$N"
- fi
- if [[ $(( $RANDOM%2 )) < 1 ]] ; then
- N=$(( $RANDOM % 9 + 1 ))
- S 3 $A1 "0.$N"
- fi
- if [[ $(( $RANDOM%2 )) < 1 ]] ; then
- N=$(( $RANDOM % 9 + 1 ))
- S 3 $A2 "0.0$N"
- fi
- $CLI "$B4ARGS" setgenerate true 1
-}
-
-for i in {1..5}; do OneRound ; done
-
-echo "Backing up..."
-
-$CLI "$B1ARGS" backupwallet "$D1/wallet.bak"
-$CLI "$B1ARGS" dumpwallet "$D1/wallet.dump"
-$CLI "$B2ARGS" backupwallet "$D2/wallet.bak"
-$CLI "$B2ARGS" dumpwallet "$D2/wallet.dump"
-$CLI "$B3ARGS" backupwallet "$D3/wallet.bak"
-$CLI "$B3ARGS" dumpwallet "$D3/wallet.dump"
-
-echo "More transactions..."
-for i in {1..5}; do OneRound ; done
-
-WaitMemPools
-
-# Generate 101 more blocks, so any fees paid
-# mature
-$CLI "$B4ARGS" setgenerate true 101
-
-BALANCE1=$( $CLI "$B1ARGS" getbalance )
-BALANCE2=$( $CLI "$B2ARGS" getbalance )
-BALANCE3=$( $CLI "$B3ARGS" getbalance )
-BALANCE4=$( $CLI "$B4ARGS" getbalance )
-
-TOTAL=$( dc -e "$BALANCE1 $BALANCE2 $BALANCE3 $BALANCE4 + + + p" )
-
-AssertEqual $TOTAL 5700.00000000
-
-function StopThree {
- $CLI $B1ARGS stop > /dev/null 2>&1
- $CLI $B2ARGS stop > /dev/null 2>&1
- $CLI $B3ARGS stop > /dev/null 2>&1
- wait $B1PID
- wait $B2PID
- wait $B3PID
-}
-function EraseThree {
- rm $D1/regtest/wallet.dat
- rm $D2/regtest/wallet.dat
- rm $D3/regtest/wallet.dat
-}
-function StartThree {
- $BITCOIND $BITCOINDARGS $B1ARGS &
- B1PID=$!
- $BITCOIND $BITCOINDARGS $B2ARGS &
- B2PID=$!
- $BITCOIND $BITCOINDARGS $B3ARGS &
- B3PID=$!
-}
-
-echo "Restoring using wallet.dat"
-
-StopThree
-EraseThree
-
-# Start node3 with no chain
-rm -rf $D3/regtest/blocks
-rm -rf $D3/regtest/chainstate
-rm -rf $D3/regtest/database
-
-cp $D1/wallet.bak $D1/regtest/wallet.dat
-cp $D2/wallet.bak $D2/regtest/wallet.dat
-cp $D3/wallet.bak $D3/regtest/wallet.dat
-
-StartThree
-WaitBlocks
-
-AssertEqual $BALANCE1 $( $CLI "$B1ARGS" getbalance )
-AssertEqual $BALANCE2 $( $CLI "$B2ARGS" getbalance )
-AssertEqual $BALANCE3 $( $CLI "$B3ARGS" getbalance )
-
-echo "Restoring using dumped wallet"
-
-StopThree
-EraseThree
-
-# Start node3 with no chain
-rm -rf $D3/regtest/blocks
-rm -rf $D3/regtest/chainstate
-rm -rf $D3/regtest/database
-
-StartThree
-
-AssertEqual 0 $( $CLI "$B1ARGS" getbalance )
-AssertEqual 0 $( $CLI "$B2ARGS" getbalance )
-AssertEqual 0 $( $CLI "$B3ARGS" getbalance )
-
-$CLI "$B1ARGS" importwallet $D1/wallet.dump
-$CLI "$B2ARGS" importwallet $D2/wallet.dump
-$CLI "$B3ARGS" importwallet $D3/wallet.dump
-
-WaitBlocks
-
-AssertEqual $BALANCE1 $( $CLI "$B1ARGS" getbalance )
-AssertEqual $BALANCE2 $( $CLI "$B2ARGS" getbalance )
-AssertEqual $BALANCE3 $( $CLI "$B3ARGS" getbalance )
-
-StopThree
-$CLI $B4ARGS stop > /dev/null 2>&1
-wait $B4PID
-
-echo "Tests successful, cleaning up"
-trap "" EXIT
-rm -rf $D
-exit 0
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c4f9f6937..d6ac6e1277 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,8 +87,8 @@ BITCOIN_CORE_H = \
coins.h \
compat.h \
compressor.h \
- core/block.h \
- core/transaction.h \
+ primitives/block.h \
+ primitives/transaction.h \
core_io.h \
crypter.h \
db.h \
@@ -101,6 +101,7 @@ BITCOIN_CORE_H = \
leveldbwrapper.h \
limitedmap.h \
main.h \
+ merkleblock.h \
miner.h \
mruset.h \
netbase.h \
@@ -168,6 +169,7 @@ libbitcoin_server_a_SOURCES = \
init.cpp \
leveldbwrapper.cpp \
main.cpp \
+ merkleblock.cpp \
miner.cpp \
net.cpp \
noui.cpp \
@@ -235,8 +237,8 @@ libbitcoin_common_a_SOURCES = \
chainparams.cpp \
coins.cpp \
compressor.cpp \
- core/block.cpp \
- core/transaction.cpp \
+ primitives/block.cpp \
+ primitives/transaction.cpp \
core_read.cpp \
core_write.cpp \
eccryptoverify.cpp \
@@ -350,7 +352,7 @@ bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if BUILD_BITCOIN_LIBS
include_HEADERS = script/bitcoinconsensus.h
libbitcoinconsensus_la_SOURCES = \
- core/transaction.cpp \
+ primitives/transaction.cpp \
crypto/hmac_sha512.cpp \
crypto/sha1.cpp \
crypto/sha256.cpp \
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 1b638e99e9..ea349b197e 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -110,7 +110,7 @@ Object CallRPC(const string& strMethod, const Array& params)
bool fUseSSL = GetBoolArg("-rpcssl", false);
asio::io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
- context.set_options(ssl::context::no_sslv2);
+ context.set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3);
asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index c0d21ed36f..7308d93661 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -4,15 +4,17 @@
#include "base58.h"
#include "clientversion.h"
-#include "core/transaction.h"
+#include "primitives/block.h" // for MAX_BLOCK_SIZE
+#include "primitives/transaction.h"
#include "core_io.h"
+#include "coins.h"
#include "keystore.h"
-#include "main.h" // for MAX_BLOCK_SIZE
#include "script/script.h"
#include "script/sign.h"
#include "ui_interface.h" // for _(...)
#include "univalue/univalue.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "utilmoneystr.h"
#include <stdio.h>
@@ -57,6 +59,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += " -? " + _("This help message") + "\n";
strUsage += " -create " + _("Create new, empty TX.") + "\n";
strUsage += " -json " + _("Select JSON output") + "\n";
+ strUsage += " -txid " + _("Output only the hex-encoded transaction id of the resultant transaction.") + "\n";
strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly.") + "\n";
strUsage += " -testnet " + _("Use the test network") + "\n";
strUsage += "\n";
@@ -488,6 +491,13 @@ static void OutputTxJSON(const CTransaction& tx)
fprintf(stdout, "%s\n", jsonOutput.c_str());
}
+static void OutputTxHash(const CTransaction& tx)
+{
+ string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
+
+ fprintf(stdout, "%s\n", strHexHash.c_str());
+}
+
static void OutputTxHex(const CTransaction& tx)
{
string strHex = EncodeHexTx(tx);
@@ -499,6 +509,8 @@ static void OutputTx(const CTransaction& tx)
{
if (GetBoolArg("-json", false))
OutputTxJSON(tx);
+ else if (GetBoolArg("-txid", false))
+ OutputTxHash(tx);
else
OutputTxHex(tx);
}
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 07b8f2c0ae..da30e6f355 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -4,7 +4,7 @@
#include "bloom.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "hash.h"
#include "script/script.h"
#include "script/standard.h"
diff --git a/src/chain.h b/src/chain.h
index c01240665d..d834790f06 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_CHAIN_H
#define BITCOIN_CHAIN_H
-#include "core/block.h"
+#include "primitives/block.h"
#include "pow.h"
#include "tinyformat.h"
#include "uint256.h"
diff --git a/src/chainparams.h b/src/chainparams.h
index 9f24b70a26..5d1ee1d3c6 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -8,7 +8,7 @@
#include "chainparamsbase.h"
#include "checkpoints.h"
-#include "core/block.h"
+#include "primitives/block.h"
#include "protocol.h"
#include "uint256.h"
diff --git a/src/coincontrol.h b/src/coincontrol.h
index c8bdd3b39d..cf61998723 100644
--- a/src/coincontrol.h
+++ b/src/coincontrol.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_COINCONTROL_H
#define BITCOIN_COINCONTROL_H
-#include "core/transaction.h"
+#include "primitives/transaction.h"
/** Coin Control Features. */
class CCoinControl
diff --git a/src/compressor.h b/src/compressor.h
index d9cde5de7a..efb8119d01 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_COMPRESSOR_H
#define BITCOIN_COMPRESSOR_H
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "script/script.h"
#include "serialize.h"
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 42e2f8d200..65c3a08c55 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -4,8 +4,8 @@
#include "core_io.h"
-#include "core/block.h"
-#include "core/transaction.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "script/script.h"
#include "serialize.h"
#include "streams.h"
diff --git a/src/core_write.cpp b/src/core_write.cpp
index a3ae8eec07..760b6a71bf 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -5,7 +5,7 @@
#include "core_io.h"
#include "base58.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "script/script.h"
#include "script/standard.h"
#include "serialize.h"
@@ -129,4 +129,6 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
if (hashBlock != 0)
entry.pushKV("blockhash", hashBlock.GetHex());
+
+ entry.pushKV("hex", EncodeHexTx(tx)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
}
diff --git a/src/init.cpp b/src/init.cpp
index 7b6ebb1b30..11329c16aa 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
@@ -60,7 +60,7 @@ bool fFeeEstimatesInitialized = false;
#define MIN_CORE_FILEDESCRIPTORS 150
#endif
-// Used to pass flags to the Bind() function
+/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0,
BF_EXPLICIT = (1U << 0),
@@ -175,9 +175,9 @@ void Shutdown()
LogPrintf("%s: done\n", __func__);
}
-//
-// Signal handlers are very limited in what they are allowed to do, so:
-//
+/**
+ * Signal handlers are very limited in what they are allowed to do, so:
+ */
void HandleSIGTERM(int)
{
fRequestShutdown = true;
diff --git a/src/init.h b/src/init.h
index aaf8c07e6e..f2f7ac6747 100644
--- a/src/init.h
+++ b/src/init.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_INIT_H
@@ -22,7 +22,7 @@ bool ShutdownRequested();
void Shutdown();
bool AppInit2(boost::thread_group& threadGroup);
-/* The help message mode determines what help message to show */
+/** The help message mode determines what help message to show */
enum HelpMessageMode {
HMM_BITCOIND,
HMM_BITCOIN_QT
diff --git a/src/main.cpp b/src/main.cpp
index 0515eeb156..70e3973e6c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
@@ -11,6 +11,7 @@
#include "checkpoints.h"
#include "checkqueue.h"
#include "init.h"
+#include "merkleblock.h"
#include "net.h"
#include "pow.h"
#include "txdb.h"
@@ -33,9 +34,9 @@ using namespace std;
# error "Bitcoin cannot be compiled without assertions."
#endif
-//
-// Global state
-//
+/**
+ * Global state
+ */
CCriticalSection cs_main;
@@ -66,7 +67,7 @@ map<uint256, COrphanTx> mapOrphanTransactions;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
void EraseOrphansFor(NodeId peer);
-// Constant stuff for coinbase transactions we create:
+/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
const string strMessageMagic = "Bitcoin Signed Message:\n";
@@ -97,44 +98,49 @@ namespace {
CBlockIndex *pindexBestInvalid;
- // The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
- // as good as our current tip. Entries may be failed, though.
+ /**
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
+ * as good as our current tip. Entries may be failed, though.
+ */
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
- // Number of nodes with fSyncStarted.
+ /** Number of nodes with fSyncStarted. */
int nSyncStarted = 0;
- // All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions.
+ /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. */
multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
int nLastBlockFile = 0;
- // Every received block is assigned a unique and increasing identifier, so we
- // know which one to give priority in case of a fork.
+ /**
+ * Every received block is assigned a unique and increasing identifier, so we
+ * know which one to give priority in case of a fork.
+ */
CCriticalSection cs_nBlockSequenceId;
- // Blocks loaded from disk are assigned id 0, so start the counter at 1.
+ /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
uint32_t nBlockSequenceId = 1;
- // Sources of received blocks, to be able to send them reject messages or ban
- // them, if processing happens afterwards. Protected by cs_main.
+ /**
+ * Sources of received blocks, to be able to send them reject messages or ban
+ * them, if processing happens afterwards. Protected by cs_main.
+ */
map<uint256, NodeId> mapBlockSource;
- // Blocks that are in flight, and that are in the queue to be downloaded.
- // Protected by cs_main.
+ /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
- CBlockIndex *pindex; // Optional.
- int64_t nTime; // Time of "getdata" request in microseconds.
+ CBlockIndex *pindex; //! Optional.
+ int64_t nTime; //! Time of "getdata" request in microseconds.
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
- // Number of preferrable block download peers.
+ /** Number of preferable block download peers. */
int nPreferredDownload = 0;
- // Dirty block index entries.
+ /** Dirty block index entries. */
set<CBlockIndex*> setDirtyBlockIndex;
- // Dirty block file entries.
+ /** Dirty block file entries. */
set<int> setDirtyFileInfo;
} // anon namespace
@@ -148,19 +154,19 @@ namespace {
namespace {
struct CMainSignals {
- // Notifies listeners of updated transaction data (transaction, and optionally the block it is found in.
+ /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
- // Notifies listeners of an erased transaction (currently disabled, requires transaction replacement).
+ /** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */
boost::signals2::signal<void (const uint256 &)> EraseTransaction;
- // Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible).
+ /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
- // Notifies listeners of a new active block chain.
+ /** Notifies listeners of a new active block chain. */
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
- // Notifies listeners about an inventory item being seen on the network.
+ /** Notifies listeners about an inventory item being seen on the network. */
boost::signals2::signal<void (const uint256 &)> Inventory;
- // Tells listeners to broadcast their data.
+ /** Tells listeners to broadcast their data. */
boost::signals2::signal<void ()> Broadcast;
- // Notifies listeners of a block validation result
+ /** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
} g_signals;
@@ -213,32 +219,34 @@ struct CBlockReject {
uint256 hashBlock;
};
-// Maintain validation-specific state about nodes, protected by cs_main, instead
-// by CNode's own locks. This simplifies asynchronous operation, where
-// processing of incoming data is done after the ProcessMessage call returns,
-// and we're no longer holding the node's locks.
+/**
+ * Maintain validation-specific state about nodes, protected by cs_main, instead
+ * by CNode's own locks. This simplifies asynchronous operation, where
+ * processing of incoming data is done after the ProcessMessage call returns,
+ * and we're no longer holding the node's locks.
+ */
struct CNodeState {
- // Accumulated misbehaviour score for this peer.
+ //! Accumulated misbehaviour score for this peer.
int nMisbehavior;
- // Whether this peer should be disconnected and banned (unless whitelisted).
+ //! Whether this peer should be disconnected and banned (unless whitelisted).
bool fShouldBan;
- // String name of this peer (debugging/logging purposes).
+ //! String name of this peer (debugging/logging purposes).
std::string name;
- // List of asynchronously-determined block rejections to notify this peer about.
+ //! List of asynchronously-determined block rejections to notify this peer about.
std::vector<CBlockReject> rejects;
- // The best known block we know this peer has announced.
+ //! The best known block we know this peer has announced.
CBlockIndex *pindexBestKnownBlock;
- // The hash of the last unknown block this peer has announced.
+ //! The hash of the last unknown block this peer has announced.
uint256 hashLastUnknownBlock;
- // The last full block we both have.
+ //! The last full block we both have.
CBlockIndex *pindexLastCommonBlock;
- // Whether we've started headers synchronization with this peer.
+ //! Whether we've started headers synchronization with this peer.
bool fSyncStarted;
- // Since when we're stalling block download progress (in microseconds), or 0.
+ //! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight;
- // Whether we consider this a preferred download peer.
+ //! Whether we consider this a preferred download peer.
bool fPreferredDownload;
CNodeState() {
@@ -254,7 +262,7 @@ struct CNodeState {
}
};
-// Map maintaining per-node state. Requires cs_main.
+/** Map maintaining per-node state. Requires cs_main. */
map<NodeId, CNodeState> mapNodeState;
// Requires cs_main.
@@ -708,15 +716,15 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
}
-//
-// Check transaction inputs to mitigate two
-// potential denial-of-service attacks:
-//
-// 1. scriptSigs with extra data stuffed into them,
-// not consumed by scriptPubKey (or P2SH script)
-// 2. P2SH scripts with a crazy number of expensive
-// CHECKSIG/CHECKMULTISIG operations
-//
+/**
+ * Check transaction inputs to mitigate two
+ * potential denial-of-service attacks:
+ *
+ * 1. scriptSigs with extra data stuffed into them,
+ * not consumed by scriptPubKey (or P2SH script)
+ * 2. P2SH scripts with a crazy number of expensive
+ * CHECKSIG/CHECKMULTISIG operations
+ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
@@ -1054,7 +1062,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return true;
}
-// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
+/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
{
CBlockIndex *pindexSlow = NULL;
@@ -1181,7 +1189,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
CAmount GetBlockValue(int nHeight, const CAmount& nFees)
{
- int64_t nSubsidy = 50 * COIN;
+ CAmount nSubsidy = 50 * COIN;
int halvings = nHeight / Params().SubsidyHalvingInterval();
// Force block reward to zero when right shift is undefined.
@@ -1327,7 +1335,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
if (state.IsInvalid(nDoS)) {
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
if (it != mapBlockSource.end() && State(it->second)) {
- CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason(), pindex->GetBlockHash()};
+ CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
State(it->second)->rejects.push_back(reject);
if (nDoS > 0)
Misbehaving(it->second, nDoS);
@@ -1357,10 +1365,11 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
}
-bool CScriptCheck::operator()() const {
+bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore)))
- return error("CScriptCheck() : %s:%d VerifySignature failed", ptxTo->GetHash().ToString(), nIn);
+ if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore), &error)) {
+ return ::error("CScriptCheck() : %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
+ }
return true;
}
@@ -1448,7 +1457,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
CScriptCheck check(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
if (check())
- return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag");
+ return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
// invalid in new blocks, e.g. a invalid P2SH. We DoS ban
@@ -1457,7 +1466,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// as to the correct behavior - we may want to continue
// peering with non-upgraded nodes even after a soft-fork
// super-majority vote has passed.
- return state.DoS(100,false, REJECT_INVALID, "mandatory-script-verify-flag-failed");
+ return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
}
}
}
@@ -1818,7 +1827,7 @@ void FlushStateToDisk() {
FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
}
-// Update chainActive and related internal data structures.
+/** Update chainActive and related internal data structures. */
void static UpdateTip(CBlockIndex *pindexNew) {
chainActive.SetTip(pindexNew);
@@ -1857,7 +1866,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
}
}
-// Disconnect chainActive's tip.
+/** Disconnect chainActive's tip. */
bool static DisconnectTip(CValidationState &state) {
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
@@ -1904,8 +1913,10 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
-// Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
-// corresponding to pindexNew, to bypass loading it again from disk.
+/**
+ * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
+ * corresponding to pindexNew, to bypass loading it again from disk.
+ */
bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) {
assert(pindexNew->pprev == chainActive.Tip());
mempool.check(pcoinsTip);
@@ -1965,8 +1976,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
return true;
}
-// Return the tip of the chain with the most work in it, that isn't
-// known to be invalid (it's however far from certain to be valid).
+/**
+ * Return the tip of the chain with the most work in it, that isn't
+ * known to be invalid (it's however far from certain to be valid).
+ */
static CBlockIndex* FindMostWorkChain() {
do {
CBlockIndex *pindexNew = NULL;
@@ -2007,7 +2020,7 @@ static CBlockIndex* FindMostWorkChain() {
} while(true);
}
-// Delete all entries in setBlockIndexCandidates that are worse than the current tip.
+/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */
static void PruneBlockIndexCandidates() {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
@@ -2019,8 +2032,10 @@ static void PruneBlockIndexCandidates() {
assert(!setBlockIndexCandidates.empty());
}
-// Try to make some progress towards making pindexMostWork the active block.
-// pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
+/**
+ * Try to make some progress towards making pindexMostWork the active block.
+ * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
+ */
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) {
AssertLockHeld(cs_main);
bool fInvalidFound = false;
@@ -2085,9 +2100,11 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
return true;
}
-// Make the best chain active, in multiple steps. The result is either failure
-// or an activated best chain. pblock is either NULL or a pointer to a block
-// that is already loaded (to avoid loading it again from disk).
+/**
+ * Make the best chain active, in multiple steps. The result is either failure
+ * or an activated best chain. pblock is either NULL or a pointer to a block
+ * that is already loaded (to avoid loading it again from disk).
+ */
bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
CBlockIndex *pindexNewTip = NULL;
CBlockIndex *pindexMostWork = NULL;
@@ -2236,7 +2253,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
return pindexNew;
}
-// Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS).
+/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
{
pindexNew->nTx = block.vtx.size();
@@ -2705,159 +2722,6 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
-CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
-{
- header = block.GetBlockHeader();
-
- vector<bool> vMatch;
- vector<uint256> vHashes;
-
- vMatch.reserve(block.vtx.size());
- vHashes.reserve(block.vtx.size());
-
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- {
- const uint256& hash = block.vtx[i].GetHash();
- if (filter.IsRelevantAndUpdate(block.vtx[i]))
- {
- vMatch.push_back(true);
- vMatchedTxn.push_back(make_pair(i, hash));
- }
- else
- vMatch.push_back(false);
- vHashes.push_back(hash);
- }
-
- txn = CPartialMerkleTree(vHashes, vMatch);
-}
-
-
-
-
-
-
-
-
-uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
- if (height == 0) {
- // hash at height 0 is the txids themself
- return vTxid[pos];
- } else {
- // calculate left hash
- uint256 left = CalcHash(height-1, pos*2, vTxid), right;
- // calculate right hash if not beyong the end of the array - copy left hash otherwise1
- if (pos*2+1 < CalcTreeWidth(height-1))
- right = CalcHash(height-1, pos*2+1, vTxid);
- else
- right = left;
- // combine subhashes
- return Hash(BEGIN(left), END(left), BEGIN(right), END(right));
- }
-}
-
-void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) {
- // determine whether this node is the parent of at least one matched txid
- bool fParentOfMatch = false;
- for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++)
- fParentOfMatch |= vMatch[p];
- // store as flag bit
- vBits.push_back(fParentOfMatch);
- if (height==0 || !fParentOfMatch) {
- // if at height 0, or nothing interesting below, store hash and stop
- vHash.push_back(CalcHash(height, pos, vTxid));
- } else {
- // otherwise, don't store any hash, but descend into the subtrees
- TraverseAndBuild(height-1, pos*2, vTxid, vMatch);
- if (pos*2+1 < CalcTreeWidth(height-1))
- TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch);
- }
-}
-
-uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch) {
- if (nBitsUsed >= vBits.size()) {
- // overflowed the bits array - failure
- fBad = true;
- return 0;
- }
- bool fParentOfMatch = vBits[nBitsUsed++];
- if (height==0 || !fParentOfMatch) {
- // if at height 0, or nothing interesting below, use stored hash and do not descend
- if (nHashUsed >= vHash.size()) {
- // overflowed the hash array - failure
- fBad = true;
- return 0;
- }
- const uint256 &hash = vHash[nHashUsed++];
- if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid
- vMatch.push_back(hash);
- return hash;
- } else {
- // otherwise, descend into the subtrees to extract matched txids and hashes
- uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right;
- if (pos*2+1 < CalcTreeWidth(height-1))
- right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch);
- else
- right = left;
- // and combine them before returning
- return Hash(BEGIN(left), END(left), BEGIN(right), END(right));
- }
-}
-
-CPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) {
- // reset state
- vBits.clear();
- vHash.clear();
-
- // calculate height of tree
- int nHeight = 0;
- while (CalcTreeWidth(nHeight) > 1)
- nHeight++;
-
- // traverse the partial tree
- TraverseAndBuild(nHeight, 0, vTxid, vMatch);
-}
-
-CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
-
-uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
- vMatch.clear();
- // An empty set will not work
- if (nTransactions == 0)
- return 0;
- // check for excessively high numbers of transactions
- if (nTransactions > MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
- return 0;
- // there can never be more hashes provided than one for every txid
- if (vHash.size() > nTransactions)
- return 0;
- // there must be at least one bit per node in the partial tree, and at least one node per hash
- if (vBits.size() < vHash.size())
- return 0;
- // calculate height of tree
- int nHeight = 0;
- while (CalcTreeWidth(nHeight) > 1)
- nHeight++;
- // traverse the partial tree
- unsigned int nBitsUsed = 0, nHashUsed = 0;
- uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
- // verify that no problems occured during the tree traversal
- if (fBad)
- return 0;
- // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
- if ((nBitsUsed+7)/8 != (vBits.size()+7)/8)
- return 0;
- // verify that all hashes were consumed
- if (nHashUsed != vHash.size())
- return 0;
- return hashMerkleRoot;
-}
-
-
-
-
-
-
-
bool AbortNode(const std::string &strMessage, const std::string &userMessage) {
strMiscWarning = strMessage;
LogPrintf("*** %s\n", strMessage);
@@ -3975,7 +3839,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->id, pfrom->cleanSubVer,
state.GetRejectReason());
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
- state.GetRejectReason(), inv.hash);
+ state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS);
}
@@ -4049,7 +3913,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS;
if (state.IsInvalid(nDoS)) {
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
- state.GetRejectReason(), inv.hash);
+ state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) {
LOCK(cs_main);
Misbehaving(pfrom->GetId(), nDoS);
@@ -4256,7 +4120,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (fDebug) {
try {
string strMsg; unsigned char ccode; string strReason;
- vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111);
+ vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);
ostringstream ss;
ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
diff --git a/src/main.h b/src/main.h
index caf8331ee1..8f0378647d 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MAIN_H
@@ -14,8 +14,8 @@
#include "chain.h"
#include "chainparams.h"
#include "coins.h"
-#include "core/block.h"
-#include "core/transaction.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "net.h"
#include "pow.h"
#include "script/script.h"
@@ -49,8 +49,6 @@ class CValidationState;
struct CBlockTemplate;
struct CNodeStateStats;
-/** The maximum allowed size for a serialized block, in bytes (network rule) */
-static const unsigned int MAX_BLOCK_SIZE = 1000000;
/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
@@ -60,7 +58,7 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
-/** Maxiumum number of signature check operations in an IsStandard() P2SH script */
+/** 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;
@@ -96,8 +94,10 @@ static const unsigned int MAX_HEADERS_RESULTS = 2000;
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** Time to wait (in seconds) between writing blockchain state to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 3600;
+/** Maximum length of reject messages. */
+static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
-/** "reject" message codes **/
+/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
static const unsigned char REJECT_INVALID = 0x10;
static const unsigned char REJECT_OBSOLETE = 0x11;
@@ -131,10 +131,10 @@ extern bool fIsBareMultisigStd;
extern unsigned int nCoinCacheSize;
extern CFeeRate minRelayTxFee;
-// Best header we've seen so far (used for getheaders queries' starting points).
+/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
-// Minimum disk space required - used in CheckDiskSpace()
+/** Minimum disk space required - used in CheckDiskSpace() */
static const uint64_t nMinDiskSpace = 52428800;
/** Register a wallet to receive updates from core */
@@ -151,15 +151,17 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
-/** Process an incoming block. This only returns after the best known valid
- block is made active. Note that it does not, however, guarantee that the
- specific block passed to it has been checked for validity!
- @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state iff pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation.
- @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
- @param[in] pblock The block we want to process.
- @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
- @return True if state.IsValid()
-*/
+/**
+ * Process an incoming block. This only returns after the best known valid
+ * block is made active. Note that it does not, however, guarantee that the
+ * specific block passed to it has been checked for validity!
+ *
+ * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation.
+ * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
+ * @param[in] pblock The block we want to process.
+ * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
+ * @return True if state.IsValid()
+ */
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
@@ -245,54 +247,59 @@ struct CDiskTxPos : public CDiskBlockPos
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-//
-// Check transaction inputs, and make sure any
-// pay-to-script-hash transactions are evaluating IsStandard scripts
-//
-// Why bother? To avoid denial-of-service attacks; an attacker
-// can submit a standard HASH... OP_EQUAL transaction,
-// which will get accepted into blocks. The redemption
-// script can be anything; an attacker could use a very
-// expensive-to-check-upon-redemption script like:
-// DUP CHECKSIG DROP ... repeated 100 times... OP_1
-//
+/**
+ * Check transaction inputs, and make sure any
+ * pay-to-script-hash transactions are evaluating IsStandard scripts
+ *
+ * Why bother? To avoid denial-of-service attacks; an attacker
+ * can submit a standard HASH... OP_EQUAL transaction,
+ * which will get accepted into blocks. The redemption
+ * script can be anything; an attacker could use a very
+ * expensive-to-check-upon-redemption script like:
+ * DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ */
-/** Check for standard transaction types
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
- @return True if all inputs (scriptSigs) use only standard transaction forms
-*/
+/**
+ * Check for standard transaction types
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return True if all inputs (scriptSigs) use only standard transaction forms
+ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
- @return number of sigops this transaction's outputs will produce when spent
- @see CTransaction::FetchInputs
-*/
+/**
+ * Count ECDSA signature operations the old-fashioned (pre-0.6) way
+ * @return number of sigops this transaction's outputs will produce when spent
+ * @see CTransaction::FetchInputs
+ */
unsigned int GetLegacySigOpCount(const CTransaction& tx);
-/** Count ECDSA signature operations in pay-to-script-hash inputs.
-
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
- @return maximum number of sigops required to validate this transaction's inputs
- @see CTransaction::FetchInputs
+/**
+ * Count ECDSA signature operations in pay-to-script-hash inputs.
+ *
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return maximum number of sigops required to validate this transaction's inputs
+ * @see CTransaction::FetchInputs
*/
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
-// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
-// instead of being performed inline.
+/**
+ * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
+ * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
+ * instead of being performed inline.
+ */
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
-// Apply the effects of this transaction on the UTXO set represented by view
+/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight);
-// Context-independent validity checks
+/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
/** Check for standard transaction types
- @return True if all outputs (scriptPubKeys) use only standard transaction forms
-*/
+ * @return True if all outputs (scriptPubKeys) use only standard transaction forms
+ */
bool IsStandardTx(const CTransaction& tx, std::string& reason);
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
@@ -315,8 +322,10 @@ public:
};
-/** Closure representing one script verification
- * Note that this stores references to the spending transaction */
+/**
+ * Closure representing one script verification
+ * Note that this stores references to the spending transaction
+ */
class CScriptCheck
{
private:
@@ -325,14 +334,15 @@ private:
unsigned int nIn;
unsigned int nFlags;
bool cacheStore;
+ ScriptError error;
public:
- CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false) {}
+ CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
- bool operator()() const;
+ bool operator()();
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
@@ -340,110 +350,13 @@ public:
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
+ std::swap(error, check.error);
}
-};
-/** Data structure that represents a partial merkle tree.
- *
- * It respresents a subset of the txid's of a known block, in a way that
- * allows recovery of the list of txid's and the merkle root, in an
- * authenticated way.
- *
- * The encoding works as follows: we traverse the tree in depth-first order,
- * storing a bit for each traversed node, signifying whether the node is the
- * parent of at least one matched leaf txid (or a matched txid itself). In
- * case we are at the leaf level, or this bit is 0, its merkle node hash is
- * stored, and its children are not explorer further. Otherwise, no hash is
- * stored, but we recurse into both (or the only) child branch. During
- * decoding, the same depth-first traversal is performed, consuming bits and
- * hashes as they written during encoding.
- *
- * The serialization is fixed and provides a hard guarantee about the
- * encoded size:
- *
- * SIZE <= 10 + ceil(32.25*N)
- *
- * Where N represents the number of leaf nodes of the partial tree. N itself
- * is bounded by:
- *
- * N <= total_transactions
- * N <= 1 + matched_transactions*tree_height
- *
- * The serialization format:
- * - uint32 total_transactions (4 bytes)
- * - varint number of hashes (1-3 bytes)
- * - uint256[] hashes in depth-first order (<= 32*N bytes)
- * - varint number of bytes of flag bits (1-3 bytes)
- * - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
- * The size constraints follow from this.
- */
-class CPartialMerkleTree
-{
-protected:
- // the total number of transactions in the block
- unsigned int nTransactions;
-
- // node-is-parent-of-matched-txid bits
- std::vector<bool> vBits;
-
- // txids and internal hashes
- std::vector<uint256> vHash;
-
- // flag set when encountering invalid data
- bool fBad;
-
- // helper function to efficiently calculate the number of nodes at given height in the merkle tree
- unsigned int CalcTreeWidth(int height) {
- return (nTransactions+(1 << height)-1) >> height;
- }
-
- // calculate the hash of a node in the merkle tree (at leaf level: the txid's themself)
- uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
-
- // recursive function that traverses tree nodes, storing the data as bits and hashes
- void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
-
- // recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
- // it returns the hash of the respective node.
- uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
-
-public:
-
- // serialization implementation
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(nTransactions);
- READWRITE(vHash);
- std::vector<unsigned char> vBytes;
- if (ser_action.ForRead()) {
- READWRITE(vBytes);
- CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
- us.vBits.resize(vBytes.size() * 8);
- for (unsigned int p = 0; p < us.vBits.size(); p++)
- us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
- us.fBad = false;
- } else {
- vBytes.resize((vBits.size()+7)/8);
- for (unsigned int p = 0; p < vBits.size(); p++)
- vBytes[p / 8] |= vBits[p] << (p % 8);
- READWRITE(vBytes);
- }
- }
-
- // Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them
- CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
-
- CPartialMerkleTree();
-
- // extract the matching txid's represented by this partial merkle tree.
- // returns the merkle root, or 0 in case of failure
- uint256 ExtractMatches(std::vector<uint256> &vMatch);
+ ScriptError GetScriptError() const { return error; }
};
-
/** Functions for disk access for blocks */
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
@@ -458,22 +371,21 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
* of problems. Note that in any case, coins may be modified. */
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
-// Apply the effects of this block (with given index) on the UTXO set represented by coins
+/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
-// Context-independent validity checks
+/** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-// Context-dependent validity checks
+/** Context-dependent validity checks */
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev);
bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev);
-// Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held)
+/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-// Store block on disk
-// if dbp is provided, the file is known to already reside on disk
+/** Store block on disk. If dbp is provided, the file is known to already reside on disk */
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
@@ -482,13 +394,13 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
class CBlockFileInfo
{
public:
- unsigned int nBlocks; // number of blocks stored in file
- unsigned int nSize; // number of used bytes of block file
- unsigned int nUndoSize; // number of used bytes in the undo file
- unsigned int nHeightFirst; // lowest height of block in file
- unsigned int nHeightLast; // highest height of block in file
- uint64_t nTimeFirst; // earliest time of block in file
- uint64_t nTimeLast; // latest time of block in file
+ unsigned int nBlocks; //! number of blocks stored in file
+ unsigned int nSize; //! number of used bytes of block file
+ unsigned int nUndoSize; //! number of used bytes in the undo file
+ unsigned int nHeightFirst; //! lowest height of block in file
+ unsigned int nHeightLast; //! highest height of block in file
+ uint64_t nTimeFirst; //! earliest time of block in file
+ uint64_t nTimeLast; //! latest time of block in file
ADD_SERIALIZE_METHODS;
@@ -519,7 +431,7 @@ public:
std::string ToString() const;
- // update statistics (does not update nSize)
+ /** update statistics (does not update nSize) */
void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
if (nBlocks==0 || nHeightFirst > nHeightIn)
nHeightFirst = nHeightIn;
@@ -537,9 +449,9 @@ public:
class CValidationState {
private:
enum mode_state {
- MODE_VALID, // everything ok
- MODE_INVALID, // network rule violation (DoS value may be set)
- MODE_ERROR, // run-time error
+ MODE_VALID, //! everything ok
+ MODE_INVALID, //! network rule violation (DoS value may be set)
+ MODE_ERROR, //! run-time error
} mode;
int nDoS;
std::string strRejectReason;
@@ -634,36 +546,6 @@ struct CBlockTemplate
-/** Used to relay blocks as header + vector<merkle branch>
- * to filtered nodes.
- */
-class CMerkleBlock
-{
-public:
- // Public only for unit testing
- CBlockHeader header;
- CPartialMerkleTree txn;
-
-public:
- // Public only for unit testing and relay testing
- // (not relayed)
- std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
-
- // Create from a CBlock, filtering transactions according to filter
- // Note that this will call IsRelevantAndUpdate on the filter for each transaction,
- // thus the filter will likely be modified.
- CMerkleBlock(const CBlock& block, CBloomFilter& filter);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(header);
- READWRITE(txn);
- }
-};
-
-
class CValidationInterface {
protected:
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {};
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
new file mode 100644
index 0000000000..8618e355d7
--- /dev/null
+++ b/src/merkleblock.cpp
@@ -0,0 +1,152 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "merkleblock.h"
+
+#include "hash.h"
+#include "primitives/block.h" // for MAX_BLOCK_SIZE
+#include "utilstrencodings.h"
+
+using namespace std;
+
+CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
+{
+ header = block.GetBlockHeader();
+
+ vector<bool> vMatch;
+ vector<uint256> vHashes;
+
+ vMatch.reserve(block.vtx.size());
+ vHashes.reserve(block.vtx.size());
+
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
+ {
+ const uint256& hash = block.vtx[i].GetHash();
+ if (filter.IsRelevantAndUpdate(block.vtx[i]))
+ {
+ vMatch.push_back(true);
+ vMatchedTxn.push_back(make_pair(i, hash));
+ }
+ else
+ vMatch.push_back(false);
+ vHashes.push_back(hash);
+ }
+
+ txn = CPartialMerkleTree(vHashes, vMatch);
+}
+
+uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
+ if (height == 0) {
+ // hash at height 0 is the txids themself
+ return vTxid[pos];
+ } else {
+ // calculate left hash
+ uint256 left = CalcHash(height-1, pos*2, vTxid), right;
+ // calculate right hash if not beyond the end of the array - copy left hash otherwise1
+ if (pos*2+1 < CalcTreeWidth(height-1))
+ right = CalcHash(height-1, pos*2+1, vTxid);
+ else
+ right = left;
+ // combine subhashes
+ return Hash(BEGIN(left), END(left), BEGIN(right), END(right));
+ }
+}
+
+void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) {
+ // determine whether this node is the parent of at least one matched txid
+ bool fParentOfMatch = false;
+ for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++)
+ fParentOfMatch |= vMatch[p];
+ // store as flag bit
+ vBits.push_back(fParentOfMatch);
+ if (height==0 || !fParentOfMatch) {
+ // if at height 0, or nothing interesting below, store hash and stop
+ vHash.push_back(CalcHash(height, pos, vTxid));
+ } else {
+ // otherwise, don't store any hash, but descend into the subtrees
+ TraverseAndBuild(height-1, pos*2, vTxid, vMatch);
+ if (pos*2+1 < CalcTreeWidth(height-1))
+ TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch);
+ }
+}
+
+uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch) {
+ if (nBitsUsed >= vBits.size()) {
+ // overflowed the bits array - failure
+ fBad = true;
+ return 0;
+ }
+ bool fParentOfMatch = vBits[nBitsUsed++];
+ if (height==0 || !fParentOfMatch) {
+ // if at height 0, or nothing interesting below, use stored hash and do not descend
+ if (nHashUsed >= vHash.size()) {
+ // overflowed the hash array - failure
+ fBad = true;
+ return 0;
+ }
+ const uint256 &hash = vHash[nHashUsed++];
+ if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid
+ vMatch.push_back(hash);
+ return hash;
+ } else {
+ // otherwise, descend into the subtrees to extract matched txids and hashes
+ uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right;
+ if (pos*2+1 < CalcTreeWidth(height-1))
+ right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch);
+ else
+ right = left;
+ // and combine them before returning
+ return Hash(BEGIN(left), END(left), BEGIN(right), END(right));
+ }
+}
+
+CPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) {
+ // reset state
+ vBits.clear();
+ vHash.clear();
+
+ // calculate height of tree
+ int nHeight = 0;
+ while (CalcTreeWidth(nHeight) > 1)
+ nHeight++;
+
+ // traverse the partial tree
+ TraverseAndBuild(nHeight, 0, vTxid, vMatch);
+}
+
+CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
+
+uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
+ vMatch.clear();
+ // An empty set will not work
+ if (nTransactions == 0)
+ return 0;
+ // check for excessively high numbers of transactions
+ if (nTransactions > MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
+ return 0;
+ // there can never be more hashes provided than one for every txid
+ if (vHash.size() > nTransactions)
+ return 0;
+ // there must be at least one bit per node in the partial tree, and at least one node per hash
+ if (vBits.size() < vHash.size())
+ return 0;
+ // calculate height of tree
+ int nHeight = 0;
+ while (CalcTreeWidth(nHeight) > 1)
+ nHeight++;
+ // traverse the partial tree
+ unsigned int nBitsUsed = 0, nHashUsed = 0;
+ uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
+ // verify that no problems occured during the tree traversal
+ if (fBad)
+ return 0;
+ // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
+ if ((nBitsUsed+7)/8 != (vBits.size()+7)/8)
+ return 0;
+ // verify that all hashes were consumed
+ if (nHashUsed != vHash.size())
+ return 0;
+ return hashMerkleRoot;
+}
diff --git a/src/merkleblock.h b/src/merkleblock.h
new file mode 100644
index 0000000000..c549e3cdba
--- /dev/null
+++ b/src/merkleblock.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_MERKLEBLOCK_H
+#define BITCOIN_MERKLEBLOCK_H
+
+#include "serialize.h"
+#include "uint256.h"
+#include "primitives/block.h"
+#include "bloom.h"
+
+#include <vector>
+
+/** Data structure that represents a partial merkle tree.
+ *
+ * It represents a subset of the txid's of a known block, in a way that
+ * allows recovery of the list of txid's and the merkle root, in an
+ * authenticated way.
+ *
+ * The encoding works as follows: we traverse the tree in depth-first order,
+ * storing a bit for each traversed node, signifying whether the node is the
+ * parent of at least one matched leaf txid (or a matched txid itself). In
+ * case we are at the leaf level, or this bit is 0, its merkle node hash is
+ * stored, and its children are not explorer further. Otherwise, no hash is
+ * stored, but we recurse into both (or the only) child branch. During
+ * decoding, the same depth-first traversal is performed, consuming bits and
+ * hashes as they written during encoding.
+ *
+ * The serialization is fixed and provides a hard guarantee about the
+ * encoded size:
+ *
+ * SIZE <= 10 + ceil(32.25*N)
+ *
+ * Where N represents the number of leaf nodes of the partial tree. N itself
+ * is bounded by:
+ *
+ * N <= total_transactions
+ * N <= 1 + matched_transactions*tree_height
+ *
+ * The serialization format:
+ * - uint32 total_transactions (4 bytes)
+ * - varint number of hashes (1-3 bytes)
+ * - uint256[] hashes in depth-first order (<= 32*N bytes)
+ * - varint number of bytes of flag bits (1-3 bytes)
+ * - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
+ * The size constraints follow from this.
+ */
+class CPartialMerkleTree
+{
+protected:
+ /** the total number of transactions in the block */
+ unsigned int nTransactions;
+
+ /** node-is-parent-of-matched-txid bits */
+ std::vector<bool> vBits;
+
+ /** txids and internal hashes */
+ std::vector<uint256> vHash;
+
+ /** flag set when encountering invalid data */
+ bool fBad;
+
+ /** helper function to efficiently calculate the number of nodes at given height in the merkle tree */
+ unsigned int CalcTreeWidth(int height) {
+ return (nTransactions+(1 << height)-1) >> height;
+ }
+
+ /** calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves) */
+ uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
+
+ /** recursive function that traverses tree nodes, storing the data as bits and hashes */
+ void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
+
+ /**
+ * recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
+ * it returns the hash of the respective node.
+ */
+ uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
+
+public:
+
+ /** serialization implementation */
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(nTransactions);
+ READWRITE(vHash);
+ std::vector<unsigned char> vBytes;
+ if (ser_action.ForRead()) {
+ READWRITE(vBytes);
+ CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
+ us.vBits.resize(vBytes.size() * 8);
+ for (unsigned int p = 0; p < us.vBits.size(); p++)
+ us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
+ us.fBad = false;
+ } else {
+ vBytes.resize((vBits.size()+7)/8);
+ for (unsigned int p = 0; p < vBits.size(); p++)
+ vBytes[p / 8] |= vBits[p] << (p % 8);
+ READWRITE(vBytes);
+ }
+ }
+
+ /** Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them */
+ CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
+
+ CPartialMerkleTree();
+
+ /**
+ * extract the matching txid's represented by this partial merkle tree.
+ * returns the merkle root, or 0 in case of failure
+ */
+ uint256 ExtractMatches(std::vector<uint256> &vMatch);
+};
+
+
+/**
+ * Used to relay blocks as header + vector<merkle branch>
+ * to filtered nodes.
+ */
+class CMerkleBlock
+{
+public:
+ /** Public only for unit testing */
+ CBlockHeader header;
+ CPartialMerkleTree txn;
+
+public:
+ /** Public only for unit testing and relay testing (not relayed) */
+ std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
+
+ /**
+ * Create from a CBlock, filtering transactions according to filter
+ * Note that this will call IsRelevantAndUpdate on the filter for each transaction,
+ * thus the filter will likely be modified.
+ */
+ CMerkleBlock(const CBlock& block, CBloomFilter& filter);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(header);
+ READWRITE(txn);
+ }
+};
+
+#endif // BITCOIN_MERKLEBLOCK_H
diff --git a/src/miner.cpp b/src/miner.cpp
index 660173f35b..ad29431421 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -6,8 +6,8 @@
#include "miner.h"
#include "amount.h"
-#include "core/block.h"
-#include "core/transaction.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "hash.h"
#include "main.h"
#include "net.h"
diff --git a/src/net.cpp b/src/net.cpp
index 6bf72d22c5..42b3c30fb7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -12,7 +12,7 @@
#include "addrman.h"
#include "chainparams.h"
#include "clientversion.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "ui_interface.h"
#ifdef WIN32
@@ -399,7 +399,9 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
// Connect
SOCKET hSocket;
- if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort()) : ConnectSocket(addrConnect, hSocket))
+ bool proxyConnectionFailed = false;
+ if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :
+ ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed))
{
addrman.Attempt(addrConnect);
@@ -415,6 +417,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
pnode->nTimeConnected = GetTime();
return pnode;
+ } else if (!proxyConnectionFailed) {
+ // If connecting to the node failed, and failure is not caused by a problem connecting to
+ // the proxy, mark this as an attempt.
+ addrman.Attempt(addrConnect);
}
return NULL;
diff --git a/src/net.h b/src/net.h
index e48acf5644..a475be0b33 100644
--- a/src/net.h
+++ b/src/net.h
@@ -44,6 +44,8 @@ static const int PING_INTERVAL = 2 * 60;
static const int TIMEOUT_INTERVAL = 20 * 60;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
+/** The maximum number of new addresses to accumulate before announcing. */
+static const unsigned int MAX_ADDR_TO_SEND = 1000;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@@ -368,8 +370,13 @@ public:
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
- if (addr.IsValid() && !setAddrKnown.count(addr))
- vAddrToSend.push_back(addr);
+ if (addr.IsValid() && !setAddrKnown.count(addr)) {
+ if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
+ vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr;
+ } else {
+ vAddrToSend.push_back(addr);
+ }
+ }
}
diff --git a/src/netbase.cpp b/src/netbase.cpp
index aca5a107fe..053c645a1b 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -519,9 +519,11 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
+bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
{
proxyType proxy;
+ if (outProxyConnectionFailed)
+ *outProxyConnectionFailed = false;
// no proxy needed (none set for target network)
if (!GetProxy(addrDest.GetNetwork(), proxy))
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
@@ -529,8 +531,11 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy, hSocket, nTimeout))
+ if (!ConnectSocketDirectly(proxy, hSocket, nTimeout)) {
+ if (outProxyConnectionFailed)
+ *outProxyConnectionFailed = true;
return false;
+ }
// do socks negotiation
if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
@@ -539,10 +544,14 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
return true;
}
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
+bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
{
string strDest;
int port = portDefault;
+
+ if (outProxyConnectionFailed)
+ *outProxyConnectionFailed = false;
+
SplitHostPort(string(pszDest), port, strDest);
SOCKET hSocket = INVALID_SOCKET;
@@ -561,8 +570,11 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
if (!HaveNameProxy())
return false;
// first connect to name proxy server
- if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout))
+ if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout)) {
+ if (outProxyConnectionFailed)
+ *outProxyConnectionFailed = true;
return false;
+ }
// do socks negotiation
if (!Socks5(strDest, (unsigned short)port, hSocket))
return false;
diff --git a/src/netbase.h b/src/netbase.h
index 9d8697dcc6..09fe094946 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -182,8 +182,8 @@ bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nM
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true);
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0);
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
-bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout);
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
+bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed = 0);
+bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed = 0);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
/** Close socket and set hSocket to INVALID_SOCKET */
diff --git a/src/pow.cpp b/src/pow.cpp
index e07e7ff770..bdcfa852f4 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -7,7 +7,7 @@
#include "chain.h"
#include "chainparams.h"
-#include "core/block.h"
+#include "primitives/block.h"
#include "uint256.h"
#include "util.h"
diff --git a/src/core/block.cpp b/src/primitives/block.cpp
index 2010d44dac..225bb80be8 100644
--- a/src/core/block.cpp
+++ b/src/primitives/block.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core/block.h"
+#include "primitives/block.h"
#include "hash.h"
#include "tinyformat.h"
diff --git a/src/core/block.h b/src/primitives/block.h
index 6e119c3699..a189592539 100644
--- a/src/core/block.h
+++ b/src/primitives/block.h
@@ -3,13 +3,16 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_CORE_BLOCK_H
-#define BITCOIN_CORE_BLOCK_H
+#ifndef BITCOIN_PRIMITIVES_BLOCK_H
+#define BITCOIN_PRIMITIVES_BLOCK_H
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "serialize.h"
#include "uint256.h"
+/** The maximum allowed size for a serialized block, in bytes (network rule) */
+static const unsigned int MAX_BLOCK_SIZE = 1000000;
+
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
@@ -165,4 +168,4 @@ struct CBlockLocator
}
};
-#endif // BITCOIN_CORE_BLOCK_H
+#endif // BITCOIN_PRIMITIVES_BLOCK_H
diff --git a/src/core/transaction.cpp b/src/primitives/transaction.cpp
index f835bafb9f..336151905c 100644
--- a/src/core/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "hash.h"
#include "tinyformat.h"
diff --git a/src/core/transaction.h b/src/primitives/transaction.h
index 724348020a..a7a1e013ed 100644
--- a/src/core/transaction.h
+++ b/src/primitives/transaction.h
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_CORE_TRANSACTION_H
-#define BITCOIN_CORE_TRANSACTION_H
+#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
+#define BITCOIN_PRIMITIVES_TRANSACTION_H
#include "amount.h"
#include "script/script.h"
@@ -273,4 +273,4 @@ struct CMutableTransaction
uint256 GetHash() const;
};
-#endif // BITCOIN_CORE_TRANSACTION_H
+#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 9872ebc1f6..123777a71b 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -570,9 +570,9 @@ int main(int argc, char *argv[])
}
#ifdef ENABLE_WALLET
// Parse URIs on command line -- this can affect Params()
- if (!PaymentServer::ipcParseCommandLine(argc, argv))
- exit(0);
+ PaymentServer::ipcParseCommandLine(argc, argv);
#endif
+
QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
assert(!networkStyle.isNull());
// Allow for separate UI settings for testnets
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 75e1f9ae78..5c542b59ae 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -4,7 +4,7 @@
#include "bitcoinunits.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include <QStringList>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index f23175049a..8f3e476fd9 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -38,9 +38,6 @@ static const int TOOLTIP_WRAP_THRESHOLD = 80;
/* Maximum allowed URI length */
static const int MAX_URI_LENGTH = 255;
-/* Maximum somewhat-sane size of a payment request file */
-static const int MAX_PAYMENT_REQUEST_SIZE = 50000; // bytes
-
/* QRCodeDialog -- size of exported QR Code image */
#define EXPORT_IMAGE_SIZE 256
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 22a1f019e9..a1ae756c43 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -9,7 +9,7 @@
#include "qvalidatedlineedit.h"
#include "walletmodel.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "init.h"
#include "main.h"
#include "protocol.h"
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 7aefffe24a..a40b5bbcd8 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -1,5 +1,5 @@
-// Copyright (c) 2011-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2011-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index 91c704c520..fbc3a09265 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -1,5 +1,5 @@
-// Copyright (c) 2011-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2011-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_PAYMENTREQUESTPLUS_H
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 707de55290..bd3dab41a8 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -1,11 +1,10 @@
-// Copyright (c) 2011-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2011-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "paymentserver.h"
#include "bitcoinunits.h"
-#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
@@ -19,6 +18,7 @@
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
+
#include <QApplication>
#include <QByteArray>
#include <QDataStream>
@@ -46,14 +46,20 @@
#include <QUrlQuery>
#endif
-using namespace std;
using namespace boost;
+using namespace std;
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
-const char* BITCOIN_REQUEST_MIMETYPE = "application/bitcoin-paymentrequest";
-const char* BITCOIN_PAYMENTACK_MIMETYPE = "application/bitcoin-paymentack";
-const char* BITCOIN_PAYMENTACK_CONTENTTYPE = "application/bitcoin-payment";
+// BIP70 payment protocol messages
+const char* BIP70_MESSAGE_PAYMENTACK = "PaymentACK";
+const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
+// BIP71 payment protocol media types
+const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
+const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
+const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
+// BIP70 max payment request size in bytes (DoS protection)
+const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
X509_STORE* PaymentServer::certStore = NULL;
void PaymentServer::freeCertStore()
@@ -184,7 +190,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// Warning: ipcSendCommandLine() is called early in init,
// so don't use "emit message()", but "QMessageBox::"!
//
-bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
+void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
for (int i = 1; i < argc; i++)
{
@@ -192,6 +198,10 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
if (arg.startsWith("-"))
continue;
+ // If the bitcoin: URI contains a payment request, we are not able to detect the
+ // network as that would require fetching and parsing the payment request.
+ // That means clicking such an URI which contains a testnet payment request
+ // will start a mainnet instance and throw a "wrong network" error.
if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI
{
savedPaymentRequests.append(arg);
@@ -216,7 +226,7 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
savedPaymentRequests.append(arg);
PaymentRequestPlus request;
- if (readPaymentRequest(arg, request))
+ if (readPaymentRequestFromFile(arg, request))
{
if (request.getDetails().network() == "main")
{
@@ -235,7 +245,6 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
qWarning() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
}
}
- return true;
}
//
@@ -254,6 +263,7 @@ bool PaymentServer::ipcSendCommandLine()
if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))
{
delete socket;
+ socket = NULL;
return false;
}
@@ -262,12 +272,14 @@ bool PaymentServer::ipcSendCommandLine()
out.setVersion(QDataStream::Qt_4_0);
out << r;
out.device()->seek(0);
+
socket->write(block);
socket->flush();
-
socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT);
socket->disconnectFromServer();
+
delete socket;
+ socket = NULL;
fResult = true;
}
@@ -440,7 +452,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
PaymentRequestPlus request;
SendCoinsRecipient recipient;
- if (!readPaymentRequest(s, request))
+ if (!readPaymentRequestFromFile(s, request))
{
emit message(tr("Payment request file handling"),
tr("Payment request file cannot be read! This can be caused by an invalid payment request file."),
@@ -474,18 +486,25 @@ void PaymentServer::handleURIConnection()
handleURIOrFile(msg);
}
-bool PaymentServer::readPaymentRequest(const QString& filename, PaymentRequestPlus& request)
+//
+// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
+// so don't use "emit message()", but "QMessageBox::"!
+//
+bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request)
{
QFile f(filename);
- if (!f.open(QIODevice::ReadOnly))
- {
- qWarning() << "PaymentServer::readPaymentRequest : Failed to open " << filename;
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning() << QString("PaymentServer::%1: Failed to open %2").arg(__func__).arg(filename);
return false;
}
- if (f.size() > MAX_PAYMENT_REQUEST_SIZE)
- {
- qWarning() << "PaymentServer::readPaymentRequest : " << filename << " too large";
+ // BIP70 DoS protection
+ if (f.size() > BIP70_MAX_PAYMENTREQUEST_SIZE) {
+ qWarning() << QString("PaymentServer::%1: Payment request %2 is too large (%3 bytes, allowed %4 bytes).")
+ .arg(__func__)
+ .arg(filename)
+ .arg(f.size())
+ .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
return false;
}
@@ -580,10 +599,10 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
void PaymentServer::fetchRequest(const QUrl& url)
{
QNetworkRequest netRequest;
- netRequest.setAttribute(QNetworkRequest::User, "PaymentRequest");
+ netRequest.setAttribute(QNetworkRequest::User, BIP70_MESSAGE_PAYMENTREQUEST);
netRequest.setUrl(url);
netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
- netRequest.setRawHeader("Accept", BITCOIN_REQUEST_MIMETYPE);
+ netRequest.setRawHeader("Accept", BIP71_MIMETYPE_PAYMENTREQUEST);
netManager->get(netRequest);
}
@@ -594,11 +613,11 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
return;
QNetworkRequest netRequest;
- netRequest.setAttribute(QNetworkRequest::User, "PaymentACK");
+ netRequest.setAttribute(QNetworkRequest::User, BIP70_MESSAGE_PAYMENTACK);
netRequest.setUrl(QString::fromStdString(details.payment_url()));
- netRequest.setHeader(QNetworkRequest::ContentTypeHeader, BITCOIN_PAYMENTACK_CONTENTTYPE);
+ netRequest.setHeader(QNetworkRequest::ContentTypeHeader, BIP71_MIMETYPE_PAYMENT);
netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
- netRequest.setRawHeader("Accept", BITCOIN_PAYMENTACK_MIMETYPE);
+ netRequest.setRawHeader("Accept", BIP71_MIMETYPE_PAYMENTACK);
payments::Payment payment;
payment.set_merchant_data(details.merchant_data());
@@ -616,7 +635,6 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
else {
CPubKey newKey;
if (wallet->GetKeyFromPool(newKey)) {
- LOCK(wallet->cs_wallet); // SetAddressBook
CKeyID keyID = newKey.GetID();
wallet->SetAddressBook(keyID, strAccount, "refund");
@@ -646,13 +664,26 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
void PaymentServer::netRequestFinished(QNetworkReply* reply)
{
reply->deleteLater();
- if (reply->error() != QNetworkReply::NoError)
- {
+
+ // BIP70 DoS protection
+ if (reply->size() > BIP70_MAX_PAYMENTREQUEST_SIZE) {
+ QString msg = tr("Payment request %2 is too large (%3 bytes, allowed %4 bytes).")
+ .arg(__func__)
+ .arg(reply->request().url().toString())
+ .arg(reply->size())
+ .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
+
+ qWarning() << QString("PaymentServer::%1:").arg(__func__) << msg;
+ emit message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR);
+ return;
+ }
+
+ if (reply->error() != QNetworkReply::NoError) {
QString msg = tr("Error communicating with %1: %2")
.arg(reply->request().url().toString())
.arg(reply->errorString());
- qWarning() << "PaymentServer::netRequestFinished : " << msg;
+ qWarning() << "PaymentServer::netRequestFinished: " << msg;
emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return;
}
@@ -660,7 +691,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
QByteArray data = reply->readAll();
QString requestType = reply->request().attribute(QNetworkRequest::User).toString();
- if (requestType == "PaymentRequest")
+ if (requestType == BIP70_MESSAGE_PAYMENTREQUEST)
{
PaymentRequestPlus request;
SendCoinsRecipient recipient;
@@ -676,7 +707,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
return;
}
- else if (requestType == "PaymentACK")
+ else if (requestType == BIP70_MESSAGE_PAYMENTACK)
{
payments::PaymentACK paymentACK;
if (!paymentACK.ParseFromArray(data.data(), data.size()))
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 25b08cde49..e1305b9437 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -1,5 +1,5 @@
// Copyright (c) 2011-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_PAYMENTSERVER_H
@@ -40,6 +40,8 @@
class OptionsModel;
+class CWallet;
+
QT_BEGIN_NAMESPACE
class QApplication;
class QByteArray;
@@ -50,7 +52,8 @@ class QSslError;
class QUrl;
QT_END_NAMESPACE
-class CWallet;
+// BIP70 max payment request size in bytes (DoS protection)
+extern const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE;
class PaymentServer : public QObject
{
@@ -59,7 +62,7 @@ class PaymentServer : public QObject
public:
// Parse URIs on command line
// Returns false on error
- static bool ipcParseCommandLine(int argc, char *argv[]);
+ static void ipcParseCommandLine(int argc, char *argv[]);
// Returns true if there were URIs on the command line
// which were successfully sent to an already-running
@@ -85,6 +88,9 @@ public:
// OptionsModel is used for getting proxy settings and display unit
void setOptionsModel(OptionsModel *optionsModel);
+ // This is now public, because we use it in paymentservertests.cpp
+ static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
+
signals:
// Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient);
@@ -118,7 +124,6 @@ protected:
bool eventFilter(QObject *object, QEvent *event);
private:
- static bool readPaymentRequest(const QString& filename, PaymentRequestPlus& request);
bool processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient);
void fetchRequest(const QUrl& url);
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 84cab01c50..8f49cb9464 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -7,6 +7,7 @@
#include "optionsmodel.h"
#include "paymentrequestdata.h"
+#include "random.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -108,6 +109,17 @@ void PaymentServerTests::paymentServerTests()
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString(""));
+ // Just get some random data big enough to trigger BIP70 DoS protection
+ unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
+ GetRandBytes(randData, sizeof(randData));
+ // Write data to a temp file:
+ QTemporaryFile tempFile;
+ 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/rest.cpp b/src/rest.cpp
index 4953d7e717..6285784af5 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core/block.h"
-#include "core/transaction.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "main.h"
#include "rpcserver.h"
#include "streams.h"
@@ -18,6 +18,7 @@ using namespace std;
using namespace json_spirit;
enum RetFormat {
+ RF_UNDEF,
RF_BINARY,
RF_HEX,
RF_JSON,
@@ -25,14 +26,16 @@ enum RetFormat {
static const struct {
enum RetFormat rf;
- const char *name;
+ const char* name;
} rf_names[] = {
- { RF_BINARY, "binary" }, // default, if match not found
- { RF_HEX, "hex" },
- { RF_JSON, "json" },
+ {RF_UNDEF, ""},
+ {RF_BINARY, "bin"},
+ {RF_HEX, "hex"},
+ {RF_JSON, "json"},
};
-class RestErr {
+class RestErr
+{
public:
enum HTTPStatusCode status;
string message;
@@ -49,15 +52,34 @@ static RestErr RESTERR(enum HTTPStatusCode status, string message)
return re;
}
-static enum RetFormat ParseDataFormat(const string& format)
+static enum RetFormat ParseDataFormat(vector<string>& params, const string strReq)
{
- for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
- if (format == rf_names[i].name)
- return rf_names[i].rf;
+ boost::split(params, strReq, boost::is_any_of("."));
+ if (params.size() > 1) {
+ for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
+ if (params[1] == rf_names[i].name)
+ return rf_names[i].rf;
+ }
return rf_names[0].rf;
}
+static string AvailableDataFormatsString()
+{
+ string formats = "";
+ for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
+ if (strlen(rf_names[i].name) > 0) {
+ formats.append(".");
+ formats.append(rf_names[i].name);
+ formats.append(", ");
+ }
+
+ if (formats.length() > 0)
+ return formats.substr(0, formats.length() - 2);
+
+ return formats;
+}
+
static bool ParseHashStr(const string& strReq, uint256& v)
{
if (!IsHex(strReq) || (strReq.size() != 64))
@@ -67,15 +89,13 @@ static bool ParseHashStr(const string& strReq, uint256& v)
return true;
}
-static bool rest_block(AcceptedConnection *conn,
+static bool rest_block(AcceptedConnection* conn,
string& strReq,
map<string, string>& mapHeaders,
bool fRun)
{
vector<string> params;
- boost::split(params, strReq, boost::is_any_of("/"));
-
- enum RetFormat rf = ParseDataFormat(params.size() > 1 ? params[1] : string(""));
+ enum RetFormat rf = ParseDataFormat(params, strReq);
string hashStr = params[0];
uint256 hash;
@@ -105,7 +125,7 @@ static bool rest_block(AcceptedConnection *conn,
}
case RF_HEX: {
- string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";;
+ string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
return true;
}
@@ -115,22 +135,24 @@ static bool rest_block(AcceptedConnection *conn,
string strJSON = write_string(Value(objBlock), false) + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
- }
+ }
+
+ default: {
+ throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ }
}
// not reached
- return true; // continue to process further HTTP reqs on this cxn
+ return true; // continue to process further HTTP reqs on this cxn
}
-static bool rest_tx(AcceptedConnection *conn,
+static bool rest_tx(AcceptedConnection* conn,
string& strReq,
map<string, string>& mapHeaders,
bool fRun)
{
vector<string> params;
- boost::split(params, strReq, boost::is_any_of("/"));
-
- enum RetFormat rf = ParseDataFormat(params.size() > 1 ? params[1] : string(""));
+ enum RetFormat rf = ParseDataFormat(params, strReq);
string hashStr = params[0];
uint256 hash;
@@ -153,7 +175,7 @@ static bool rest_tx(AcceptedConnection *conn,
}
case RF_HEX: {
- string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";;
+ string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";
conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
return true;
}
@@ -165,33 +187,37 @@ static bool rest_tx(AcceptedConnection *conn,
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
+
+ default: {
+ throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ }
}
// not reached
- return true; // continue to process further HTTP reqs on this cxn
+ return true; // continue to process further HTTP reqs on this cxn
}
static const struct {
- const char *prefix;
- bool (*handler)(AcceptedConnection *conn,
+ const char* prefix;
+ bool (*handler)(AcceptedConnection* conn,
string& strURI,
map<string, string>& mapHeaders,
bool fRun);
} uri_prefixes[] = {
- { "/rest/tx/", rest_tx },
- { "/rest/block/", rest_block },
+ {"/rest/tx/", rest_tx},
+ {"/rest/block/", rest_block},
};
-bool HTTPReq_REST(AcceptedConnection *conn,
+bool HTTPReq_REST(AcceptedConnection* conn,
string& strURI,
map<string, string>& mapHeaders,
bool fRun)
{
try {
std::string statusmessage;
- if(RPCIsInWarmup(&statusmessage))
- throw RESTERR(HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: "+statusmessage);
-
+ if (RPCIsInWarmup(&statusmessage))
+ throw RESTERR(HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
+
for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++) {
unsigned int plen = strlen(uri_prefixes[i].prefix);
if (strURI.substr(0, plen) == uri_prefixes[i].prefix) {
@@ -199,8 +225,7 @@ bool HTTPReq_REST(AcceptedConnection *conn,
return uri_prefixes[i].handler(conn, strReq, mapHeaders, fRun);
}
}
- }
- catch (RestErr& re) {
+ } catch (RestErr& re) {
conn->stream() << HTTPReply(re.status, re.message + "\r\n", false, false, "text/plain") << std::flush;
return false;
}
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 045cd90ef6..924f416904 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -505,6 +505,12 @@ Value getchaintips(const Array& params, bool fHelp)
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" }\n"
"]\n"
+ "Possible values for status:\n"
+ "1. \"invalid\" This branch contains at least one invalid block\n"
+ "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
+ "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
+ "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
+ "5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
"\nExamples:\n"
+ HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 837a7593b6..45899d3db5 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -266,6 +266,7 @@ Value getmininginfo(const Array& params, bool fHelp)
}
+// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
Value prioritisetransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 3)
@@ -277,22 +278,20 @@ Value prioritisetransaction(const Array& params, bool fHelp)
"2. priority delta (numeric, required) The priority to add or subtract.\n"
" The transaction selection algorithm considers the tx as it would have a higher priority.\n"
" (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n"
- "3. fee delta (numeric, required) The absolute fee value to add or subtract in bitcoin.\n"
+ "3. fee delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee.\n"
"\nResult\n"
"true (boolean) Returns true\n"
"\nExamples:\n"
- + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 0.00010000")
- + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 0.00010000")
+ + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
+ + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
);
uint256 hash;
hash.SetHex(params[0].get_str());
- CAmount nAmount = 0;
- if (params[2].get_real() != 0.0)
- nAmount = AmountFromValue(params[2]);
+ CAmount nAmount = params[2].get_int64();
mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
return true;
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 25734f4930..8de15ff9e2 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "core_io.h"
#include "init.h"
#include "keystore.h"
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 8512212185..252b0866a2 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -269,6 +269,8 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "gettxout", &gettxout, true, false, false },
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
{ "blockchain", "verifychain", &verifychain, true, false, false },
+ { "blockchain", "invalidateblock", &invalidateblock, true, true, false },
+ { "blockchain", "reconsiderblock", &reconsiderblock, true, true, false },
/* Mining */
{ "mining", "getblocktemplate", &getblocktemplate, true, false, false },
@@ -595,7 +597,7 @@ void StartRPCThreads()
if (fUseSSL)
{
- rpc_ssl_context->set_options(ssl::context::no_sslv2);
+ rpc_ssl_context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3);
filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 4faa760ad7..d4fd2ad7d9 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -5,7 +5,7 @@
#include "bitcoinconsensus.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "script/interpreter.h"
#include "version.h"
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 237c712870..3231f2e74e 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -5,7 +5,7 @@
#include "interpreter.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
diff --git a/src/script/script_error.h b/src/script/script_error.h
index ac1f2deae5..091524f35c 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_SCRIPT_ERROR_H
-#define BITCOIN_SCRIPT_ERROR_H
+#ifndef BITCOIN_SCRIPT_SCRIPT_ERROR_H
+#define BITCOIN_SCRIPT_SCRIPT_ERROR_H
typedef enum ScriptError_t
{
@@ -54,4 +54,4 @@ typedef enum ScriptError_t
const char* ScriptErrorString(const ScriptError error);
-#endif // BITCOIN_SCRIPT_ERROR_H
+#endif // BITCOIN_SCRIPT_SCRIPT_ERROR_H
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 7dfed751b6..03c33ad9b5 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -5,7 +5,7 @@
#include "script/sign.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "key.h"
#include "keystore.h"
#include "script/standard.h"
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index 24a86b561b..3a85e8cba0 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -18,6 +18,8 @@ env:
- FIELD=64bit ENDOMORPHISM=yes
- FIELD=32bit
- FIELD=32bit ENDOMORPHISM=yes
+ - BIGNUM=none
+ - BIGNUM=none ENDOMORPHISM=yes
- BUILD=distcheck
- EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
before_script: ./autogen.sh
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index d527da6b77..dbf1790f34 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -68,12 +68,13 @@ bench_sign_LDFLAGS = -static
bench_inv_SOURCES = src/bench_inv.c
bench_inv_LDADD = $(COMMON_LIB) $(SECP_LIBS)
bench_inv_LDFLAGS = -static
+bench_inv_CPPFLAGS = $(SECP_INCLUDES)
endif
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DVERIFY $(SECP_TEST_INCLUDES)
+tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
tests_LDADD = $(COMMON_LIB) $(SECP_LIBS) $(SECP_TEST_LIBS)
tests_LDFLAGS = -static
TESTS = tests
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index e6f3470ed7..4ca28f99cf 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -78,7 +78,13 @@ fi
dnl
AC_DEFUN([SECP_GMP_CHECK],[
if test x"$has_gmp" != x"yes"; then
- AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS=-lgmp; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])
+ CPPFLAGS_TEMP="$CPPFLAGS"
+ CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS"
+ LIBS_TEMP="$LIBS"
+ LIBS="$GMP_LIBS $LIBS"
+ AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])
+ CPPFLAGS="$CPPFLAGS_TEMP"
+ LIBS="$LIBS_TEMP"
fi
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])
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 2da5709834..6e6fccd7fd 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -33,10 +33,35 @@ case $host in
esac
case $host_os in
- darwin*)
- CPPFLAGS="$CPPFLAGS -I/opt/local/include"
- LDFLAGS="$LDFLAGS -L/opt/local/lib"
- ;;
+ *darwin*)
+ if test x$cross_compiling != xyes; then
+ AC_PATH_PROG([BREW],brew,)
+ if test x$BREW != x; then
+ dnl These Homebrew packages may be keg-only, meaning that they won't be found
+ dnl in expected paths because they may conflict with system files. Ask
+ dnl Homebrew where each one is located, then adjust paths accordingly.
+
+ openssl_prefix=`$BREW --prefix openssl 2>/dev/null`
+ gmp_prefix=`$BREW --prefix gmp 2>/dev/null`
+ if test x$openssl_prefix != x; then
+ PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
+ export PKG_CONFIG_PATH
+ fi
+ if test x$gmp_prefix != x; then
+ GMP_CPPFLAGS="-I$gmp_prefix/include"
+ GMP_LIBS="-L$gmp_prefix/lib"
+ fi
+ else
+ AC_PATH_PROG([PORT],port,)
+ dnl if homebrew isn't installed and macports is, add the macports default paths
+ dnl as a last resort.
+ if test x$PORT != x; then
+ CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
+ LDFLAGS="$LDFLAGS -L/opt/local/lib"
+ fi
+ fi
+ fi
+ ;;
esac
CFLAGS="$CFLAGS -W"
@@ -70,7 +95,7 @@ AC_ARG_ENABLE(endomorphism,
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=gmp|64bit|64bit_asm|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
-AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|auto],
+AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|none|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],
@@ -154,7 +179,7 @@ if test x"$req_bignum" = x"auto"; then
fi
if test x"$set_bignum" = x; then
- AC_MSG_ERROR([no working bignum implementation found])
+ set_bignum=none
fi
else
set_bignum=$req_bignum
@@ -162,8 +187,7 @@ else
gmp)
SECP_GMP_CHECK
;;
- openssl)
- SECP_OPENSSL_CHECK
+ none)
;;
*)
AC_MSG_ERROR([invalid bignum implementation selection])
@@ -196,9 +220,15 @@ esac
# select bignum implementation
case $set_bignum in
gmp)
- AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])
- AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation])
- AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the USE_FIELD_INV_NUM implementation])
+ AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed])
+ AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num])
+ 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)
+ 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])
;;
*)
AC_MSG_ERROR([invalid bignum implementation])
@@ -236,10 +266,11 @@ fi
if test x"$set_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
+ SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
fi
if test x"$use_endomorphism" = x"yes"; then
- AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism])
+ AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
AC_MSG_NOTICE([Using field implementation: $set_field])
@@ -256,4 +287,10 @@ AC_SUBST(YASM_BINFMT)
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"])
+
+dnl make sure nothing new is exported so that we don't break the cache
+PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
+unset PKG_CONFIG_PATH
+PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
+
AC_OUTPUT
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 932bf0279f..94a6ef483f 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -15,18 +15,6 @@ extern "C" {
# endif
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
-# if SECP256K1_GNUC_PREREQ(3,0)
-# define SECP256K1_RESTRICT __restrict__
-# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
-# define SECP256K1_RESTRICT __restrict
-# else
-# define SECP256K1_RESTRICT
-# endif
-# else
-# define SECP256K1_RESTRICT restrict
-# endif
-
-# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(2,7)
# define SECP256K1_INLINE __inline__
# elif (defined(_MSC_VER))
diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h
index 3b1e0484ea..5fc5230c36 100644
--- a/src/secp256k1/src/ecdsa.h
+++ b/src/secp256k1/src/ecdsa.h
@@ -7,17 +7,21 @@
#ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_
-#include "num.h"
+#include "scalar.h"
+#include "group.h"
+
+static void secp256k1_ecsda_start(void);
+static void secp256k1_ecdsa_stop(void);
typedef struct {
- secp256k1_num_t r, s;
+ secp256k1_scalar_t r, s;
} secp256k1_ecdsa_sig_t;
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
-static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message);
+static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
-static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid);
-static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s);
+static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
+static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s);
#endif
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 4c05ec39f8..a951d0b4ad 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -8,13 +8,51 @@
#ifndef _SECP256K1_ECDSA_IMPL_H_
#define _SECP256K1_ECDSA_IMPL_H_
-#include "num.h"
+#include "scalar.h"
#include "field.h"
#include "group.h"
#include "ecmult.h"
#include "ecmult_gen.h"
#include "ecdsa.h"
+typedef struct {
+ secp256k1_fe_t order_as_fe;
+ secp256k1_fe_t p_minus_order;
+} secp256k1_ecdsa_consts_t;
+
+static const secp256k1_ecdsa_consts_t *secp256k1_ecdsa_consts = NULL;
+
+static void secp256k1_ecdsa_start(void) {
+ if (secp256k1_ecdsa_consts != NULL)
+ return;
+
+ /* Allocate. */
+ secp256k1_ecdsa_consts_t *ret = (secp256k1_ecdsa_consts_t*)malloc(sizeof(secp256k1_ecdsa_consts_t));
+
+ static const unsigned char order[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
+ 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
+ };
+
+ secp256k1_fe_set_b32(&ret->order_as_fe, order);
+ secp256k1_fe_negate(&ret->p_minus_order, &ret->order_as_fe, 1);
+ secp256k1_fe_normalize(&ret->p_minus_order);
+
+ /* Set the global pointer. */
+ secp256k1_ecdsa_consts = ret;
+}
+
+static void secp256k1_ecdsa_stop(void) {
+ if (secp256k1_ecdsa_consts == NULL)
+ return;
+
+ secp256k1_ecdsa_consts_t *c = (secp256k1_ecdsa_consts_t*)secp256k1_ecdsa_consts;
+ secp256k1_ecdsa_consts = NULL;
+ free(c);
+}
+
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
if (sig[0] != 0x30) return 0;
int lenr = sig[3];
@@ -26,18 +64,37 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned ch
if (lenr == 0) return 0;
if (sig[lenr+4] != 0x02) return 0;
if (lens == 0) return 0;
- secp256k1_num_set_bin(&r->r, sig+4, lenr);
- secp256k1_num_set_bin(&r->s, sig+6+lenr, lens);
+ const unsigned char *sp = sig + 6 + lenr;
+ while (lens > 0 && sp[0] == 0) {
+ lens--;
+ sp++;
+ }
+ if (lens > 32) return 0;
+ const unsigned char *rp = sig + 4;
+ while (lenr > 0 && rp[0] == 0) {
+ lenr--;
+ rp++;
+ }
+ if (lenr > 32) return 0;
+ unsigned char ra[32] = {0}, sa[32] = {0};
+ memcpy(ra + 32 - lenr, rp, lenr);
+ memcpy(sa + 32 - lens, sp, lens);
+ int overflow = 0;
+ secp256k1_scalar_set_b32(&r->r, ra, &overflow);
+ if (overflow) return 0;
+ secp256k1_scalar_set_b32(&r->s, sa, &overflow);
+ if (overflow) return 0;
return 1;
}
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
- int lenR = (secp256k1_num_bits(&a->r) + 7)/8;
- if (lenR == 0 || secp256k1_num_get_bit(&a->r, lenR*8-1))
- lenR++;
- int lenS = (secp256k1_num_bits(&a->s) + 7)/8;
- if (lenS == 0 || secp256k1_num_get_bit(&a->s, lenS*8-1))
- lenS++;
+ unsigned char r[33] = {0}, s[33] = {0};
+ secp256k1_scalar_get_b32(&r[1], &a->r);
+ secp256k1_scalar_get_b32(&s[1], &a->s);
+ unsigned char *rp = r, *sp = s;
+ int lenR = 33, lenS = 33;
+ while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }
+ while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }
if (*size < 6+lenS+lenR)
return 0;
*size = 6 + lenS + lenR;
@@ -45,98 +102,67 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
sig[1] = 4 + lenS + lenR;
sig[2] = 0x02;
sig[3] = lenR;
- secp256k1_num_get_bin(sig+4, lenR, &a->r);
+ memcpy(sig+4, rp, lenR);
sig[4+lenR] = 0x02;
sig[5+lenR] = lenS;
- secp256k1_num_get_bin(sig+lenR+6, lenS, &a->s);
+ memcpy(sig+lenR+6, sp, lenS);
return 1;
}
-static int secp256k1_ecdsa_sig_recompute(secp256k1_num_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
- const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
-
- if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
- return 0;
- if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
- return 0;
- if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
+static int secp256k1_ecdsa_sig_recompute(secp256k1_scalar_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
+ if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s))
return 0;
int ret = 0;
- secp256k1_num_t sn, u1, u2;
- secp256k1_num_init(&sn);
- secp256k1_num_init(&u1);
- secp256k1_num_init(&u2);
- secp256k1_num_mod_inverse(&sn, &sig->s, &c->order);
- secp256k1_num_mod_mul(&u1, &sn, message, &c->order);
- secp256k1_num_mod_mul(&u2, &sn, &sig->r, &c->order);
+ 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(&xr);
unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr);
- secp256k1_num_set_bin(r2, xrb, 32);
- secp256k1_num_mod(r2, &c->order);
+ secp256k1_scalar_set_b32(r2, xrb, NULL);
ret = 1;
}
- secp256k1_num_free(&sn);
- secp256k1_num_free(&u1);
- secp256k1_num_free(&u2);
return ret;
}
-static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid) {
- const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
-
- if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
- return 0;
- if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
- return 0;
- if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
+static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
+ if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s))
return 0;
- secp256k1_num_t rx;
- secp256k1_num_init(&rx);
- secp256k1_num_copy(&rx, &sig->r);
+ unsigned char brx[32];
+ secp256k1_scalar_get_b32(brx, &sig->r);
+ secp256k1_fe_t fx;
+ VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) {
- secp256k1_num_add(&rx, &rx, &c->order);
- if (secp256k1_num_cmp(&rx, &secp256k1_fe_consts->p) >= 0)
+ if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_consts->p_minus_order) >= 0)
return 0;
+ secp256k1_fe_add(&fx, &secp256k1_ecdsa_consts->order_as_fe);
}
- unsigned char brx[32];
- secp256k1_num_get_bin(brx, 32, &rx);
- secp256k1_num_free(&rx);
- secp256k1_fe_t fx;
- secp256k1_fe_set_b32(&fx, brx);
secp256k1_ge_t x;
if (!secp256k1_ge_set_xo(&x, &fx, recid & 1))
return 0;
secp256k1_gej_t xj;
secp256k1_gej_set_ge(&xj, &x);
- secp256k1_num_t rn, u1, u2;
- secp256k1_num_init(&rn);
- secp256k1_num_init(&u1);
- secp256k1_num_init(&u2);
- secp256k1_num_mod_inverse(&rn, &sig->r, &c->order);
- secp256k1_num_mod_mul(&u1, &rn, message, &c->order);
- secp256k1_num_sub(&u1, &c->order, &u1);
- secp256k1_num_mod_mul(&u2, &rn, &sig->s, &c->order);
+ secp256k1_scalar_t rn, u1, u2;
+ secp256k1_scalar_inverse_var(&rn, &sig->r);
+ secp256k1_scalar_mul(&u1, &rn, message);
+ secp256k1_scalar_negate(&u1, &u1);
+ secp256k1_scalar_mul(&u2, &rn, &sig->s);
secp256k1_gej_t qj;
secp256k1_ecmult(&qj, &xj, &u2, &u1);
secp256k1_ge_set_gej_var(pubkey, &qj);
- secp256k1_num_free(&rn);
- secp256k1_num_free(&u1);
- secp256k1_num_free(&u2);
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_num_t *message) {
- secp256k1_num_t r2;
- secp256k1_num_init(&r2);
+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_num_cmp(&sig->r, &r2) == 0;
- secp256k1_num_free(&r2);
+ ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_scalar_eq(&sig->r, &r2);
return ret;
}
@@ -150,34 +176,30 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
int overflow = 0;
- secp256k1_scalar_t sigr;
- secp256k1_scalar_set_b32(&sigr, b, &overflow);
+ secp256k1_scalar_set_b32(&sig->r, b, &overflow);
if (recid)
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
secp256k1_scalar_t n;
- secp256k1_scalar_mul(&n, &sigr, seckey);
+ secp256k1_scalar_mul(&n, &sig->r, seckey);
secp256k1_scalar_add(&n, &n, message);
- secp256k1_scalar_t sigs;
- secp256k1_scalar_inverse(&sigs, nonce);
- secp256k1_scalar_mul(&sigs, &sigs, &n);
+ secp256k1_scalar_inverse(&sig->s, nonce);
+ secp256k1_scalar_mul(&sig->s, &sig->s, &n);
secp256k1_scalar_clear(&n);
secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r);
- if (secp256k1_scalar_is_zero(&sigs))
+ if (secp256k1_scalar_is_zero(&sig->s))
return 0;
- if (secp256k1_scalar_is_high(&sigs)) {
- secp256k1_scalar_negate(&sigs, &sigs);
+ if (secp256k1_scalar_is_high(&sig->s)) {
+ secp256k1_scalar_negate(&sig->s, &sig->s);
if (recid)
*recid ^= 1;
}
- secp256k1_scalar_get_num(&sig->s, &sigs);
- secp256k1_scalar_get_num(&sig->r, &sigr);
return 1;
}
-static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s) {
- secp256k1_num_copy(&sig->r, r);
- secp256k1_num_copy(&sig->s, s);
+static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s) {
+ sig->r = *r;
+ sig->s = *s;
}
#endif
diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h
index 024c8b821b..6de5dc0a59 100644
--- a/src/secp256k1/src/eckey.h
+++ b/src/secp256k1/src/eckey.h
@@ -9,7 +9,6 @@
#include "group.h"
#include "scalar.h"
-#include "num.h"
static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
@@ -18,8 +17,8 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned
static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed);
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
-static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_num_t *tweak);
+static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
-static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_num_t *tweak);
+static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
#endif
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index 290b1f0900..0f218ced9e 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -9,7 +9,7 @@
#include "eckey.h"
-#include "num.h"
+#include "scalar.h"
#include "field.h"
#include "group.h"
#include "ecmult_gen.h"
@@ -17,12 +17,12 @@
static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
secp256k1_fe_t x;
- secp256k1_fe_set_b32(&x, pub+1);
- return secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
+ return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe_t x, y;
- secp256k1_fe_set_b32(&x, pub+1);
- secp256k1_fe_set_b32(&y, pub+33);
+ if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
+ return 0;
+ }
secp256k1_ge_set_xy(elem, &x, &y);
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
return 0;
@@ -154,17 +154,12 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp
return 1;
}
-static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_num_t *tweak) {
- if (secp256k1_num_cmp(tweak, &secp256k1_ge_consts->order) >= 0)
- return 0;
-
+static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
secp256k1_gej_t pt;
secp256k1_gej_set_ge(&pt, key);
- secp256k1_num_t one;
- secp256k1_num_init(&one);
- secp256k1_num_set_int(&one, 1);
+ secp256k1_scalar_t one;
+ secp256k1_scalar_set_int(&one, 1);
secp256k1_ecmult(&pt, &pt, &one, tweak);
- secp256k1_num_free(&one);
if (secp256k1_gej_is_infinity(&pt))
return 0;
@@ -180,19 +175,15 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp
return 1;
}
-static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_num_t *tweak) {
- if (secp256k1_num_is_zero(tweak))
- return 0;
- if (secp256k1_num_cmp(tweak, &secp256k1_ge_consts->order) >= 0)
+static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
+ if (secp256k1_scalar_is_zero(tweak))
return 0;
- secp256k1_num_t zero;
- secp256k1_num_init(&zero);
- secp256k1_num_set_int(&zero, 0);
+ secp256k1_scalar_t zero;
+ secp256k1_scalar_set_int(&zero, 0);
secp256k1_gej_t pt;
secp256k1_gej_set_ge(&pt, key);
secp256k1_ecmult(&pt, &pt, tweak, &zero);
- secp256k1_num_free(&zero);
secp256k1_ge_set_gej(key, &pt);
return 1;
}
diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h
index e3cf18b680..15a7100a4a 100644
--- a/src/secp256k1/src/ecmult.h
+++ b/src/secp256k1/src/ecmult.h
@@ -14,6 +14,6 @@ static void secp256k1_ecmult_start(void);
static void secp256k1_ecmult_stop(void);
/** Double multiply: R = na*A + ng*G */
-static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng);
+static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng);
#endif
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 07859ab04b..af0ead522d 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -23,8 +23,8 @@ typedef struct {
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63).
* None of the resulting prec group elements have a known scalar, and neither do any of
* the intermediate sums while computing a*G.
- * To make memory access uniform, the bytes of prec(i, n_i) are sliced per value of n_i. */
- unsigned char prec[64][sizeof(secp256k1_ge_t)][16]; /* prec[j][k][i] = k'th byte of (16^j * i * G + U_i) */
+ */
+ secp256k1_fe_t prec[64][16][2]; /* prec[j][i] = (16^j * i * G + U_i).{x,y} */
} secp256k1_ecmult_gen_consts_t;
static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL;
@@ -45,7 +45,7 @@ static void secp256k1_ecmult_gen_start(void) {
{
static const unsigned char nums_b32[32] = "The scalar for this x is unknown";
secp256k1_fe_t nums_x;
- secp256k1_fe_set_b32(&nums_x, nums_b32);
+ VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
secp256k1_ge_t nums_ge;
VERIFY_CHECK(secp256k1_ge_set_xo(&nums_ge, &nums_x, 0));
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
@@ -81,9 +81,9 @@ static void secp256k1_ecmult_gen_start(void) {
}
for (int j=0; j<64; j++) {
for (int i=0; i<16; i++) {
- const unsigned char* raw = (const unsigned char*)(&prec[j*16 + i]);
- for (size_t k=0; k<sizeof(secp256k1_ge_t); k++)
- ret->prec[j][k][i] = raw[k];
+ VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[j*16 + i]));
+ ret->prec[j][i][0] = prec[j*16 + i].x;
+ ret->prec[j][i][1] = prec[j*16 + i].y;
}
}
@@ -104,11 +104,14 @@ static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *g
const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts;
secp256k1_gej_set_infinity(r);
secp256k1_ge_t add;
+ add.infinity = 0;
int bits;
for (int j=0; j<64; j++) {
bits = secp256k1_scalar_get_bits(gn, j * 4, 4);
- for (size_t k=0; k<sizeof(secp256k1_ge_t); k++)
- ((unsigned char*)(&add))[k] = c->prec[j][k][bits];
+ for (int i=0; i<16; i++) {
+ secp256k1_fe_cmov(&add.x, &c->prec[j][i][0], i == bits);
+ secp256k1_fe_cmov(&add.y, &c->prec[j][i][1], i == bits);
+ }
secp256k1_gej_add_ge(r, r, &add);
}
bits = 0;
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 508902564e..445b81593f 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -7,8 +7,8 @@
#ifndef _SECP256K1_ECMULT_IMPL_H_
#define _SECP256K1_ECMULT_IMPL_H_
-#include "num.h"
#include "group.h"
+#include "scalar.h"
#include "ecmult.h"
/* optimal for 128-bit and 256-bit exponents. */
@@ -16,7 +16,11 @@
/** larger numbers may result in slightly better performance, at the cost of
exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB. */
+#ifdef USE_ENDOMORPHISM
#define WINDOW_G 14
+#else
+#define WINDOW_G 15
+#endif
/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
* pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
@@ -69,7 +73,9 @@ static void secp256k1_ecmult_table_precomp_ge_var(secp256k1_ge_t *pre, const sec
typedef struct {
/* For accelerating the computation of a*P + b*G: */
secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */
+#endif
} secp256k1_ecmult_consts_t;
static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
@@ -85,14 +91,18 @@ static void secp256k1_ecmult_start(void) {
const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g);
+#ifdef USE_ENDOMORPHISM
/* calculate 2^128*generator */
secp256k1_gej_t g_128j = gj;
for (int i=0; i<128; i++)
secp256k1_gej_double_var(&g_128j, &g_128j);
+#endif
/* precompute the tables with odd multiples */
secp256k1_ecmult_table_precomp_ge_var(ret->pre_g, &gj, WINDOW_G);
+#ifdef USE_ENDOMORPHISM
secp256k1_ecmult_table_precomp_ge_var(ret->pre_g_128, &g_128j, WINDOW_G);
+#endif
/* Set the global pointer to the precomputation table. */
secp256k1_ecmult_consts = ret;
@@ -111,56 +121,62 @@ static void secp256k1_ecmult_stop(void) {
* with the following guarantees:
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
* - two non-zero entries in wnaf are separated by at least w-1 zeroes.
- * - the index of the highest non-zero entry in wnaf (=return value-1) is at most bits, where
- * bits is the number of bits necessary to represent the absolute value of the input.
+ * - the number of set values in wnaf is returned. This number is at most 256, and at most one more
+ * - than the number of bits in the (absolute value) of the input.
*/
-static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_num_t *a, int w) {
- int ret = 0;
- int zeroes = 0;
- secp256k1_num_t x;
- secp256k1_num_copy(&x, a);
+static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) {
+ secp256k1_scalar_t s = *a;
+
int sign = 1;
- if (secp256k1_num_is_neg(&x)) {
+ if (secp256k1_scalar_get_bits(&s, 255, 1)) {
+ secp256k1_scalar_negate(&s, &s);
sign = -1;
- secp256k1_num_negate(&x);
}
- while (!secp256k1_num_is_zero(&x)) {
- while (!secp256k1_num_is_odd(&x)) {
- zeroes++;
- secp256k1_num_shift(&x, 1);
+
+ int set_bits = 0;
+ int bit = 0;
+ while (bit < 256) {
+ if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) {
+ bit++;
+ continue;
+ }
+ while (set_bits < bit) {
+ wnaf[set_bits++] = 0;
}
- int word = secp256k1_num_shift(&x, w);
- while (zeroes) {
- wnaf[ret++] = 0;
- zeroes--;
+ int now = w;
+ if (bit + now > 256) {
+ now = 256 - bit;
}
+ int word = secp256k1_scalar_get_bits_var(&s, bit, now);
if (word & (1 << (w-1))) {
- secp256k1_num_inc(&x);
- wnaf[ret++] = sign * (word - (1 << w));
+ secp256k1_scalar_add_bit(&s, bit + w);
+ wnaf[set_bits++] = sign * (word - (1 << w));
} else {
- wnaf[ret++] = sign * word;
+ wnaf[set_bits++] = sign * word;
}
- zeroes = w-1;
+ bit += now;
}
- return ret;
+ return set_bits;
}
-static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng) {
+static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) {
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
#ifdef USE_ENDOMORPHISM
- secp256k1_num_t na_1, na_lam;
+ secp256k1_scalar_t na_1, na_lam;
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
- secp256k1_gej_split_exp_var(&na_1, &na_lam, na);
+ secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na);
/* build wnaf representation for na_1 and na_lam. */
- int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
- int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
+ int wnaf_na_1[130]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
+ int wnaf_na_lam[130]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
+ VERIFY_CHECK(bits_na_1 <= 130);
+ VERIFY_CHECK(bits_na_lam <= 130);
int bits = bits_na_1;
if (bits_na_lam > bits) bits = bits_na_lam;
#else
/* build wnaf representation for na. */
- int wnaf_na[257]; int bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
+ int wnaf_na[256]; int bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
int bits = bits_na;
#endif
@@ -172,19 +188,22 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
for (int i=0; i<ECMULT_TABLE_SIZE(WINDOW_A); i++)
secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]);
-#endif
/* Splitted G factors. */
- secp256k1_num_t ng_1, ng_128;
+ secp256k1_scalar_t ng_1, ng_128;
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
- secp256k1_num_split(&ng_1, &ng_128, ng, 128);
+ secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
/* Build wnaf representation for ng_1 and ng_128 */
int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
if (bits_ng_1 > bits) bits = bits_ng_1;
if (bits_ng_128 > bits) bits = bits_ng_128;
+#else
+ int wnaf_ng[257]; int bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G);
+ if (bits_ng > bits) bits = bits_ng;
+#endif
secp256k1_gej_set_infinity(r);
secp256k1_gej_t tmpj;
@@ -202,12 +221,6 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
secp256k1_gej_add_var(r, r, &tmpj);
}
-#else
- if (i < bits_na && (n = wnaf_na[i])) {
- ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
- secp256k1_gej_add_var(r, r, &tmpj);
- }
-#endif
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa);
@@ -216,6 +229,16 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa);
}
+#else
+ if (i < bits_na && (n = wnaf_na[i])) {
+ ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
+ secp256k1_gej_add_var(r, r, &tmpj);
+ }
+ if (i < bits_ng && (n = wnaf_ng[i])) {
+ ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
+ secp256k1_gej_add_ge_var(r, r, &tmpa);
+ }
+#endif
}
}
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index c7feead900..0cdf0fb479 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -33,7 +33,10 @@
#endif
typedef struct {
+#ifndef USE_NUM_NONE
secp256k1_num_t p;
+#endif
+ secp256k1_fe_t order;
} secp256k1_fe_consts_t;
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
@@ -59,8 +62,11 @@ 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);
-/** Set a field element equal to 32-byte big endian value. Resulting field element is normalized. */
-static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
+/** 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);
+
+/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */
+static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
/** 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);
@@ -78,7 +84,7 @@ static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
-static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b);
+static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b);
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
@@ -104,11 +110,13 @@ static void secp256k1_fe_inv_all(size_t len, secp256k1_fe_t r[len], const secp25
/** Potentially faster version of secp256k1_fe_inv_all, without constant-time guarantee. */
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]);
-
/** Convert a field element to a hexadecimal string. */
static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
/** Convert a hexadecimal string to a field element. */
-static void secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
+static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
+
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
+static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag);
#endif
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index c0f1be0b2d..c4403fba22 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -152,7 +152,21 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const se
| (t[5]^u[5]) | (t[6]^u[6]) | (t[7]^u[7]) | (t[8]^u[8]) | (t[9]^u[9])) == 0;
}
-static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+static int secp256k1_fe_cmp_var(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
+ for (int i = 9; i >= 0; i--) {
+ if (a->n[i] > b->n[i]) return 1;
+ if (a->n[i] < b->n[i]) return -1;
+ }
+ return 0;
+}
+
+static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
for (int i=0; i<32; i++) {
@@ -162,11 +176,15 @@ static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
}
}
+ if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
+ return 0;
+ }
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
+ return 1;
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@@ -253,7 +271,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
#define VERIFY_BITS(x, n) do { } while(0)
#endif
-SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t *b, uint32_t *r) {
+SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b, uint32_t *r) {
VERIFY_BITS(a[0], 30);
VERIFY_BITS(a[1], 30);
VERIFY_BITS(a[2], 30);
@@ -853,12 +871,13 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t
}
-static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
+ VERIFY_CHECK(r != b);
#endif
secp256k1_fe_mul_inner(a->n, b->n, r->n);
#ifdef VERIFY
@@ -881,4 +900,24 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
+static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
+ uint32_t mask0 = flag + ~((uint32_t)0), mask1 = ~mask0;
+ r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
+ r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
+ r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
+ r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
+ r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
+ r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1);
+ r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1);
+ r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
+ r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
+ r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
+#ifdef VERIFY
+ if (flag) {
+ r->magnitude = a->magnitude;
+ r->normalized = a->normalized;
+ }
+#endif
+}
+
#endif
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index d1b06d05a4..75b210eaf6 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -150,7 +150,21 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const se
return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4])) == 0;
}
-static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+static int secp256k1_fe_cmp_var(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
+ for (int i = 4; i >= 0; i--) {
+ if (a->n[i] > b->n[i]) return 1;
+ if (a->n[i] < b->n[i]) return -1;
+ }
+ return 0;
+}
+
+static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
for (int i=0; i<32; i++) {
for (int j=0; j<2; j++) {
@@ -159,11 +173,15 @@ static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
}
}
+ if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
+ return 0;
+ }
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
+ return 1;
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@@ -229,12 +247,13 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
#endif
}
-static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
+ VERIFY_CHECK(r != b);
#endif
secp256k1_fe_mul_inner(a->n, b->n, r->n);
#ifdef VERIFY
@@ -257,4 +276,19 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
+static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
+ uint64_t mask0 = flag + ~((uint64_t)0), mask1 = ~mask0;
+ r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
+ r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
+ r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
+ r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
+ r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
+#ifdef VERIFY
+ if (flag) {
+ r->magnitude = a->magnitude;
+ r->normalized = a->normalized;
+ }
+#endif
+}
+
#endif
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index c476428672..e552fb4319 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -15,7 +15,7 @@
#define VERIFY_BITS(x, n) do { } while(0)
#endif
-SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r) {
+SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b, uint64_t *r) {
VERIFY_BITS(a[0], 56);
VERIFY_BITS(a[1], 56);
VERIFY_BITS(a[2], 56);
@@ -26,6 +26,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
VERIFY_BITS(b[2], 56);
VERIFY_BITS(b[3], 56);
VERIFY_BITS(b[4], 52);
+ VERIFY_CHECK(r != b);
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
@@ -33,15 +34,17 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
* Note that [x 0 0 0 0 0] = [x*R].
*/
+ uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
+
__int128 c, d;
- d = (__int128)a[0] * b[3]
- + (__int128)a[1] * b[2]
- + (__int128)a[2] * b[1]
- + (__int128)a[3] * b[0];
+ d = (__int128)a0 * b[3]
+ + (__int128)a1 * b[2]
+ + (__int128)a2 * b[1]
+ + (__int128)a3 * b[0];
VERIFY_BITS(d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
- c = (__int128)a[4] * b[4];
+ c = (__int128)a4 * b[4];
VERIFY_BITS(c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (c & M) * R; c >>= 52;
@@ -53,11 +56,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
VERIFY_BITS(d, 63);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- d += (__int128)a[0] * b[4]
- + (__int128)a[1] * b[3]
- + (__int128)a[2] * b[2]
- + (__int128)a[3] * b[1]
- + (__int128)a[4] * b[0];
+ d += (__int128)a0 * b[4]
+ + (__int128)a1 * b[3]
+ + (__int128)a2 * b[2]
+ + (__int128)a3 * b[1]
+ + (__int128)a4 * b[0];
VERIFY_BITS(d, 115);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += c * R;
@@ -72,13 +75,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- c = (__int128)a[0] * b[0];
+ c = (__int128)a0 * b[0];
VERIFY_BITS(c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
- d += (__int128)a[1] * b[4]
- + (__int128)a[2] * b[3]
- + (__int128)a[3] * b[2]
- + (__int128)a[4] * b[1];
+ d += (__int128)a1 * b[4]
+ + (__int128)a2 * b[3]
+ + (__int128)a3 * b[2]
+ + (__int128)a4 * b[1];
VERIFY_BITS(d, 115);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
uint64_t u0 = d & M; d >>= 52;
@@ -92,48 +95,43 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
c += (__int128)u0 * (R >> 4);
VERIFY_BITS(c, 115);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- uint64_t t0 = c & M; c >>= 52;
- VERIFY_BITS(t0, 52);
+ r[0] = c & M; c >>= 52;
+ VERIFY_BITS(r[0], 52);
VERIFY_BITS(c, 61);
- /* [d 0 t4 t3 0 c t0] = [p8 0 0 p5 p4 p3 0 0 p0] */
+ /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (__int128)a[0] * b[1]
- + (__int128)a[1] * b[0];
+ c += (__int128)a0 * b[1]
+ + (__int128)a1 * b[0];
VERIFY_BITS(c, 114);
- /* [d 0 t4 t3 0 c t0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
- d += (__int128)a[2] * b[4]
- + (__int128)a[3] * b[3]
- + (__int128)a[4] * b[2];
+ /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
+ d += (__int128)a2 * b[4]
+ + (__int128)a3 * b[3]
+ + (__int128)a4 * b[2];
VERIFY_BITS(d, 114);
- /* [d 0 t4 t3 0 c t0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
+ /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62);
- /* [d 0 0 t4 t3 0 c t0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- uint64_t t1 = c & M; c >>= 52;
- VERIFY_BITS(t1, 52);
+ /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
+ r[1] = c & M; c >>= 52;
+ VERIFY_BITS(r[1], 52);
VERIFY_BITS(c, 63);
- /* [d 0 0 t4 t3 c t1 t0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
+ /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (__int128)a[0] * b[2]
- + (__int128)a[1] * b[1]
- + (__int128)a[2] * b[0];
+ c += (__int128)a0 * b[2]
+ + (__int128)a1 * b[1]
+ + (__int128)a2 * b[0];
VERIFY_BITS(c, 114);
- /* [d 0 0 t4 t3 c t1 t0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
- d += (__int128)a[3] * b[4]
- + (__int128)a[4] * b[3];
+ /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
+ d += (__int128)a3 * b[4]
+ + (__int128)a4 * b[3];
VERIFY_BITS(d, 114);
- /* [d 0 0 t4 t3 c t1 t0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
+ /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62);
- /* [d 0 0 0 t4 t3 c t1 t0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
+ /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[0] = t0;
- VERIFY_BITS(r[0], 52);
- /* [d 0 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- r[1] = t1;
- VERIFY_BITS(r[1], 52);
/* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[2] = c & M; c >>= 52;
VERIFY_BITS(r[2], 52);
diff --git a/src/secp256k1/src/field_gmp_impl.h b/src/secp256k1/src/field_gmp_impl.h
index af4728e5b4..8af7dd68f8 100644
--- a/src/secp256k1/src/field_gmp_impl.h
+++ b/src/secp256k1/src/field_gmp_impl.h
@@ -75,7 +75,15 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const se
return ret;
}
-static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+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++) {
@@ -83,6 +91,7 @@ static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
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 */
@@ -142,7 +151,8 @@ static void secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) {
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 *b) {
+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);
@@ -160,4 +170,11 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
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 3a31e1844e..4d25e53715 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -41,7 +41,7 @@ static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
r[64] = 0x00;
}
-static void secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
+static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
unsigned char tmp[32] = {};
static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
@@ -63,7 +63,7 @@ static void secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
if (alen > i*2)
tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]];
}
- secp256k1_fe_set_b32(r, tmp);
+ return secp256k1_fe_set_b32(r, tmp);
}
static int secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
@@ -197,7 +197,7 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
for (int j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, &x2);
for (int j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1);
- secp256k1_fe_mul(r, &t1, a);
+ secp256k1_fe_mul(r, a, &t1);
}
static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
@@ -212,7 +212,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
secp256k1_num_get_bin(b, 32, &n);
- secp256k1_fe_set_b32(r, b);
+ VERIFY_CHECK(secp256k1_fe_set_b32(r, b));
#else
#error "Please select field inverse implementation"
#endif
@@ -267,16 +267,20 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const se
}
static void secp256k1_fe_start(void) {
+#ifndef USE_NUM_NONE
static const unsigned char secp256k1_fe_consts_p[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
};
+#endif
if (secp256k1_fe_consts == NULL) {
secp256k1_fe_inner_start();
secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t));
+#ifndef USE_NUM_NONE
secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
+#endif
secp256k1_fe_consts = ret;
}
}
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index ba02549821..0f14bd25f3 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -27,14 +27,11 @@ typedef struct {
/** Global constants related to the group */
typedef struct {
- secp256k1_num_t order; /* the order of the curve (= order of its generator) */
- secp256k1_num_t half_order; /* half the order of the curve (= order of its generator) */
secp256k1_ge_t g; /* the generator point */
#ifdef USE_ENDOMORPHISM
/* constants related to secp256k1's efficiently computable endomorphism */
secp256k1_fe_t beta;
- secp256k1_num_t lambda, a1b2, b1, a2;
#endif
} secp256k1_ge_consts_t;
@@ -112,10 +109,6 @@ static void secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a);
#ifdef USE_ENDOMORPHISM
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
-
-/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (given that a is
- not more than 256 bits). */
-static void secp256k1_gej_split_exp_var(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a);
#endif
/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */
@@ -124,5 +117,4 @@ static void secp256k1_gej_clear(secp256k1_gej_t *r);
/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */
static void secp256k1_ge_clear(secp256k1_ge_t *r);
-
#endif
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 1edbc6e099..cbd0d8c4fc 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -208,29 +208,25 @@ static int secp256k1_ge_is_valid(const secp256k1_ge_t *a) {
}
static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
- if (a->infinity) {
- r->infinity = 1;
- return;
- }
-
- secp256k1_fe_t t5 = a->y;
- secp256k1_fe_normalize(&t5);
- if (secp256k1_fe_is_zero(&t5)) {
- r->infinity = 1;
+ // For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
+ // Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
+ // y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
+ r->infinity = a->infinity;
+ if (r->infinity) {
return;
}
secp256k1_fe_t t1,t2,t3,t4;
- secp256k1_fe_mul(&r->z, &t5, &a->z);
+ secp256k1_fe_mul(&r->z, &a->z, &a->y);
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
secp256k1_fe_sqr(&t1, &a->x);
secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */
secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */
- secp256k1_fe_sqr(&t3, &t5);
+ secp256k1_fe_sqr(&t3, &a->y);
secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */
secp256k1_fe_sqr(&t4, &t3);
secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */
- secp256k1_fe_mul(&t3, &a->x, &t3); /* T3 = 2*X*Y^2 (1) */
+ secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */
r->x = t3;
secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */
secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
@@ -241,7 +237,6 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *
secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */
secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
- r->infinity = 0;
}
static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
@@ -342,7 +337,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
*
* Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives:
* U1 = X1*Z2^2, U2 = X2*Z1^2
- * S1 = X1*Z2^3, S2 = X2*Z2^3
+ * S1 = Y1*Z2^3, S2 = Y2*Z1^3
* Z = Z1*Z2
* T = U1+U2
* M = S1+S2
@@ -414,40 +409,9 @@ static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *
*r = *a;
secp256k1_fe_mul(&r->x, &r->x, beta);
}
-
-static void secp256k1_gej_split_exp_var(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a) {
- const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
- secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
-
- secp256k1_num_copy(&bnn2, &c->order);
- secp256k1_num_shift(&bnn2, 1);
-
- secp256k1_num_mul(&bnc1, a, &c->a1b2);
- secp256k1_num_add(&bnc1, &bnc1, &bnn2);
- secp256k1_num_div(&bnc1, &bnc1, &c->order);
-
- secp256k1_num_mul(&bnc2, a, &c->b1);
- secp256k1_num_add(&bnc2, &bnc2, &bnn2);
- secp256k1_num_div(&bnc2, &bnc2, &c->order);
-
- secp256k1_num_mul(&bnt1, &bnc1, &c->a1b2);
- secp256k1_num_mul(&bnt2, &bnc2, &c->a2);
- secp256k1_num_add(&bnt1, &bnt1, &bnt2);
- secp256k1_num_sub(r1, a, &bnt1);
- secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
- secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
- secp256k1_num_sub(r2, &bnt1, &bnt2);
-}
#endif
-
static void secp256k1_ge_start(void) {
- static const unsigned char secp256k1_ge_consts_order[] = {
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
- 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
- 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
- };
static const unsigned char secp256k1_ge_consts_g_x[] = {
0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
@@ -462,47 +426,21 @@ static void secp256k1_ge_start(void) {
};
#ifdef USE_ENDOMORPHISM
/* properties of secp256k1's efficiently computable endomorphism */
- static const unsigned char secp256k1_ge_consts_lambda[] = {
- 0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
- 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
- 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
- 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72
- };
static const unsigned char secp256k1_ge_consts_beta[] = {
0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee
};
- static const unsigned char secp256k1_ge_consts_a1b2[] = {
- 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
- 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
- };
- static const unsigned char secp256k1_ge_consts_b1[] = {
- 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
- 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
- };
- static const unsigned char secp256k1_ge_consts_a2[] = {
- 0x01,
- 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
- 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
- };
#endif
if (secp256k1_ge_consts == NULL) {
secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t));
- secp256k1_num_set_bin(&ret->order, secp256k1_ge_consts_order, sizeof(secp256k1_ge_consts_order));
- secp256k1_num_copy(&ret->half_order, &ret->order);
- secp256k1_num_shift(&ret->half_order, 1);
#ifdef USE_ENDOMORPHISM
- secp256k1_num_set_bin(&ret->lambda, secp256k1_ge_consts_lambda, sizeof(secp256k1_ge_consts_lambda));
- secp256k1_num_set_bin(&ret->a1b2, secp256k1_ge_consts_a1b2, sizeof(secp256k1_ge_consts_a1b2));
- secp256k1_num_set_bin(&ret->a2, secp256k1_ge_consts_a2, sizeof(secp256k1_ge_consts_a2));
- secp256k1_num_set_bin(&ret->b1, secp256k1_ge_consts_b1, sizeof(secp256k1_ge_consts_b1));
- secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta);
+ VERIFY_CHECK(secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta));
#endif
secp256k1_fe_t g_x, g_y;
- secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x);
- secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y);
+ VERIFY_CHECK(secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x));
+ VERIFY_CHECK(secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y));
secp256k1_ge_set_xy(&ret->g, &g_x, &g_y);
secp256k1_ge_consts = ret;
}
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index c86f847858..339b6bb6ec 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -7,6 +7,8 @@
#ifndef _SECP256K1_NUM_
#define _SECP256K1_NUM_
+#ifndef USE_NUM_NONE
+
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
@@ -17,9 +19,6 @@
#error "Please select num implementation"
#endif
-/** Clear a number to prevent the leak of sensitive data. */
-static void secp256k1_num_clear(secp256k1_num_t *r);
-
/** Copy a number. */
static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
@@ -30,15 +29,9 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec
/** Set a number to the value of a binary big-endian string. */
static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
-/** Set a number equal to a (signed) integer. */
-static void secp256k1_num_set_int(secp256k1_num_t *r, int a);
-
/** Compute a modular inverse. The input must be less than the modulus. */
static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
-/** Multiply two numbers modulo another. */
-static void secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m);
-
/** Compare the absolute value of two numbers. */
static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
@@ -54,47 +47,22 @@ static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, cons
/** Multiply two (signed) numbers. */
static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
-/** Divide two (signed) numbers. */
-static void secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
-
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
even if r was negative. */
static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
-/** Calculate the number of bits in (the absolute value of) a number. */
-static int secp256k1_num_bits(const secp256k1_num_t *a);
-
-/** Right-shift the passed number by bits bits, and return those bits. */
-static int secp256k1_num_shift(secp256k1_num_t *r, int bits);
+/** Right-shift the passed number by bits bits. */
+static void secp256k1_num_shift(secp256k1_num_t *r, int bits);
/** Check whether a number is zero. */
static int secp256k1_num_is_zero(const secp256k1_num_t *a);
-/** Check whether a number is odd. */
-static int secp256k1_num_is_odd(const secp256k1_num_t *a);
-
/** Check whether a number is strictly negative. */
static int secp256k1_num_is_neg(const secp256k1_num_t *a);
-/** Check whether a particular bit is set in a number. */
-static int secp256k1_num_get_bit(const secp256k1_num_t *a, int pos);
-
-/** Increase a number by 1. */
-static void secp256k1_num_inc(secp256k1_num_t *r);
-
-/** Set a number equal to the value of a hex string (unsigned). */
-static void secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen);
-
-/** Convert (the absolute value of) a number to a hexadecimal string. */
-static void secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a);
-
-/** Split a number into a low and high part. */
-static void secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
-
/** Change a number's sign. */
static void secp256k1_num_negate(secp256k1_num_t *r);
-/** Get a bunch of bits from a number. */
-static int secp256k1_num_get_bits(const secp256k1_num_t *a, int offset, int count);
+#endif
#endif
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index e45a59e0cd..19d474e59f 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -22,35 +22,10 @@ static void secp256k1_num_sanity(const secp256k1_num_t *a) {
#define secp256k1_num_sanity(a) do { } while(0)
#endif
-static void secp256k1_num_init(secp256k1_num_t *r) {
- r->neg = 0;
- r->limbs = 1;
- r->data[0] = 0;
-}
-
-static void secp256k1_num_clear(secp256k1_num_t *r) {
- memset(r, 0, sizeof(*r));
-}
-
-static void secp256k1_num_free(secp256k1_num_t *r) {
- (void)r;
-}
-
static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
*r = *a;
}
-static int secp256k1_num_bits(const secp256k1_num_t *a) {
- int ret=(a->limbs-1)*GMP_NUMB_BITS;
- mp_limb_t x=a->data[a->limbs-1];
- while (x) {
- x >>= 1;
- ret++;
- }
- return ret;
-}
-
-
static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned char tmp[65];
int len = 0;
@@ -71,18 +46,16 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un
VERIFY_CHECK(alen > 0);
VERIFY_CHECK(alen <= 64);
int len = mpn_set_str(r->data, a, alen, 256);
+ if (len == 0) {
+ r->data[0] = 0;
+ len = 1;
+ }
VERIFY_CHECK(len <= NUM_LIMBS*2);
r->limbs = len;
r->neg = 0;
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
}
-static void secp256k1_num_set_int(secp256k1_num_t *r, int a) {
- r->limbs = 1;
- r->neg = (a < 0);
- r->data[0] = (a < 0) ? -a : a;
-}
-
static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
r->limbs = a->limbs;
@@ -161,10 +134,6 @@ static int secp256k1_num_is_zero(const secp256k1_num_t *a) {
return (a->limbs == 1 && a->data[0] == 0);
}
-static int secp256k1_num_is_odd(const secp256k1_num_t *a) {
- return a->data[0] & 1;
-}
-
static int secp256k1_num_is_neg(const secp256k1_num_t *a) {
return (a->limbs > 1 || a->data[0] != 0) && a->neg;
}
@@ -237,140 +206,27 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons
memset(tmp, 0, sizeof(tmp));
}
-static void secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
- secp256k1_num_sanity(a);
- secp256k1_num_sanity(b);
- if (b->limbs > a->limbs) {
- r->limbs = 1;
- r->data[0] = 0;
- r->neg = 0;
- return;
- }
-
- mp_limb_t quo[2*NUM_LIMBS+1];
- mp_limb_t rem[2*NUM_LIMBS+1];
- mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs);
- mpn_copyi(r->data, quo, a->limbs - b->limbs + 1);
- r->limbs = a->limbs - b->limbs + 1;
- while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--;
- r->neg = a->neg ^ b->neg;
-}
-
-static void secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
- secp256k1_num_mul(r, a, b);
- secp256k1_num_mod(r, m);
-}
-
-
-static int secp256k1_num_shift(secp256k1_num_t *r, int bits) {
- VERIFY_CHECK(bits <= GMP_NUMB_BITS);
- mp_limb_t ret = mpn_rshift(r->data, r->data, r->limbs, bits);
- if (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
- ret >>= (GMP_NUMB_BITS - bits);
- return ret;
-}
-
-static int secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
- return (a->limbs*GMP_NUMB_BITS > pos) && ((a->data[pos/GMP_NUMB_BITS] >> (pos % GMP_NUMB_BITS)) & 1);
-}
-
-static void secp256k1_num_inc(secp256k1_num_t *r) {
- mp_limb_t ret = mpn_add_1(r->data, r->data, r->limbs, (mp_limb_t)1);
- if (ret) {
- VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);
- r->data[r->limbs++] = ret;
- }
-}
-
-static void secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
- static const unsigned char cvt[256] = {
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
- 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0
- };
- unsigned char num[257] = {};
- for (int i=0; i<alen; i++) {
- num[i] = cvt[(unsigned char)a[i]];
- }
- r->limbs = mpn_set_str(r->data, num, alen, 16);
- r->neg = 0;
- while (r->limbs > 1 && r->data[r->limbs-1] == 0) r->limbs--;
-}
-
-static void secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
- static const unsigned char cvt[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- unsigned char *tmp = malloc(257);
- mp_size_t len = mpn_get_str(tmp, 16, (mp_limb_t*)a->data, a->limbs);
- VERIFY_CHECK(len <= rlen);
- for (int i=0; i<len; i++) {
- VERIFY_CHECK(rlen-len+i >= 0);
- VERIFY_CHECK(rlen-len+i < rlen);
- VERIFY_CHECK(tmp[i] < 16);
- r[rlen-len+i] = cvt[tmp[i]];
- }
- for (int i=0; i<rlen-len; i++) {
- VERIFY_CHECK(i >= 0);
- VERIFY_CHECK(i < rlen);
- r[i] = cvt[0];
- }
- free(tmp);
-}
-
-static void secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
- VERIFY_CHECK(bits > 0);
- rh->neg = a->neg;
- if (bits >= a->limbs * GMP_NUMB_BITS) {
- *rl = *a;
- rh->limbs = 1;
- rh->data[0] = 0;
- return;
- }
- rl->limbs = 0;
- rl->neg = a->neg;
- int left = bits;
- while (left >= GMP_NUMB_BITS) {
- rl->data[rl->limbs] = a->data[rl->limbs];
- rl->limbs++;
- left -= GMP_NUMB_BITS;
- }
- if (left == 0) {
- mpn_copyi(rh->data, a->data + rl->limbs, a->limbs - rl->limbs);
- rh->limbs = a->limbs - rl->limbs;
- } else {
- mpn_rshift(rh->data, a->data + rl->limbs, a->limbs - rl->limbs, left);
- rh->limbs = a->limbs - rl->limbs;
- while (rh->limbs>1 && rh->data[rh->limbs-1]==0) rh->limbs--;
- }
- if (left > 0) {
- rl->data[rl->limbs] = a->data[rl->limbs] & ((((mp_limb_t)1) << left) - 1);
- rl->limbs++;
+static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
+ if (bits % GMP_NUMB_BITS) {
+ // Shift within limbs.
+ mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
+ }
+ if (bits >= GMP_NUMB_BITS) {
+ // Shift full limbs.
+ for (int i = 0; i < r->limbs; i++) {
+ int index = i + (bits / GMP_NUMB_BITS);
+ if (index < r->limbs && index < 2*NUM_LIMBS) {
+ r->data[i] = r->data[index];
+ } else {
+ r->data[i] = 0;
+ }
+ }
}
- while (rl->limbs>1 && rl->data[rl->limbs-1]==0) rl->limbs--;
+ while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
}
static void secp256k1_num_negate(secp256k1_num_t *r) {
r->neg ^= 1;
}
-static int secp256k1_num_get_bits(const secp256k1_num_t *a, int offset, int count) {
- int ret = 0;
- for (int i = 0; i < count; i++) {
- ret |= ((a->data[(offset + i) / GMP_NUMB_BITS] >> ((offset + i) % GMP_NUMB_BITS)) & 1) << i;
- }
- return ret;
-}
-
#endif
diff --git a/src/secp256k1/src/num_impl.h b/src/secp256k1/src/num_impl.h
index f73d3ceea8..0b0e3a072a 100644
--- a/src/secp256k1/src/num_impl.h
+++ b/src/secp256k1/src/num_impl.h
@@ -15,6 +15,8 @@
#if defined(USE_NUM_GMP)
#include "num_gmp_impl.h"
+#elif defined(USE_NUM_NONE)
+/* Nothing. */
#else
#error "Please select num implementation"
#endif
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index 3baacb3721..2f5ba0d447 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -21,20 +21,32 @@
#error "Please select scalar implementation"
#endif
+static void secp256k1_scalar_start(void);
+static void secp256k1_scalar_stop(void);
+
/** Clear a scalar to prevent the leak of sensitive data. */
static void secp256k1_scalar_clear(secp256k1_scalar_t *r);
-/** Access bits from a scalar. */
-static int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count);
+/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */
+static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count);
+
+/** Access bits from a scalar. Not constant time. */
+static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count);
/** Set a scalar from a big endian byte array. */
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow);
+/** Set a scalar to an unsigned integer. */
+static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v);
+
/** Convert a scalar to a byte array. */
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a);
-/** Add two scalars together (modulo the group order). */
-static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
+/** Add two scalars together (modulo the group order). Returns whether it overflowed. */
+static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
+
+/** Add a power of two to a scalar. The result is not allowed to overflow. */
+static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit);
/** Multiply two scalars (modulo the group order). */
static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
@@ -45,6 +57,9 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
/** Compute the inverse of a scalar (modulo the group order). */
static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
+/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */
+static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
+
/** Compute the complement of a scalar (modulo the group order). */
static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
@@ -57,7 +72,25 @@ static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a);
/** Check whether a scalar is higher than the group order divided by 2. */
static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a);
+#ifndef USE_NUM_NONE
/** Convert a scalar to a number. */
static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a);
+/** Get the order of the group as a number. */
+static void secp256k1_scalar_order_get_num(secp256k1_num_t *r);
+#endif
+
+/** Compare two scalars. */
+static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
+
+static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
+
+#ifdef USE_ENDOMORPHISM
+/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */
+static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
+#endif
+
+/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
+static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift);
+
#endif
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index f78718234f..d144775220 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -33,9 +33,27 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
r->d[3] = 0;
}
-SECP256K1_INLINE static int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) {
- VERIFY_CHECK((offset + count - 1) / 64 == offset / 64);
- return (a->d[offset / 64] >> (offset % 64)) & ((((uint64_t)1) << count) - 1);
+SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) {
+ r->d[0] = v;
+ r->d[1] = 0;
+ r->d[2] = 0;
+ r->d[3] = 0;
+}
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+ VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
+ return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
+}
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+ VERIFY_CHECK(count < 32);
+ VERIFY_CHECK(offset + count <= 256);
+ if ((offset + count - 1) >> 6 == offset >> 6) {
+ return secp256k1_scalar_get_bits(a, offset, count);
+ } else {
+ VERIFY_CHECK((offset >> 6) + 1 < 4);
+ return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1);
+ }
}
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) {
@@ -63,7 +81,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig
return overflow;
}
-static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
uint128_t t = (uint128_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[1] + b->d[1];
@@ -72,7 +90,26 @@ static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[3] + b->d[3];
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- secp256k1_scalar_reduce(r, t + secp256k1_scalar_check_overflow(r));
+ int overflow = t + secp256k1_scalar_check_overflow(r);
+ VERIFY_CHECK(overflow == 0 || overflow == 1);
+ secp256k1_scalar_reduce(r, overflow);
+ return overflow;
+}
+
+static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
+ VERIFY_CHECK(bit < 256);
+ uint128_t t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
+ r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
+ t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
+ r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
+ t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));
+ r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
+ t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
+ r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;
+#ifdef VERIFY
+ VERIFY_CHECK((t >> 64) == 0);
+ VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
+#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
@@ -280,13 +317,11 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
-static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
/* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0;
- uint64_t l[8];
-
/* l[0..7] = a[0..3] * b[0..3]. */
muladd_fast(a->d[0], b->d[0]);
extract_fast(l[0]);
@@ -313,17 +348,13 @@ static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[6]);
VERIFY_CHECK(c1 <= 0);
l[7] = c0;
-
- secp256k1_scalar_reduce_512(r, l);
}
-static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) {
/* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0;
- uint64_t l[8];
-
/* l[0..7] = a[0..3] * b[0..3]. */
muladd_fast(a->d[0], a->d[0]);
extract_fast(l[0]);
@@ -344,8 +375,6 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[6]);
VERIFY_CHECK(c1 == 0);
l[7] = c0;
-
- secp256k1_scalar_reduce_512(r, l);
}
#undef sumadd
@@ -356,4 +385,47 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
#undef extract
#undef extract_fast
+static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+ uint64_t l[8];
+ secp256k1_scalar_mul_512(l, a, b);
+ secp256k1_scalar_reduce_512(r, l);
+}
+
+static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+ uint64_t l[8];
+ secp256k1_scalar_sqr_512(l, a);
+ secp256k1_scalar_reduce_512(r, l);
+}
+
+static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
+ r1->d[0] = a->d[0];
+ r1->d[1] = a->d[1];
+ r1->d[2] = 0;
+ r1->d[3] = 0;
+ r2->d[0] = a->d[2];
+ r2->d[1] = a->d[3];
+ r2->d[2] = 0;
+ r2->d[3] = 0;
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+ return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0;
+}
+
+SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
+ VERIFY_CHECK(shift >= 256);
+ uint64_t l[8];
+ secp256k1_scalar_mul_512(l, a, b);
+ unsigned int shiftlimbs = shift >> 6;
+ unsigned int shiftlow = shift & 0x3F;
+ unsigned int shifthigh = 64 - shiftlow;
+ r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0;
+ if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) {
+ secp256k1_scalar_add_bit(r, 0);
+ }
+}
+
#endif
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index e58be1365f..915cbcddbe 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -45,9 +45,31 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
r->d[7] = 0;
}
-SECP256K1_INLINE static int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) {
- VERIFY_CHECK((offset + count - 1) / 32 == offset / 32);
- return (a->d[offset / 32] >> (offset % 32)) & ((1 << count) - 1);
+SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) {
+ r->d[0] = v;
+ r->d[1] = 0;
+ r->d[2] = 0;
+ r->d[3] = 0;
+ r->d[4] = 0;
+ r->d[5] = 0;
+ r->d[6] = 0;
+ r->d[7] = 0;
+}
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+ VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
+ return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
+}
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+ VERIFY_CHECK(count < 32);
+ VERIFY_CHECK(offset + count <= 256);
+ if ((offset + count - 1) >> 5 == offset >> 5) {
+ return secp256k1_scalar_get_bits(a, offset, count);
+ } else {
+ VERIFY_CHECK((offset >> 5) + 1 < 8);
+ return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1);
+ }
}
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) {
@@ -89,7 +111,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3
return overflow;
}
-static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
uint64_t t = (uint64_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[1] + b->d[1];
@@ -106,7 +128,34 @@ static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[7] + b->d[7];
r->d[7] = t & 0xFFFFFFFFULL; t >>= 32;
- secp256k1_scalar_reduce(r, t + secp256k1_scalar_check_overflow(r));
+ int overflow = t + secp256k1_scalar_check_overflow(r);
+ VERIFY_CHECK(overflow == 0 || overflow == 1);
+ secp256k1_scalar_reduce(r, overflow);
+ return overflow;
+}
+
+static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
+ VERIFY_CHECK(bit < 256);
+ uint64_t t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
+ r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
+ r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F));
+ r->d[2] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F));
+ r->d[3] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F));
+ r->d[4] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F));
+ r->d[5] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F));
+ r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
+ t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F));
+ r->d[7] = t & 0xFFFFFFFFULL;
+#ifdef VERIFY
+ VERIFY_CHECK((t >> 32) == 0);
+ VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
+#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
@@ -405,12 +454,10 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
-static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul_512(uint32_t l[16], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
- uint32_t l[16];
-
/* l[0..15] = a[0..7] * b[0..7]. */
muladd_fast(a->d[0], b->d[0]);
extract_fast(l[0]);
@@ -493,16 +540,12 @@ static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[14]);
VERIFY_CHECK(c1 == 0);
l[15] = c0;
-
- secp256k1_scalar_reduce_512(r, l);
}
-static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_sqr_512(uint32_t l[16], const secp256k1_scalar_t *a) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
- uint32_t l[16];
-
/* l[0..15] = a[0..7]^2. */
muladd_fast(a->d[0], a->d[0]);
extract_fast(l[0]);
@@ -557,8 +600,6 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[14]);
VERIFY_CHECK(c1 == 0);
l[15] = c0;
-
- secp256k1_scalar_reduce_512(r, l);
}
#undef sumadd
@@ -569,4 +610,59 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
#undef extract
#undef extract_fast
+static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+ uint32_t l[16];
+ secp256k1_scalar_mul_512(l, a, b);
+ secp256k1_scalar_reduce_512(r, l);
+}
+
+static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+ uint32_t l[16];
+ secp256k1_scalar_sqr_512(l, a);
+ secp256k1_scalar_reduce_512(r, l);
+}
+
+static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
+ r1->d[0] = a->d[0];
+ r1->d[1] = a->d[1];
+ r1->d[2] = a->d[2];
+ r1->d[3] = a->d[3];
+ r1->d[4] = 0;
+ r1->d[5] = 0;
+ r1->d[6] = 0;
+ r1->d[7] = 0;
+ r2->d[0] = a->d[4];
+ r2->d[1] = a->d[5];
+ r2->d[2] = a->d[6];
+ r2->d[3] = a->d[7];
+ r2->d[4] = 0;
+ r2->d[5] = 0;
+ r2->d[6] = 0;
+ r2->d[7] = 0;
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+ return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
+}
+
+SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
+ VERIFY_CHECK(shift >= 256);
+ uint32_t l[16];
+ secp256k1_scalar_mul_512(l, a, b);
+ unsigned int shiftlimbs = shift >> 5;
+ unsigned int shiftlow = shift & 0x1F;
+ unsigned int shifthigh = 32 - shiftlow;
+ r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0;
+ r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0;
+ if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) {
+ secp256k1_scalar_add_bit(r, 0);
+ }
+}
+
#endif
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index ddc5061c76..7fc159df77 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -9,6 +9,7 @@
#include <string.h>
+#include "group.h"
#include "scalar.h"
#if defined HAVE_CONFIG_H
@@ -23,12 +24,132 @@
#error "Please select scalar implementation"
#endif
+typedef struct {
+#ifndef USE_NUM_NONE
+ secp256k1_num_t order;
+#endif
+#ifdef USE_ENDOMORPHISM
+ secp256k1_scalar_t minus_lambda, minus_b1, minus_b2, g1, g2;
+#endif
+} secp256k1_scalar_consts_t;
+
+static const secp256k1_scalar_consts_t *secp256k1_scalar_consts = NULL;
+
+static void secp256k1_scalar_start(void) {
+ if (secp256k1_scalar_consts != NULL)
+ return;
+
+ /* Allocate. */
+ secp256k1_scalar_consts_t *ret = (secp256k1_scalar_consts_t*)malloc(sizeof(secp256k1_scalar_consts_t));
+
+#ifndef USE_NUM_NONE
+ static const unsigned char secp256k1_scalar_consts_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
+ };
+ secp256k1_num_set_bin(&ret->order, secp256k1_scalar_consts_order, sizeof(secp256k1_scalar_consts_order));
+#endif
+#ifdef USE_ENDOMORPHISM
+ /**
+ * Lambda is a scalar which has the property for secp256k1 that point multiplication by
+ * it is efficiently computable (see secp256k1_gej_mul_lambda). */
+ static const unsigned char secp256k1_scalar_consts_lambda[32] = {
+ 0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
+ 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
+ 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
+ 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72
+ };
+ /**
+ * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm
+ * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1
+ * and k2 have a small size.
+ * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are:
+ *
+ * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
+ * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}
+ * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}
+ * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
+ *
+ * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives
+ * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and
+ * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2.
+ *
+ * g1, g2 are precomputed constants used to replace division with a rounded multiplication
+ * when decomposing the scalar for an endomorphism-based point multiplication.
+ *
+ * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
+ * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
+ *
+ * The derivation is described in the paper "Efficient Software Implementation of Public-Key
+ * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
+ * Section 4.3 (here we use a somewhat higher-precision estimate):
+ * d = a1*b2 - b1*a2
+ * g1 = round((2^272)*b2/d)
+ * g2 = round((2^272)*b1/d)
+ *
+ * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
+ * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
+ */
+ static const unsigned char secp256k1_scalar_consts_minus_b1[32] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
+ 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
+ };
+ static const unsigned char secp256k1_scalar_consts_b2[32] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
+ 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
+ };
+ static const unsigned char secp256k1_scalar_consts_g1[32] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x86,
+ 0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,
+ 0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab
+ };
+ static const unsigned char secp256k1_scalar_consts_g2[32] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x43,
+ 0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,
+ 0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12
+ };
+
+ secp256k1_scalar_set_b32(&ret->minus_lambda, secp256k1_scalar_consts_lambda, NULL);
+ secp256k1_scalar_negate(&ret->minus_lambda, &ret->minus_lambda);
+ secp256k1_scalar_set_b32(&ret->minus_b1, secp256k1_scalar_consts_minus_b1, NULL);
+ secp256k1_scalar_set_b32(&ret->minus_b2, secp256k1_scalar_consts_b2, NULL);
+ secp256k1_scalar_negate(&ret->minus_b2, &ret->minus_b2);
+ secp256k1_scalar_set_b32(&ret->g1, secp256k1_scalar_consts_g1, NULL);
+ secp256k1_scalar_set_b32(&ret->g2, secp256k1_scalar_consts_g2, NULL);
+#endif
+
+ /* Set the global pointer. */
+ secp256k1_scalar_consts = ret;
+}
+
+static void secp256k1_scalar_stop(void) {
+ if (secp256k1_scalar_consts == NULL)
+ return;
+
+ secp256k1_scalar_consts_t *c = (secp256k1_scalar_consts_t*)secp256k1_scalar_consts;
+ secp256k1_scalar_consts = NULL;
+ free(c);
+}
+
+#ifndef USE_NUM_NONE
static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) {
unsigned char c[32];
secp256k1_scalar_get_b32(c, a);
secp256k1_num_set_bin(r, c, 32);
}
+static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) {
+ *r = secp256k1_scalar_consts->order;
+}
+#endif
static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
/* First compute x ^ (2^N - 1) for some values of N. */
@@ -181,4 +302,35 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal
secp256k1_scalar_mul(r, t, &x6); /* 111111 */
}
+static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
+#if defined(USE_SCALAR_INV_BUILTIN)
+ secp256k1_scalar_inverse(r, x);
+#elif defined(USE_SCALAR_INV_NUM)
+ unsigned char b[32];
+ secp256k1_scalar_get_b32(b, x);
+ secp256k1_num_t n;
+ secp256k1_num_set_bin(&n, b, 32);
+ secp256k1_num_mod_inverse(&n, &n, &secp256k1_scalar_consts->order);
+ secp256k1_num_get_bin(b, 32, &n);
+ secp256k1_scalar_set_b32(r, b, NULL);
+#else
+#error "Please select scalar inverse implementation"
+#endif
+}
+
+#ifdef USE_ENDOMORPHISM
+static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
+ VERIFY_CHECK(r1 != a);
+ VERIFY_CHECK(r2 != a);
+ secp256k1_scalar_t c1, c2;
+ secp256k1_scalar_mul_shift_var(&c1, a, &secp256k1_scalar_consts->g1, 272);
+ secp256k1_scalar_mul_shift_var(&c2, a, &secp256k1_scalar_consts->g2, 272);
+ secp256k1_scalar_mul(&c1, &c1, &secp256k1_scalar_consts->minus_b1);
+ secp256k1_scalar_mul(&c2, &c2, &secp256k1_scalar_consts->minus_b2);
+ secp256k1_scalar_add(r2, &c1, &c2);
+ secp256k1_scalar_mul(r1, r2, &secp256k1_scalar_consts->minus_lambda);
+ secp256k1_scalar_add(r1, r1, a);
+}
+#endif
+
#endif
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 1ab5b3722c..20fc27df74 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -21,6 +21,8 @@
void secp256k1_start(unsigned int flags) {
secp256k1_fe_start();
secp256k1_ge_start();
+ secp256k1_scalar_start();
+ secp256k1_ecdsa_start();
if (flags & SECP256K1_START_SIGN) {
secp256k1_ecmult_gen_start();
}
@@ -32,6 +34,8 @@ void secp256k1_start(unsigned int flags) {
void secp256k1_stop(void) {
secp256k1_ecmult_stop();
secp256k1_ecmult_gen_stop();
+ secp256k1_ecdsa_stop();
+ secp256k1_scalar_stop();
secp256k1_ge_stop();
secp256k1_fe_stop();
}
@@ -43,11 +47,13 @@ int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned
DEBUG_CHECK(sig != NULL);
DEBUG_CHECK(pubkey != NULL);
+ unsigned char msg32[32] = {0};
+ memcpy(msg32 + 32 - msglen, msg, msglen);
int ret = -3;
- secp256k1_num_t m;
+ secp256k1_scalar_t m;
secp256k1_ecdsa_sig_t s;
secp256k1_ge_t q;
- secp256k1_num_set_bin(&m, msg, msglen);
+ secp256k1_scalar_set_b32(&m, msg32, NULL);
if (!secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) {
ret = -1;
@@ -123,8 +129,8 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, u
ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
}
if (ret) {
- secp256k1_num_get_bin(sig64, 32, &sig.r);
- secp256k1_num_get_bin(sig64 + 32, 32, &sig.s);
+ secp256k1_scalar_get_b32(sig64, &sig.r);
+ secp256k1_scalar_get_b32(sig64 + 32, &sig.s);
}
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
@@ -142,11 +148,20 @@ int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const
DEBUG_CHECK(recid >= 0 && recid <= 3);
int ret = 0;
- secp256k1_num_t m;
+ unsigned char msg32[32] = {0};
+ memcpy(msg32 + 32 - msglen, msg, msglen);
+ secp256k1_scalar_t m;
secp256k1_ecdsa_sig_t sig;
- secp256k1_num_set_bin(&sig.r, sig64, 32);
- secp256k1_num_set_bin(&sig.s, sig64 + 32, 32);
- secp256k1_num_set_bin(&m, msg, msglen);
+ int overflow = 0;
+ secp256k1_scalar_set_b32(&sig.r, sig64, &overflow);
+ if (overflow) {
+ return 0;
+ }
+ secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow);
+ if (overflow) {
+ return 0;
+ }
+ secp256k1_scalar_set_b32(&m, msg32, NULL);
secp256k1_ge_t q;
if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
@@ -224,8 +239,12 @@ int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const un
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(tweak != NULL);
- secp256k1_num_t term;
- secp256k1_num_set_bin(&term, tweak, 32);
+ secp256k1_scalar_t term;
+ int overflow = 0;
+ secp256k1_scalar_set_b32(&term, tweak, &overflow);
+ if (overflow) {
+ return 0;
+ }
secp256k1_ge_t p;
int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
if (ret) {
@@ -264,8 +283,12 @@ int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const un
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(tweak != NULL);
- secp256k1_num_t factor;
- secp256k1_num_set_bin(&factor, tweak, 32);
+ secp256k1_scalar_t factor;
+ int overflow = 0;
+ secp256k1_scalar_set_b32(&factor, tweak, &overflow);
+ if (overflow) {
+ return 0;
+ }
secp256k1_ge_t p;
int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
if (ret) {
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 5d9b8344d9..78cdd67f27 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -23,23 +23,13 @@
static int count = 64;
-/***** NUM TESTS *****/
-
-void random_num_negate(secp256k1_num_t *num) {
- if (secp256k1_rand32() & 1)
- secp256k1_num_negate(num);
-}
-
void random_field_element_test(secp256k1_fe_t *fe) {
do {
unsigned char b32[32];
secp256k1_rand256_test(b32);
- secp256k1_num_t num;
- secp256k1_num_set_bin(&num, b32, 32);
- if (secp256k1_num_cmp(&num, &secp256k1_fe_consts->p) >= 0)
- continue;
- secp256k1_fe_set_b32(fe, b32);
- break;
+ if (secp256k1_fe_set_b32(fe, b32)) {
+ break;
+ }
} while(1);
}
@@ -75,19 +65,6 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge
gej->infinity = ge->infinity;
}
-void random_num_order_test(secp256k1_num_t *num) {
- do {
- unsigned char b32[32];
- secp256k1_rand256_test(b32);
- secp256k1_num_set_bin(num, b32, 32);
- if (secp256k1_num_is_zero(num))
- continue;
- if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
- continue;
- break;
- } while(1);
-}
-
void random_scalar_order_test(secp256k1_scalar_t *num) {
do {
unsigned char b32[32];
@@ -100,82 +77,36 @@ void random_scalar_order_test(secp256k1_scalar_t *num) {
} while(1);
}
-void random_num_order(secp256k1_num_t *num) {
+void random_scalar_order(secp256k1_scalar_t *num) {
do {
unsigned char b32[32];
secp256k1_rand256(b32);
- secp256k1_num_set_bin(num, b32, 32);
- if (secp256k1_num_is_zero(num))
- continue;
- if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
+ int overflow = 0;
+ secp256k1_scalar_set_b32(num, b32, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(num))
continue;
break;
} while(1);
}
-void test_num_copy_inc_cmp(void) {
- secp256k1_num_t n1,n2;
- random_num_order(&n1);
- secp256k1_num_copy(&n2, &n1);
- CHECK(secp256k1_num_eq(&n1, &n2));
- CHECK(secp256k1_num_eq(&n2, &n1));
- secp256k1_num_inc(&n2);
- CHECK(!secp256k1_num_eq(&n1, &n2));
- CHECK(!secp256k1_num_eq(&n2, &n1));
-}
-
+/***** NUM TESTS *****/
-void test_num_get_set_hex(void) {
- secp256k1_num_t n1,n2;
- random_num_order_test(&n1);
- char c[64];
- secp256k1_num_get_hex(c, 64, &n1);
- secp256k1_num_set_hex(&n2, c, 64);
- CHECK(secp256k1_num_eq(&n1, &n2));
- for (int i=0; i<64; i++) {
- /* check whether the lower 4 bits correspond to the last hex character */
- int low1 = secp256k1_num_shift(&n1, 4);
- int lowh = c[63];
- int low2 = ((lowh>>6)*9+(lowh-'0'))&15;
- CHECK(low1 == low2);
- /* shift bits off the hex representation, and compare */
- memmove(c+1, c, 63);
- c[0] = '0';
- secp256k1_num_set_hex(&n2, c, 64);
- CHECK(secp256k1_num_eq(&n1, &n2));
- }
+#ifndef USE_NUM_NONE
+void random_num_negate(secp256k1_num_t *num) {
+ if (secp256k1_rand32() & 1)
+ secp256k1_num_negate(num);
}
-void test_num_get_set_bin(void) {
- secp256k1_num_t n1,n2;
- random_num_order_test(&n1);
- unsigned char c[32];
- secp256k1_num_get_bin(c, 32, &n1);
- secp256k1_num_set_bin(&n2, c, 32);
- CHECK(secp256k1_num_eq(&n1, &n2));
- for (int i=0; i<32; i++) {
- /* check whether the lower 8 bits correspond to the last byte */
- int low1 = secp256k1_num_shift(&n1, 8);
- int low2 = c[31];
- CHECK(low1 == low2);
- /* shift bits off the byte representation, and compare */
- memmove(c+1, c, 31);
- c[0] = 0;
- secp256k1_num_set_bin(&n2, c, 32);
- CHECK(secp256k1_num_eq(&n1, &n2));
- }
+void random_num_order_test(secp256k1_num_t *num) {
+ secp256k1_scalar_t sc;
+ random_scalar_order_test(&sc);
+ secp256k1_scalar_get_num(num, &sc);
}
-void run_num_int(void) {
- secp256k1_num_t n1;
- for (int i=-255; i<256; i++) {
- unsigned char c1[3] = {};
- c1[2] = abs(i);
- unsigned char c2[3] = {0x11,0x22,0x33};
- secp256k1_num_set_int(&n1, i);
- secp256k1_num_get_bin(c2, 3, &n1);
- CHECK(memcmp(c1, c2, 3) == 0);
- }
+void random_num_order(secp256k1_num_t *num) {
+ secp256k1_scalar_t sc;
+ random_scalar_order(&sc);
+ secp256k1_scalar_get_num(num, &sc);
}
void test_num_negate(void) {
@@ -229,82 +160,84 @@ void test_num_add_sub(void) {
void run_num_smalltests(void) {
for (int i=0; i<100*count; i++) {
- test_num_copy_inc_cmp();
- test_num_get_set_hex();
- test_num_get_set_bin();
test_num_negate();
test_num_add_sub();
}
- run_num_int();
}
+#endif
/***** SCALAR TESTS *****/
-int secp256k1_scalar_eq(const secp256k1_scalar_t *s1, const secp256k1_scalar_t *s2) {
- secp256k1_scalar_t t;
- secp256k1_scalar_negate(&t, s2);
- secp256k1_scalar_add(&t, &t, s1);
- int ret = secp256k1_scalar_is_zero(&t);
- return ret;
-}
-
void scalar_test(void) {
unsigned char c[32];
/* Set 's' to a random scalar, with value 'snum'. */
- secp256k1_rand256_test(c);
secp256k1_scalar_t s;
- secp256k1_scalar_set_b32(&s, c, NULL);
- secp256k1_num_t snum;
- secp256k1_num_set_bin(&snum, c, 32);
- secp256k1_num_mod(&snum, &secp256k1_ge_consts->order);
+ random_scalar_order_test(&s);
/* Set 's1' to a random scalar, with value 's1num'. */
- secp256k1_rand256_test(c);
secp256k1_scalar_t s1;
- secp256k1_scalar_set_b32(&s1, c, NULL);
- secp256k1_num_t s1num;
- secp256k1_num_set_bin(&s1num, c, 32);
- secp256k1_num_mod(&s1num, &secp256k1_ge_consts->order);
+ random_scalar_order_test(&s1);
/* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */
- secp256k1_rand256_test(c);
secp256k1_scalar_t s2;
- int overflow = 0;
- secp256k1_scalar_set_b32(&s2, c, &overflow);
- secp256k1_num_t s2num;
- secp256k1_num_set_bin(&s2num, c, 32);
- secp256k1_num_mod(&s2num, &secp256k1_ge_consts->order);
+ random_scalar_order_test(&s2);
+ secp256k1_scalar_get_b32(c, &s2);
+
+#ifndef USE_NUM_NONE
+ secp256k1_num_t snum, s1num, s2num;
+ secp256k1_scalar_get_num(&snum, &s);
+ secp256k1_scalar_get_num(&s1num, &s1);
+ secp256k1_scalar_get_num(&s2num, &s2);
+
+ secp256k1_num_t order;
+ secp256k1_scalar_order_get_num(&order);
+ secp256k1_num_t half_order = order;
+ secp256k1_num_shift(&half_order, 1);
+#endif
{
/* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */
- secp256k1_num_t n, t, m;
- secp256k1_num_set_int(&n, 0);
- secp256k1_num_set_int(&m, 16);
+ secp256k1_scalar_t n;
+ secp256k1_scalar_set_int(&n, 0);
for (int i = 0; i < 256; i += 4) {
- secp256k1_num_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));
- secp256k1_num_mul(&n, &n, &m);
- secp256k1_num_add(&n, &n, &t);
+ secp256k1_scalar_t t;
+ secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));
+ for (int j = 0; j < 4; j++) {
+ secp256k1_scalar_add(&n, &n, &n);
+ }
+ secp256k1_scalar_add(&n, &n, &t);
}
- CHECK(secp256k1_num_eq(&n, &snum));
+ CHECK(secp256k1_scalar_eq(&n, &s));
}
{
- /* Test that get_b32 returns the same as get_bin on the number. */
- unsigned char r1[32];
- secp256k1_scalar_get_b32(r1, &s2);
- unsigned char r2[32];
- secp256k1_num_get_bin(r2, 32, &s2num);
- CHECK(memcmp(r1, r2, 32) == 0);
- /* If no overflow occurred when assigning, it should also be equal to the original byte array. */
- CHECK((memcmp(r1, c, 32) == 0) == (overflow == 0));
+ /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */
+ secp256k1_scalar_t n;
+ secp256k1_scalar_set_int(&n, 0);
+ int i = 0;
+ while (i < 256) {
+ int now = (secp256k1_rand32() % 15) + 1;
+ if (now + i > 256) {
+ now = 256 - i;
+ }
+ secp256k1_scalar_t t;
+ secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now));
+ for (int j = 0; j < now; j++) {
+ secp256k1_scalar_add(&n, &n, &n);
+ }
+ secp256k1_scalar_add(&n, &n, &t);
+ i += now;
+ }
+ CHECK(secp256k1_scalar_eq(&n, &s));
}
+#ifndef USE_NUM_NONE
{
/* Test that adding the scalars together is equal to adding their numbers together modulo the order. */
secp256k1_num_t rnum;
secp256k1_num_add(&rnum, &snum, &s2num);
- secp256k1_num_mod(&rnum, &secp256k1_ge_consts->order);
+ secp256k1_num_mod(&rnum, &order);
secp256k1_scalar_t r;
secp256k1_scalar_add(&r, &s, &s2);
secp256k1_num_t r2num;
@@ -316,7 +249,7 @@ void scalar_test(void) {
/* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */
secp256k1_num_t rnum;
secp256k1_num_mul(&rnum, &snum, &s2num);
- secp256k1_num_mod(&rnum, &secp256k1_ge_consts->order);
+ secp256k1_num_mod(&rnum, &order);
secp256k1_scalar_t r;
secp256k1_scalar_mul(&r, &s, &s2);
secp256k1_num_t r2num;
@@ -333,14 +266,14 @@ void scalar_test(void) {
/* Check that comparison with zero matches comparison with zero on the number. */
CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s));
/* Check that comparison with the half order is equal to testing for high scalar. */
- CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &secp256k1_ge_consts->half_order) > 0));
+ CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0));
secp256k1_scalar_t neg;
secp256k1_scalar_negate(&neg, &s);
secp256k1_num_t negnum;
- secp256k1_num_sub(&negnum, &secp256k1_ge_consts->order, &snum);
- secp256k1_num_mod(&negnum, &secp256k1_ge_consts->order);
+ secp256k1_num_sub(&negnum, &order, &snum);
+ secp256k1_num_mod(&negnum, &order);
/* Check that comparison with the half order is equal to testing for high scalar after negation. */
- CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &secp256k1_ge_consts->half_order) > 0));
+ CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0));
/* Negating should change the high property, unless the value was already zero. */
CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s));
secp256k1_num_t negnum2;
@@ -356,15 +289,36 @@ void scalar_test(void) {
}
{
+ /* Test secp256k1_scalar_mul_shift_var. */
+ secp256k1_scalar_t r;
+ unsigned int shift = 256 + (secp256k1_rand32() % 257);
+ secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift);
+ secp256k1_num_t rnum;
+ secp256k1_num_mul(&rnum, &s1num, &s2num);
+ secp256k1_num_shift(&rnum, shift - 1);
+ secp256k1_num_t one;
+ unsigned char cone[1] = {0x01};
+ secp256k1_num_set_bin(&one, cone, 1);
+ secp256k1_num_add(&rnum, &rnum, &one);
+ secp256k1_num_shift(&rnum, 1);
+ secp256k1_num_t rnum2;
+ secp256k1_scalar_get_num(&rnum2, &r);
+ CHECK(secp256k1_num_eq(&rnum, &rnum2));
+ }
+#endif
+
+ {
/* Test that scalar inverses are equal to the inverse of their number modulo the order. */
if (!secp256k1_scalar_is_zero(&s)) {
secp256k1_scalar_t inv;
secp256k1_scalar_inverse(&inv, &s);
+#ifndef USE_NUM_NONE
secp256k1_num_t invnum;
- secp256k1_num_mod_inverse(&invnum, &snum, &secp256k1_ge_consts->order);
+ secp256k1_num_mod_inverse(&invnum, &snum, &order);
secp256k1_num_t invnum2;
secp256k1_scalar_get_num(&invnum2, &inv);
CHECK(secp256k1_num_eq(&invnum, &invnum2));
+#endif
secp256k1_scalar_mul(&inv, &inv, &s);
/* Multiplying a scalar with its inverse must result in one. */
CHECK(secp256k1_scalar_is_one(&inv));
@@ -383,6 +337,23 @@ void scalar_test(void) {
}
{
+ /* Test add_bit. */
+ int bit = secp256k1_rand32() % 256;
+ secp256k1_scalar_t b;
+ secp256k1_scalar_set_int(&b, 1);
+ CHECK(secp256k1_scalar_is_one(&b));
+ for (int i = 0; i < bit; i++) {
+ secp256k1_scalar_add(&b, &b, &b);
+ }
+ secp256k1_scalar_t r1 = s1, r2 = s1;
+ if (!secp256k1_scalar_add(&r1, &r1, &b)) {
+ /* No overflow happened. */
+ secp256k1_scalar_add_bit(&r2, bit);
+ CHECK(secp256k1_scalar_eq(&r1, &r2));
+ }
+ }
+
+ {
/* Test commutativity of mul. */
secp256k1_scalar_t r1, r2;
secp256k1_scalar_mul(&r1, &s1, &s2);
@@ -428,20 +399,49 @@ void scalar_test(void) {
secp256k1_scalar_mul(&r2, &s1, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2));
}
+
}
void run_scalar_tests(void) {
for (int i = 0; i < 128 * count; i++) {
scalar_test();
}
+
+ {
+ /* (-1)+1 should be zero. */
+ secp256k1_scalar_t s, o;
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_negate(&o, &s);
+ secp256k1_scalar_add(&o, &o, &s);
+ CHECK(secp256k1_scalar_is_zero(&o));
+ }
+
+#ifndef USE_NUM_NONE
+ {
+ /* A scalar with value of the curve order should be 0. */
+ secp256k1_num_t order;
+ secp256k1_scalar_order_get_num(&order);
+ unsigned char bin[32];
+ secp256k1_num_get_bin(bin, 32, &order);
+ secp256k1_scalar_t zero;
+ int overflow = 0;
+ secp256k1_scalar_set_b32(&zero, bin, &overflow);
+ CHECK(overflow == 1);
+ CHECK(secp256k1_scalar_is_zero(&zero));
+ }
+#endif
}
/***** FIELD TESTS *****/
void random_fe(secp256k1_fe_t *x) {
unsigned char bin[32];
- secp256k1_rand256(bin);
- secp256k1_fe_set_b32(x, bin);
+ do {
+ secp256k1_rand256(bin);
+ if (secp256k1_fe_set_b32(x, bin)) {
+ return;
+ }
+ } while(1);
}
void random_fe_non_zero(secp256k1_fe_t *nz) {
@@ -617,9 +617,17 @@ void gej_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
}
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);
@@ -697,39 +705,51 @@ void run_ge(void) {
void run_ecmult_chain(void) {
/* random starting point A (on the curve) */
- secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64);
- secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
+ secp256k1_fe_t ax; VERIFY_CHECK(secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64));
+ secp256k1_fe_t ay; VERIFY_CHECK(secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64));
secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay);
/* two random initial factors xn and gn */
- secp256k1_num_t xn;
- secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64);
- secp256k1_num_t gn;
- secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64);
+ static const unsigned char xni[32] = {
+ 0x84, 0xcc, 0x54, 0x52, 0xf7, 0xfd, 0xe1, 0xed,
+ 0xb4, 0xd3, 0x8a, 0x8c, 0xe9, 0xb1, 0xb8, 0x4c,
+ 0xce, 0xf3, 0x1f, 0x14, 0x6e, 0x56, 0x9b, 0xe9,
+ 0x70, 0x5d, 0x35, 0x7a, 0x42, 0x98, 0x54, 0x07
+ };
+ secp256k1_scalar_t xn;
+ secp256k1_scalar_set_b32(&xn, xni, NULL);
+ static const unsigned char gni[32] = {
+ 0xa1, 0xe5, 0x8d, 0x22, 0x55, 0x3d, 0xcd, 0x42,
+ 0xb2, 0x39, 0x80, 0x62, 0x5d, 0x4c, 0x57, 0xa9,
+ 0x6e, 0x93, 0x23, 0xd4, 0x2b, 0x31, 0x52, 0xe5,
+ 0xca, 0x2c, 0x39, 0x90, 0xed, 0xc7, 0xc9, 0xde
+ };
+ secp256k1_scalar_t gn;
+ secp256k1_scalar_set_b32(&gn, gni, NULL);
/* two small multipliers to be applied to xn and gn in every iteration: */
- secp256k1_num_t xf;
- secp256k1_num_set_hex(&xf, "1337", 4);
- secp256k1_num_t gf;
- secp256k1_num_set_hex(&gf, "7113", 4);
+ static const unsigned char xfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x13,0x37};
+ secp256k1_scalar_t xf;
+ secp256k1_scalar_set_b32(&xf, xfi, NULL);
+ static const unsigned char gfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x71,0x13};
+ secp256k1_scalar_t gf;
+ secp256k1_scalar_set_b32(&gf, gfi, NULL);
/* accumulators with the resulting coefficients to A and G */
- secp256k1_num_t ae;
- secp256k1_num_set_int(&ae, 1);
- secp256k1_num_t ge;
- secp256k1_num_set_int(&ge, 0);
+ secp256k1_scalar_t ae;
+ secp256k1_scalar_set_int(&ae, 1);
+ secp256k1_scalar_t ge;
+ secp256k1_scalar_set_int(&ge, 0);
/* the point being computed */
secp256k1_gej_t x = a;
- const secp256k1_num_t *order = &secp256k1_ge_consts->order;
for (int i=0; i<200*count; i++) {
/* in each iteration, compute X = xn*X + gn*G; */
secp256k1_ecmult(&x, &x, &xn, &gn);
/* also compute ae and ge: the actual accumulated factors for A and G */
/* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */
- secp256k1_num_mod_mul(&ae, &ae, &xn, order);
- secp256k1_num_mod_mul(&ge, &ge, &xn, order);
- secp256k1_num_add(&ge, &ge, &gn);
- secp256k1_num_mod(&ge, order);
+ secp256k1_scalar_mul(&ae, &ae, &xn);
+ secp256k1_scalar_mul(&ge, &ge, &xn);
+ secp256k1_scalar_add(&ge, &ge, &gn);
/* modify xn and gn */
- secp256k1_num_mod_mul(&xn, &xn, &xf, order);
- secp256k1_num_mod_mul(&gn, &gn, &gf, order);
+ secp256k1_scalar_mul(&xn, &xn, &xf);
+ secp256k1_scalar_mul(&gn, &gn, &gf);
/* verify */
if (i == 19999) {
@@ -749,17 +769,25 @@ void run_ecmult_chain(void) {
}
void test_point_times_order(const secp256k1_gej_t *point) {
- /* multiplying a point by the order results in O */
- const secp256k1_num_t *order = &secp256k1_ge_consts->order;
- secp256k1_num_t zero;
- secp256k1_num_set_int(&zero, 0);
- secp256k1_gej_t res;
- secp256k1_ecmult(&res, point, order, order); /* calc res = order * point + order * G; */
- CHECK(secp256k1_gej_is_infinity(&res));
+ /* X * (point + G) + (order-X) * (pointer + G) = 0 */
+ secp256k1_scalar_t x;
+ random_scalar_order_test(&x);
+ secp256k1_scalar_t nx;
+ secp256k1_scalar_negate(&nx, &x);
+ secp256k1_gej_t res1, res2;
+ secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */
+ secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */
+ secp256k1_gej_add_var(&res1, &res1, &res2);
+ CHECK(secp256k1_gej_is_infinity(&res1));
+ CHECK(secp256k1_gej_is_valid(&res1) == 0);
+ secp256k1_ge_t res3;
+ secp256k1_ge_set_gej(&res3, &res1);
+ CHECK(secp256k1_ge_is_infinity(&res3));
+ CHECK(secp256k1_ge_is_valid(&res3) == 0);
}
void run_point_times_order(void) {
- secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2);
+ secp256k1_fe_t x; VERIFY_CHECK(secp256k1_fe_set_hex(&x, "02", 2));
for (int i=0; i<500; i++) {
secp256k1_ge_t p;
if (secp256k1_ge_set_xo(&p, &x, 1)) {
@@ -776,15 +804,16 @@ void run_point_times_order(void) {
CHECK(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
}
-void test_wnaf(const secp256k1_num_t *number, int w) {
- secp256k1_num_t x, two, t;
- secp256k1_num_set_int(&x, 0);
- secp256k1_num_set_int(&two, 2);
- int wnaf[257];
+void test_wnaf(const secp256k1_scalar_t *number, int w) {
+ secp256k1_scalar_t x, two, t;
+ secp256k1_scalar_set_int(&x, 0);
+ secp256k1_scalar_set_int(&two, 2);
+ int wnaf[256];
int bits = secp256k1_ecmult_wnaf(wnaf, number, w);
+ CHECK(bits <= 256);
int zeroes = -1;
for (int i=bits-1; i>=0; i--) {
- secp256k1_num_mul(&x, &x, &two);
+ secp256k1_scalar_mul(&x, &x, &two);
int v = wnaf[i];
if (v) {
CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */
@@ -796,18 +825,23 @@ void test_wnaf(const secp256k1_num_t *number, int w) {
CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */
zeroes++;
}
- secp256k1_num_set_int(&t, v);
- secp256k1_num_add(&x, &x, &t);
+ if (v >= 0) {
+ secp256k1_scalar_set_int(&t, v);
+ } else {
+ secp256k1_scalar_set_int(&t, -v);
+ secp256k1_scalar_negate(&t, &t);
+ }
+ secp256k1_scalar_add(&x, &x, &t);
}
- CHECK(secp256k1_num_eq(&x, number)); /* check that wnaf represents number */
+ CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */
}
void run_wnaf(void) {
- secp256k1_num_t n;
+ secp256k1_scalar_t n;
for (int i=0; i<count; i++) {
- random_num_order(&n);
+ random_scalar_order(&n);
if (i % 1)
- secp256k1_num_negate(&n);
+ secp256k1_scalar_negate(&n, &n);
test_wnaf(&n, 4+(i%10));
}
}
@@ -820,18 +854,22 @@ void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, cons
}
void test_ecdsa_sign_verify(void) {
+ int recid;
+ int getrec;
secp256k1_scalar_t msg, key;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key);
secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj);
secp256k1_ecdsa_sig_t sig;
- random_sign(&sig, &key, &msg, NULL);
- secp256k1_num_t msg_num;
- secp256k1_scalar_get_num(&msg_num, &msg);
- CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg_num));
- secp256k1_num_inc(&msg_num);
- CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg_num));
+ getrec = secp256k1_rand32()&1;
+ random_sign(&sig, &key, &msg, getrec?&recid:NULL);
+ if (getrec) CHECK(recid >= 0 && recid < 4);
+ CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
+ secp256k1_scalar_t one;
+ secp256k1_scalar_set_int(&one, 1);
+ secp256k1_scalar_add(&msg, &msg, &one);
+ CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
}
void run_ecdsa_sign_verify(void) {
@@ -846,11 +884,11 @@ void test_ecdsa_end_to_end(void) {
/* Generate a random key and message. */
{
- secp256k1_num_t msg, key;
- random_num_order_test(&msg);
- random_num_order_test(&key);
- secp256k1_num_get_bin(privkey, 32, &key);
- secp256k1_num_get_bin(message, 32, &msg);
+ secp256k1_scalar_t msg, key;
+ random_scalar_order_test(&msg);
+ random_scalar_order_test(&key);
+ secp256k1_scalar_get_b32(privkey, &key);
+ secp256k1_scalar_get_b32(message, &msg);
}
/* Construct and verify corresponding public key. */
@@ -935,7 +973,8 @@ void run_ecdsa_end_to_end(void) {
}
}
-void test_ecdsa_infinity(void) {
+/* Tests several edge cases. */
+void test_ecdsa_edge_cases(void) {
const unsigned char msg32[32] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
@@ -943,8 +982,8 @@ void test_ecdsa_infinity(void) {
's', 's', 'a', 'g', 'e', '.', '.', '.'
};
const unsigned char sig64[64] = {
- // Generated by signing the above message with nonce 'This is the nonce we will use...'
- // and secret key 0 (which is not valid), resulting in recid 0.
+ /* Generated by signing the above message with nonce 'This is the nonce we will use...'
+ * and secret key 0 (which is not valid), resulting in recid 0. */
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
@@ -960,10 +999,93 @@ void test_ecdsa_infinity(void) {
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 1));
CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 2));
CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 3));
+
+ /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
+ const unsigned char sigb64[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ };
+ unsigned char pubkeyb[33];
+ int pubkeyblen = 33;
+ for (int recid = 0; recid < 4; recid++) {
+ /* (4,4) encoded in DER. */
+ unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
+ /* (order + r,4) encoded in DER. */
+ unsigned char sigbderlong[40] = {
+ 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,
+ 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
+ 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
+ };
+ CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkeyb, &pubkeyblen, 1, recid));
+ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1);
+ for (int recid2 = 0; recid2 < 4; recid2++) {
+ unsigned char pubkey2b[33];
+ int pubkey2blen = 33;
+ CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkey2b, &pubkey2blen, 1, recid2));
+ /* Verifying with (order + r,4) should always fail. */
+ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1);
+ }
+ /* Damage signature. */
+ sigbder[7]++;
+ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0);
+ }
+
+ /* Test the case where ECDSA recomputes a point that is infinity. */
+ {
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_scalar_set_int(&sig.s, 1);
+ secp256k1_scalar_negate(&sig.s, &sig.s);
+ secp256k1_scalar_inverse(&sig.s, &sig.s);
+ secp256k1_scalar_set_int(&sig.r, 1);
+ secp256k1_gej_t keyj;
+ secp256k1_ecmult_gen(&keyj, &sig.r);
+ secp256k1_ge_t key;
+ secp256k1_ge_set_gej(&key, &keyj);
+ secp256k1_scalar_t msg = sig.s;
+ CHECK(secp256k1_ecdsa_sig_verify(&sig, &key, &msg) == 0);
+ }
+
+ /* Test r/s equal to zero */
+ {
+ /* (1,1) encoded in DER. */
+ unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
+ unsigned char sigc64[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ };
+ unsigned char pubkeyc[65];
+ int pubkeyclen = 65;
+ CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1);
+ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1);
+ sigcder[4] = 0;
+ sigc64[31] = 0;
+ CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
+ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
+ sigcder[4] = 1;
+ sigcder[7] = 0;
+ sigc64[31] = 1;
+ sigc64[63] = 0;
+ CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
+ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
+ }
}
-void run_ecdsa_infinity(void) {
- test_ecdsa_infinity();
+void run_ecdsa_edge_cases(void) {
+ test_ecdsa_edge_cases();
}
#ifdef ENABLE_OPENSSL_TESTS
@@ -996,11 +1118,12 @@ void test_ecdsa_openssl(void) {
CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
secp256k1_ecdsa_sig_t sig;
CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
- secp256k1_num_t msg_num;
- secp256k1_scalar_get_num(&msg_num, &msg);
- CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg_num));
- secp256k1_num_inc(&sig.r);
- CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg_num));
+ CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
+ secp256k1_scalar_t one;
+ secp256k1_scalar_set_int(&one, 1);
+ secp256k1_scalar_t msg2;
+ secp256k1_scalar_add(&msg2, &msg, &one);
+ CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg2));
random_sign(&sig, &key, &msg, NULL);
int secp_sigsize = 80;
@@ -1042,8 +1165,19 @@ int main(int argc, char **argv) {
/* initialize */
secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY);
+ /* initializing a second time shouldn't cause any harm or memory leaks. */
+ secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY);
+
+ /* Likewise, re-running the internal init functions should be harmless. */
+ secp256k1_fe_start();
+ secp256k1_ge_start();
+ secp256k1_scalar_start();
+ secp256k1_ecdsa_start();
+
+#ifndef USE_NUM_NONE
/* num tests */
run_num_smalltests();
+#endif
/* scalar tests */
run_scalar_tests();
@@ -1067,7 +1201,7 @@ int main(int argc, char **argv) {
/* ecdsa tests */
run_ecdsa_sign_verify();
run_ecdsa_end_to_end();
- run_ecdsa_infinity();
+ run_ecdsa_edge_cases();
#ifdef ENABLE_OPENSSL_TESTS
run_ecdsa_openssl();
#endif
@@ -1076,5 +1210,14 @@ int main(int argc, char **argv) {
/* shutdown */
secp256k1_stop();
+
+ /* shutting down twice shouldn't cause any double frees. */
+ secp256k1_stop();
+
+ /* Same for the internal shutdown functions. */
+ secp256k1_fe_stop();
+ secp256k1_ge_stop();
+ secp256k1_scalar_stop();
+ secp256k1_ecdsa_stop();
return 0;
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 96b47057c0..08b23a9d38 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -61,4 +61,21 @@
#define VERIFY_CHECK(cond) do { (void)(cond); } while(0)
#endif
+/* Macro for restrict, when available and not in a VERIFY build. */
+#if defined(SECP256K1_BUILD) && defined(VERIFY)
+# define SECP256K1_RESTRICT
+#else
+# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if SECP256K1_GNUC_PREREQ(3,0)
+# define SECP256K1_RESTRICT __restrict__
+# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
+# define SECP256K1_RESTRICT __restrict
+# else
+# define SECP256K1_RESTRICT
+# endif
+# else
+# define SECP256K1_RESTRICT restrict
+# endif
+#endif
+
#endif
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 783e284af5..2de226fdd6 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -7,10 +7,12 @@
#include "base58.h"
#include "clientversion.h"
#include "key.h"
-#include "main.h"
+#include "merkleblock.h"
#include "serialize.h"
+#include "streams.h"
#include "uint256.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <vector>
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 71e757714c..86d39b5c20 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -1,12 +1,10 @@
[
-["
-Format is: [scriptPubKey, scriptSig, flags, ... comments]
-It is evaluated as if there was a crediting coinbase transaction with two 0
-pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,
-followed by a spending transaction which spends this output as only input (and
-correct prevout hash), using the given scriptSig. All nLockTimes are 0, all
-nSequences are max.
-"],
+["Format is: [scriptPubKey, scriptSig, flags, ... comments]"],
+["It is evaluated as if there was a crediting coinbase transaction with two 0"],
+["pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,"],
+["followed by a spending transaction which spends this output as only input (and"],
+["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"],
+["nSequences are max."],
["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"],
[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."],
@@ -496,177 +494,175 @@ nSequences are max.
["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
+["Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of"],
+["pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded"],
+["signatures and pubkeys."],
[
- "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",
+ "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
+ "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT",
+ "STRICTENC",
+ "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded."
+],
+[
+ "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0",
+ "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
+ "STRICTENC",
+ "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid."
+],
+
+["Automatically generated test cases"],
+[
+ "0x47 0x3044022053205076a7bb12d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
"P2PK, bad sig"
],
[
- "0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
+ "0x47 0x30440220151ea78fa148b59f399b23731b634645ebc142f299ee9838d46fb78cf7e0bc0102200d62327dcd54ac6bcfb1516b035b1bf8eaea438c52c62d3450d1f3a8f030e0de01 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
"DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG",
"",
"P2PKH, bad pubkey"
],
[
- "0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01",
+ "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"",
"P2PK anyonecanpay marked with normal hashtype"
],
[
- "0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "0x47 0x304402202166fcd5e607de452d3c6f15e059505cf21654346592f9650ba906b9e8be88fa022005d976d28eb8de477102feba28807b3ad361e7fa24796d259c9d61452f7c318c01 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
"P2SH",
"P2SH(P2PK), bad redeemscript"
],
[
- "0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "0x47 0x3044022064cc90ca89ad721384b231653b945579359a24b928ef8539b331172628c9cc6102203e238869ab5dac3fc293db53c12e7dd3079e86cfde9024b689efc7227e4d671001 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"P2SH",
"P2SH(P2PKH), bad sig"
],
[
- "0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101",
+ "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3, 2 sigs"
],
[
- "0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
"HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
"P2SH",
"P2SH(2-of-3), 1 sig"
],
[
- "0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501",
+ "0x47 0x30440220001d6702bfa4f49c3a2542af9b1c2844a2eaac55f86f310f42d26a5dd17d6a8002202cdadbe608c00b50dd951c6ba0877d5b07a970f3e265c18697bc413a0a86f69901",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
- "STRICTENC",
+ "DERSIG",
"P2PK with too much R padding"
],
[
- "0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901",
+ "0x48 0x304502207d2b258e959605e2ea50b46fea1325b7391ffb0c14a5b58ef8ad3851da3644380221007e75136df5f2e38216c4338b31c97e8307102edb97d611e06914e1f8fba68ead01",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
- "STRICTENC",
+ "DERSIG",
"P2PK with too much S padding"
],
[
- "0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201",
+ "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
- "STRICTENC",
+ "DERSIG",
"P2PK with too little R padding"
],
[
- "0x47 0x30440220001d0f82c127470cb38316c96b1719b33382353687a1146a776dee8259606905022062cd1fc8eacef819d68f0f41cc9ae9fdc2e29b70c3c7ad2c6c18f39b4e35c42701",
+ "0x47 0x30440220003040725f724b0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"DERSIG",
"P2PK NOT with bad sig with too much R padding"
],
[
- "0x47 0x30440220005d727e2a82d6e8a98a6da6fbc281325644d1a40455e386fdb17883a8e6bc4d02202d15cca42ce136047a980d288e60c679d7e84cce18c3ceffb6bc81b9e9ba517801",
+ "0x47 0x30440220003040725f724a0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"",
"P2PK NOT with too much R padding but no DERSIG"
],
[
- "0x47 0x30440220006e8bc4f82032b12bd594847c16d8b2986de734aa3b0528bd89d664d41e6d1c02200cfd582694891bcfa2e630e899bda257486eba00a007222fae71144dba07dc2901",
+ "0x47 0x30440220003040725f724a0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"DERSIG",
"P2PK NOT with too much R padding"
],
[
- "0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01",
+ "0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
- "LOW_S,STRICTENC",
+ "LOW_S",
"P2PK with high S"
],
[
- "0x47 0x304402203aab50cd7c30cc1e1475dee615b295bcee6ccf8aa8a7f6cda6b696c70d79cbb40220558e43fe7596c31146e2d077698d5a9c38351d8ba567549a2ae43ca97231c39501",
+ "0x47 0x30440220745d63eb70d45652128b450aa5ca7d9b513439963f261cb1c40a60f0785e7ee402204877785b38945ca9dbec78e1c1d4dd12148cc25c868bd27480023b49ae0f310501",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"STRICTENC",
"P2PK with hybrid pubkey"
],
[
- "0x47 0x304402205745e8f846110c185ee1185c01843a108588b81463d2c34d4a3f2445529f12fe02206ee6a2657bbc4e2bb74bfc44c3a5c4f410ed6356ca68982465de6ca807c807c201",
+ "0x47 0x30440220606f6f9f6cebc94ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"",
"P2PK NOT with hybrid pubkey but no STRICTENC"
],
[
- "0x47 0x3044022078033e4227aa05ded69d8da579966578e230d8a7fb44d5f1a0620c3853c24f78022006a2e3f4d872ac8dfdc529110aa37301d65a76255a4b6cce2992adacd4d2c4e201",
+ "0x47 0x30440220606f6f9f6cebc94ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"STRICTENC",
"P2PK NOT with hybrid pubkey"
],
[
- "0x47 0x304402207592427de20e315d644839754f2a5cca5b978b983a15e6da82109ede01722baa022032ceaf78590faa3f7743821e1b47b897ed1a57f6ee1c8a7519d23774d8de3c4401",
+ "0x47 0x30440220606f6f9f6cebc84ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"STRICTENC",
"P2PK NOT with invalid hybrid pubkey"
],
[
- "0 0x47 0x304402206797289d3dc81692edae58430276d04641ea5d86967be557163f8494da32fd78022006fc6ab77aaed4ac11ea69cd878ab26e3e24290f47a43e9adf34075d52b7142c01",
+ "0 0x47 0x304402203cdcf66792fe97e3955655ede5dad004950e58b369831ffa7743132c507b272c022031fbcfb4a72b3e00217abf2f5557585f1f9891f12827d2f0a2ae2978e7f9f11001",
"1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG",
"STRICTENC",
"1-of-2 with the first 1 hybrid pubkey"
],
[
- "0x47 0x304402201f82b99a813c9c48c8dee8d2c43b8f637b72353fe9bdcc084537bc17e2ab770402200c43b96a5f7e115f0114eabda32e068145965cb6c7b5ef64833bb4fcf9fc1b3b05",
+ "0x47 0x304402201c215cb13e4954e60ce4f6de74941904c771f998de7b1d9627e82a1949fde517022031c2197455f3dbecbb78321201308d7b039424e38d480772d7cd4eb465a083f405",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"STRICTENC",
"P2PK with undefined hashtype"
],
-
-["
-Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of
-pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded
-signatures and pubkeys.
-"],
-[
- "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
- "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT",
- "STRICTENC",
- "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded."
-],
-[
- "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0",
- "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
- "STRICTENC",
- "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid."
-],
-
[
- "0x47 0x30440220166848cd5b82a32b5944d90de3c35249354b43773c2ece1844ee8d1103e2f6c602203b6b046da4243c77adef80ada9201b27bbfdf7f9d5428f40434b060432afd62005",
+ "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
"STRICTENC",
"P2PK NOT with invalid sig and undefined hashtype"
],
[
- "0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301",
+ "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"NULLDUMMY",
"3-of-3 with nonzero dummy"
],
[
- "0x01 0x01 0x47 0x304402201847fc3b8f7597768e7f543c58da1fca6e8e35eb28979431e6b637572ce6eaa4022048dd58608e040841d0bf52a70cfb70e1a9c8d2826fad068f4e9d2bf5c87766a501 0x47 0x30440220711311a72516affed73363763983d05c3d6a06a2eadf5d76b90b4354162ba94302204841a69e5955a7dc8e4ab3105fd0c86040c1dac6016297a51ddbf5079c28756801 0x47 0x30440220267e331a378191e7282fd10d61c97bf74bc97c233c5833d677936424ac08dee502201eee83d88b91988e1c4d9b979df2404aa190e0987a8ca09c4e5cd61da1d48ecc01",
+ "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
"NULLDUMMY",
"3-of-3 NOT with invalid sig with nonzero dummy"
],
[
- "0 0x47 0x3044022035341cc377b19138f944f90c45772cb06338c6d56a4c0c31a65bf1a8a105fadc022046dd232850b6bacb25879c9da82a7a628982aa19d055f1753468f68047662e0301 DUP",
+ "0 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01 DUP",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"SIGPUSHONLY",
"2-of-2 with two identical keys and sigs pushed using OP_DUP"
],
[
- "0x47 0x304402204d8b99eea2f53382fd67e0dbc8ed0596bd614aa0dad6bc6843c7860c79b901c3022062f022a71993013e3d9b22302a8e4b40109d7bb057aeb250b9aab2197b3e96b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
+ "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"",
"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"
],
[
- "0x47 0x30440220078c887c33abc67fbbd827ceb3f661c1c459e78218161b652f23e3ca76cfabbd022047df245eacb8a88d8c5ca7b5228e3b4d070c102d2f542433362d3f443cd24eda01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
+ "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"SIGPUSHONLY",
"P2SH(P2PK) with non-push scriptSig"
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index ada45a64ed..d3075de646 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -1,12 +1,10 @@
[
-["
-Format is: [scriptPubKey, scriptSig, flags, ... comments]
-It is evaluated as if there was a crediting coinbase transaction with two 0
-pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,
-followed by a spending transaction which spends this output as only input (and
-correct prevout hash), using the given scriptSig. All nLockTimes are 0, all
-nSequences are max.
-"],
+["Format is: [scriptPubKey, scriptSig, flags, ... comments]"],
+["It is evaluated as if there was a crediting coinbase transaction with two 0"],
+["pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,"],
+["followed by a spending transaction which spends this output as only input (and"],
+["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"],
+["nSequences are max."],
["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"],
[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "and multiple spaces should not change that."],
@@ -664,160 +662,156 @@ nSequences are max.
["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", ""],
["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", ""],
+["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"],
+["script when it reaches an invalidly encoded signature or pubkey, we can use it"],
+["to test the exact order in which signatures and pubkeys are evaluated by"],
+["distinguishing CHECKMULTISIG returning false on the stack and the script as a"],
+["whole failing."],
+["See also the corresponding inverted versions of these tests in script_invalid.json"],
+[
+ "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
+ "2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
+ "STRICTENC",
+ "2-of-2 CHECKMULTISIG NOT with the second pubkey invalid, and both signatures validly encoded. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid pubkey."
+],
+[
+ "0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
+ "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
+ "STRICTENC",
+ "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."
+],
+["Automatically generated test cases"],
[
- "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",
+ "0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
"P2PK"
],
[
- "0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508",
+ "0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508",
"DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG",
"",
"P2PKH"
],
[
- "0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581",
+ "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"",
"P2PK anyonecanpay"
],
[
- "0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "0x47 0x304402202166fcd5e607de452d3c6f15e059505cf21654346592f9650ba906b9e8be88fa022005d976d28eb8de477102feba28807b3ad361e7fa24796d259c9d61452f7c318c01 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
"P2SH",
"P2SH(P2PK)"
],
[
- "0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "0x47 0x3044022064cc90ca89ad721384b231653b945579359a24b928ef8539b331172628c9cc6102203e238869ab5dac3fc293db53c12e7dd3079e86cfde9024b689efc7227e4d671001 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"",
"P2SH(P2PKH), bad sig but no VERIFY_P2SH"
],
[
- "0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801",
+ "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3"
],
[
- "0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x304402204511cf05e85c2be07c6c176c5338a08ed3cb34212667f39613340881169986c002207cc48b27aa3691a20706a5773ec9923cadd20fedffd00c24457d85f83f0b51fe01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
"HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
"P2SH",
"P2SH(2-of-3)"
],
[
- "0x47 0x30440220001fff8863c84c0efc8eea5bffb7f388313f966f23a00ad3c0acc30ff5339684022016e6d78f51a3a1c362745931ca40b24f71cba2903dbfe5a6d392a9189127d83701",
+ "0x47 0x30440220001d6702bfa4f49c3a2542af9b1c2844a2eaac55f86f310f42d26a5dd17d6a8002202cdadbe608c00b50dd951c6ba0877d5b07a970f3e265c18697bc413a0a86f69901",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
"P2PK with too much R padding but no DERSIG"
],
[
- "0x48 0x304502202323d56f293842b544cacedd06baafb999196dfa1c2975314848c158ac606655022100514bd98186b8a3a1cc87f4aff76aed797781389f13f50d87bf95b2df6e488fcc01",
+ "0x48 0x304502207d2b258e959605e2ea50b46fea1325b7391ffb0c14a5b58ef8ad3851da3644380221007e75136df5f2e38216c4338b31c97e8307102edb97d611e06914e1f8fba68ead01",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
"P2PK with too much S padding but no DERSIG"
],
[
- "0x47 0x30440220d31c24bb6c08a496e7698a08fd41975115d7b55bfaa31cb2d573e09481e59a6702206a691239996434076b78a4e1cf46fc8e993b468a9c77fb1832186aa8040a61a201",
+ "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
"P2PK with too little R padding but no DERSIG"
],
[
- "0x47 0x30440220007c2cc7aef1801c2937447703c87ef2a3744209ad98da2abadd4ba8bb2e3ea00220503a275582c9f9e9ff30260c81b7f64b8b696f22105605cc8241fb76a797316201",
+ "0x47 0x30440220003040725f724b0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"",
"P2PK NOT with bad sig with too much R padding but no DERSIG"
],
[
- "0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801",
+ "0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
- "STRICTENC",
+ "",
"P2PK with high S but no LOW_S"
],
[
- "0x47 0x304402202163bc732c21b7de0251297d3c6c2ece182782e85fc5e19d6036f1130a79051e022033827811634924ebba68767537d78dd7bd9109ae2a89a60587927abdc25eb06401",
+ "0x47 0x30440220745d63eb70d45652128b450aa5ca7d9b513439963f261cb1c40a60f0785e7ee402204877785b38945ca9dbec78e1c1d4dd12148cc25c868bd27480023b49ae0f310501",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
"P2PK with hybrid pubkey but no STRICTENC"
],
[
- "0x47 0x3044022078d6c447887e88dcbe1bc5b613645280df6f4e5935648bc226e9d91da71b3216022047d6b7ef0949b228fc1b359afb8d50500268711354298217b983c26970790c7601",
+ "0x47 0x30440220606f6f9f6cebc84ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"",
"P2PK NOT with invalid hybrid pubkey but no STRICTENC"
],
[
- "0 0x47 0x304402203b269b9fbc0936877bf855b5fb41757218d9548b246370d991442a5f5bd1c3440220235268a4eaa8c67e543c6e37da81dd36d3b1be2de6b4fef04113389ca6ddc04501",
+ "0 0x47 0x304402203a5ee39032637c431af0a3ac42e32e0627390bd44f6f98c9c04e6d714635ad0202207b42fcd889c3ae8a1b515608f38535f1f9be815176ee8d1b65a27c767cf37aed01",
"1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"",
"1-of-2 with the second 1 hybrid pubkey and no STRICTENC"
],
[
- "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
+ "0 0x47 0x304402203a5ee39032637c431af0a3ac42e32e0627390bd44f6f98c9c04e6d714635ad0202207b42fcd889c3ae8a1b515608f38535f1f9be815176ee8d1b65a27c767cf37aed01",
"1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"STRICTENC",
"1-of-2 with the second 1 hybrid pubkey"
],
-
-["
-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
-script when it reaches an invalidly encoded signature or pubkey, we can use it
-to test the exact order in which signatures and pubkeys are evaluated by
-distinguishing CHECKMULTISIG returning false on the stack and the script as a
-whole failing.
-
-See also the corresponding inverted versions of these tests in script_invalid.json
-"],
-[
- "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
- "2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
- "STRICTENC",
- "2-of-2 CHECKMULTISIG NOT with the second pubkey invalid, and both signatures validly encoded. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid pubkey."
-],
-[
- "0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
- "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
- "STRICTENC",
- "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."
-],
-
[
- "0x47 0x304402204649e9517ef0377a8f8270bd423053fd98ddff62d74ea553e9579558abbb75e4022044a2b2344469c12e35ed898987711272b634733dd0f5e051288eceb04bd4669e05",
+ "0x47 0x304402201c215cb13e4954e60ce4f6de74941904c771f998de7b1d9627e82a1949fde517022031c2197455f3dbecbb78321201308d7b039424e38d480772d7cd4eb465a083f405",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"",
"P2PK with undefined hashtype but no STRICTENC"
],
[
- "0x47 0x304402207f1cf1866a2df0bb4b8d84d0ade72aa3abb6aaab0639d608b23d9e10ead0c48202203caa97f22c3439443eea4b89f7f6729854df0f567a8184d6ecc6e8b6c68c3e9d05",
+ "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
"",
"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"
],
[
- "1 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
+ "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3 with nonzero dummy but no NULLDUMMY"
],
[
- "1 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
+ "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
"",
"3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
],
[
- "0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01 DUP",
+ "0 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01 DUP",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"",
"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"
],
[
- "0 0x47 0x304402203acf75dd59bbef171aeeedae4f1020b824195820db82575c2b323b8899f95de9022067df297d3a5fad049ba0bb81255d0e495643cbcf9abae9e396988618bc0c6dfe01 0x47 0x304402205f8b859230c1cab7d4e8de38ff244d2ebe046b64e8d3f4219b01e483c203490a022071bdc488e31b557f7d9e5c8a8bec90dc92289ca70fa317685f4f140e38b30c4601",
+ "0 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"SIGPUSHONLY",
"2-of-2 with two identical keys and sigs pushed"
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 78c4181409..bf57dd81d9 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "main.h"
#include <boost/test/unit_test.hpp>
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 9dce4daac6..3b535a84fd 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -2,9 +2,11 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
+#include "merkleblock.h"
#include "serialize.h"
+#include "streams.h"
#include "uint256.h"
+#include "version.h"
#include <vector>
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 53411190eb..4d2a9aff45 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -491,24 +491,18 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0).PushSig(keys.key1).PushSig(keys.key1));
- std::map<std::string, Array> tests_good;
- std::map<std::string, Array> tests_bad;
+ std::set<std::string> tests_good;
+ std::set<std::string> tests_bad;
{
Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
BOOST_FOREACH(Value& tv, json_good) {
- Array test = tv.get_array();
- if (test.size() >= 4) {
- tests_good[test[3].get_str()] = test;
- }
+ tests_good.insert(write_string(Value(tv.get_array()), true));
}
BOOST_FOREACH(Value& tv, json_bad) {
- Array test = tv.get_array();
- if (test.size() >= 4) {
- tests_bad[test[3].get_str()] = test;
- }
+ tests_bad.insert(write_string(Value(tv.get_array()), true));
}
}
@@ -517,27 +511,23 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- if (tests_good.count(test.GetComment()) == 0) {
+ std::string str = write_string(Value(test.GetJSON()), true);
#ifndef UPDATE_JSON_TESTS
+ if (tests_good.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
-#endif
- strGood += write_string(Value(test.GetJSON()), true) + ",\n";
- } else {
- BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment());
- strGood += write_string(Value(tests_good[test.GetComment()]), true) + ",\n";
}
+#endif
+ strGood += str + ",\n";
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- if (tests_bad.count(test.GetComment()) == 0) {
+ std::string str = write_string(Value(test.GetJSON()), true);
#ifndef UPDATE_JSON_TESTS
+ if (tests_bad.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
-#endif
- strBad += write_string(Value(test.GetJSON()), true) + ",\n";
- } else {
- BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment());
- strBad += write_string(Value(tests_bad[test.GetComment()]), true) + ",\n";
}
+#endif
+ strBad += str + ",\n";
}
#ifdef UPDATE_JSON_TESTS
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 67d50fccf4..feea140351 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -5,7 +5,7 @@
#include "util.h"
#include "clientversion.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "random.h"
#include "sync.h"
#include "utilstrencodings.h"
@@ -340,6 +340,7 @@ BOOST_AUTO_TEST_CASE(test_FormatParagraph)
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest");
BOOST_CHECK_EQUAL(FormatParagraph("testerde test ", 4, 0), "testerde\ntest");
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test");
+ BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string. This is a second sentence in the very long test string."), "This is a very long test string. This is a second sentence in the very long\ntest string.");
}
BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
diff --git a/src/txmempool.h b/src/txmempool.h
index e68b218154..d00bdd0616 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -10,7 +10,7 @@
#include "amount.h"
#include "coins.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "sync.h"
class CAutoFile;
diff --git a/src/undo.h b/src/undo.h
index 4f5f4047dd..2301bd8b43 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -7,7 +7,7 @@
#define BITCOIN_UNDO_H
#include "compressor.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "serialize.h"
/** Undo information for a CTxIn
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 085adae85e..3e076a0266 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -5,7 +5,7 @@
#include "utilmoneystr.h"
-#include "core/transaction.h"
+#include "primitives/transaction.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index d0062d4544..419a63c431 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -459,7 +459,7 @@ std::string FormatParagraph(const std::string in, size_t width, size_t indent)
}
// Append word
out << in.substr(ptr, endword - ptr);
- col += endword - ptr;
+ col += endword - ptr + 1;
ptr = endword;
}
return out.str();
diff --git a/src/wallet.h b/src/wallet.h
index 7bbb6419c8..2dd2146e8c 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -7,8 +7,8 @@
#define BITCOIN_WALLET_H
#include "amount.h"
-#include "core/block.h"
-#include "core/transaction.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "crypter.h"
#include "key.h"
#include "keystore.h"