aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--README.md14
-rw-r--r--configure.ac2
-rw-r--r--doc/build-unix.md12
-rw-r--r--doc/files.md2
-rw-r--r--doc/reducetraffic.md35
-rw-r--r--doc/release-notes.md38
-rw-r--r--doc/tor.md17
-rwxr-xr-xqa/pull-tester/rpc-tests.py182
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py2
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py3
-rwxr-xr-xqa/rpc-tests/mempool_packages.py19
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py2
-rw-r--r--qa/rpc-tests/test_framework/authproxy.py10
-rw-r--r--qa/rpc-tests/test_framework/coverage.py101
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py28
-rw-r--r--qa/rpc-tests/test_framework/util.py62
-rw-r--r--src/Makefile.am2
-rw-r--r--src/chainparams.cpp6
-rw-r--r--src/consensus/params.h3
-rw-r--r--src/init.cpp18
-rw-r--r--src/key.cpp155
-rw-r--r--src/main.cpp22
-rw-r--r--src/main.h8
-rw-r--r--src/net.cpp13
-rw-r--r--src/net.h3
-rw-r--r--src/netbase.cpp5
-rw-r--r--src/netbase.h4
-rw-r--r--src/script/sigcache.cpp91
-rw-r--r--src/script/sigcache.h4
-rw-r--r--src/secp256k1/.gitignore4
-rw-r--r--src/secp256k1/.travis.yml18
-rw-r--r--src/secp256k1/Makefile.am54
-rw-r--r--src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4125
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m418
-rw-r--r--src/secp256k1/configure.ac64
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.c150
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.h91
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.c113
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.h90
-rw-r--r--src/secp256k1/include/secp256k1.h696
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h31
-rw-r--r--src/secp256k1/include/secp256k1_recovery.h110
-rw-r--r--src/secp256k1/include/secp256k1_schnorr.h173
-rw-r--r--src/secp256k1/src/basic-config.h32
-rw-r--r--src/secp256k1/src/bench.h20
-rw-r--r--src/secp256k1/src/bench_ecdh.c53
-rw-r--r--src/secp256k1/src/bench_internal.c62
-rw-r--r--src/secp256k1/src/bench_recover.c25
-rw-r--r--src/secp256k1/src/bench_schnorr_verify.c73
-rw-r--r--src/secp256k1/src/bench_sign.c22
-rw-r--r--src/secp256k1/src/bench_verify.c28
-rw-r--r--src/secp256k1/src/ecdsa.h15
-rw-r--r--src/secp256k1/src/ecdsa_impl.h244
-rw-r--r--src/secp256k1/src/eckey.h17
-rw-r--r--src/secp256k1/src/eckey_impl.h127
-rw-r--r--src/secp256k1/src/ecmult.h20
-rw-r--r--src/secp256k1/src/ecmult_const.h15
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h260
-rw-r--r--src/secp256k1/src/ecmult_gen.h24
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h102
-rw-r--r--src/secp256k1/src/ecmult_impl.h268
-rw-r--r--src/secp256k1/src/field.h62
-rw-r--r--src/secp256k1/src/field_10x26.h24
-rw-r--r--src/secp256k1/src/field_10x26_impl.h54
-rw-r--r--src/secp256k1/src/field_5x52.h22
-rw-r--r--src/secp256k1/src/field_5x52_impl.h54
-rw-r--r--src/secp256k1/src/field_impl.h46
-rw-r--r--src/secp256k1/src/gen_context.c74
-rw-r--r--src/secp256k1/src/group.h106
-rw-r--r--src/secp256k1/src/group_impl.h369
-rw-r--r--src/secp256k1/src/hash.h2
-rw-r--r--src/secp256k1/src/hash_impl.h12
-rw-r--r--src/secp256k1/src/modules/ecdh/Makefile.am.include8
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h54
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h75
-rw-r--r--src/secp256k1/src/modules/recovery/Makefile.am.include8
-rw-r--r--src/secp256k1/src/modules/recovery/main_impl.h193
-rw-r--r--src/secp256k1/src/modules/recovery/tests_impl.h250
-rw-r--r--src/secp256k1/src/modules/schnorr/Makefile.am.include10
-rw-r--r--src/secp256k1/src/modules/schnorr/main_impl.h164
-rw-r--r--src/secp256k1/src/modules/schnorr/schnorr.h20
-rw-r--r--src/secp256k1/src/modules/schnorr/schnorr_impl.h207
-rw-r--r--src/secp256k1/src/modules/schnorr/tests_impl.h175
-rw-r--r--src/secp256k1/src/num.h28
-rw-r--r--src/secp256k1/src/num_gmp.h2
-rw-r--r--src/secp256k1/src/num_gmp_impl.h40
-rw-r--r--src/secp256k1/src/scalar.h57
-rw-r--r--src/secp256k1/src/scalar_4x64.h2
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h81
-rw-r--r--src/secp256k1/src/scalar_8x32.h2
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h90
-rw-r--r--src/secp256k1/src/scalar_impl.h40
-rw-r--r--src/secp256k1/src/secp256k1.c655
-rw-r--r--src/secp256k1/src/testrand.h12
-rw-r--r--src/secp256k1/src/testrand_impl.h86
-rw-r--r--src/secp256k1/src/tests.c3390
-rw-r--r--src/secp256k1/src/util.h26
-rw-r--r--src/test/mempool_tests.cpp4
-rw-r--r--src/torcontrol.cpp685
-rw-r--r--src/torcontrol.h20
101 files changed, 9145 insertions, 2073 deletions
diff --git a/.travis.yml b/.travis.yml
index 8e9684826f..d2fbfee6f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -69,6 +69,6 @@ script:
- make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false )
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- if [ "$RUN_TESTS" = "true" ]; then make check; fi
- - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py; fi
+ - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi
after_script:
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then (echo "Upload goes here. Something like: scp -r $BASE_OUTDIR server" || echo "upload failed"); fi
diff --git a/README.md b/README.md
index 5aa8c327df..c08b2fb0bc 100644
--- a/README.md
+++ b/README.md
@@ -55,17 +55,15 @@ There are also regression and integration tests of the RPC interface, written
in Python, that are run automatically on the build server.
These tests can be run with: `qa/pull-tester/rpc-tests.py`
-Every pull request is built for both Windows and Linux on a dedicated server,
-and unit and sanity tests are automatically run. The binaries produced may be
-used for manual QA testing — a link to them will appear in a comment on the
-pull request posted by [BitcoinPullTester](https://github.com/BitcoinPullTester). See https://github.com/TheBlueMatt/test-scripts
-for the build/test scripts.
+The Travis CI system makes sure that every pull request is built for Windows
+and Linux, OSX, and that unit and sanity tests are automatically run.
### Manual Quality Assurance (QA) Testing
-Large changes should have a test plan, and should be tested by somebody other
-than the developer who wrote the code.
-See https://github.com/bitcoin/QA/ for how to create a test plan.
+Changes should be tested by somebody other than the developer who wrote the
+code. This is especially important for large or high-risk changes. It is useful
+to add a test plan to the pull request description if testing the changes is
+not straightforward.
Translations
------------
diff --git a/configure.ac b/configure.ac
index e8aea902ae..63a745393e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -958,7 +958,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR"
unset PKG_CONFIG_LIBDIR
PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP"
-ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no"
+ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery"
AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue])
AC_OUTPUT
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 57853a9c9d..e1f2ce54d3 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -61,15 +61,15 @@ Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
- sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev
+ sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev bsdmainutils
-On Ubuntu 15.10+ there are generic names for the individual boost development
-packages, so the following can be used to only install necessary parts of
-boost:
+On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the
+individual boost development packages, so the following can be used to only
+install necessary parts of boost:
- apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libboost-base-dev
+ sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev
-For Ubuntu before 15.10, or Debian 7 and later libboost-all-dev has to be installed:
+If that doesn't work, you can install all boost development packages with:
sudo apt-get install libboost-all-dev
diff --git a/doc/files.md b/doc/files.md
index c083bcb038..f7eca57dcb 100644
--- a/doc/files.md
+++ b/doc/files.md
@@ -12,6 +12,8 @@
* fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0
* peers.dat: peer IP address database (custom format); since 0.7.0
* wallet.dat: personal wallet (BDB) with keys and transactions
+* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0
+* onion_private_key: cached Tor hidden service private key for `-listenonion`: since 0.12.0
Only used in pre-0.8.0
---------------------
diff --git a/doc/reducetraffic.md b/doc/reducetraffic.md
new file mode 100644
index 0000000000..a79571913a
--- /dev/null
+++ b/doc/reducetraffic.md
@@ -0,0 +1,35 @@
+Reduce Traffic
+==============
+
+Some node operators need to deal with bandwith caps imposed by their ISPs.
+
+By default, bitcoin-core allows up to 125 connections to different peers, 8 of
+which are outbound. You can therefore, have at most 117 inbound connections.
+
+The default settings can result in relatively significant traffic consumption.
+
+Ways to reduce traffic:
+
+## 1. Use `-maxuploadtarget=<MiB per day>`
+
+A major component of the traffic is caused by serving historic blocks to other nodes
+during the initial blocks download phase (syncing up a new node).
+This option can be specified in MiB per day and is turned off by default.
+This is *not* a hard limit; only a threshold to minimize the outbound
+traffic. When the limit is about to be reached, the uploaded data is cut by no
+longer serving historic blocks (blocks older than one week).
+Keep in mind that new nodes require other nodes that are willing to serve
+historic blocks. **The recommended minimum is 144 blocks per day (max. 144MB
+per day)**
+
+## 2. Disable "listening" (`-listen=0`)
+
+Disabling listening will result in fewer nodes connected (remember the maximum of 8
+outbound peers). Fewer nodes will result in less traffic usage as you are relaying
+blocks and transactions to fewer nodes.
+
+## 3. Reduce maximum connections (`-maxconnections=<num>`)
+
+Reducing the maximum connected nodes to a miniumum could be desirable if traffic
+limits are tiny. Keep in mind that bitcoin's trustless model works best if you are
+connected to a handful of nodes.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index fd034743e6..2e9cc16940 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -143,7 +143,7 @@ higher, it becomes mandatory for all blocks and blocks with versions less than
Bitcoin Core's block templates are now for version 4 blocks only, and any
mining software relying on its `getblocktemplate` must be updated in parallel
-to use either libblkmaker version FIXME or any version from 0.5.1 onward. If
+to use either libblkmaker version 0.4.3 or any version from 0.5.2 onward. If
you are solo mining, this will affect you the moment you upgrade Bitcoin Core,
which must be done prior to BIP65 achieving its 951/1001 status. If you are
mining with the stratum mining protocol: this does not affect you. If you are
@@ -151,6 +151,42 @@ mining with the getblocktemplate protocol to a pool: this will affect you at
the pool operator's discretion, which must be no later than BIP65 achieving its
951/1001 status.
+Automatically listen on Tor
+----------------------------
+
+Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket
+API, to create and destroy 'ephemeral' hidden services programmatically.
+Bitcoin Core has been updated to make use of this.
+
+This means that if Tor is running (and proper authorization is available),
+Bitcoin Core automatically creates a hidden service to listen on, without
+manual configuration. This will positively affect the number of available
+.onion nodes.
+
+This new feature is enabled by default if Bitcoin Core is listening, and
+a connection to Tor can be made. It can be configured with the `-listenonion`,
+`-torcontrol` and `-torpassword` settings. To show verbose debugging
+information, pass `-debug=tor`.
+
+Reduce upload traffic
+---------------------
+
+A major part of the outbound traffic is caused by serving historic blocks to
+other nodes in initial block download state.
+
+It is now possible to reduce the total upload traffic via the `-maxuploadtarget`
+parameter. This is *not* a hard limit but a threshold to minimize the outbound
+traffic. When the limit is about to be reached, the uploaded data is cut by not
+serving historic blocks (blocks older than one week).
+Moreover, any SPV peer is disconnected when they request a filtered block.
+
+This option can be specified in MiB per day and is turned off by default
+(`-maxuploadtarget=0`).
+The recommended minimum is 144 * MAX_BLOCK_SIZE (currently 144MB) per day.
+
+A more detailed documentation about keeping traffic low can be found in
+[/doc/reducetraffic.md](/doc/reducetraffic.md).
+
0.12.0 Change log
=================
diff --git a/doc/tor.md b/doc/tor.md
index 594897f896..1d35a658bc 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -87,3 +87,20 @@ If you only want to use Tor to reach onion addresses, but not use it as a proxy
for normal IPv4/IPv6 communication, use:
./bitcoin -onion=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover
+
+3. Automatically listen on Tor
+--------------------------------
+
+Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket
+API, to create and destroy 'ephemeral' hidden services programmatically.
+Bitcoin Core has been updated to make use of this.
+
+This means that if Tor is running (and proper authorization is available),
+Bitcoin Core automatically creates a hidden service to listen on, without
+manual configuration. This will positively affect the number of available
+.onion nodes.
+
+This new feature is enabled by default if Bitcoin Core is listening, and
+a connection to Tor can be made. It can be configured with the `-listenonion`,
+`-torcontrol` and `-torpassword` settings. To show verbose debugging
+information, pass `-debug=tor`.
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index c23dcbdb7c..83fc9b8f96 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -3,16 +3,32 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Run Regression Test Suite
-#
+"""
+Run Regression Test Suite
+
+This module calls down into individual test cases via subprocess. It will
+forward all unrecognized arguments onto the individual test scripts, other
+than:
+
+ - `-extended`: run the "extended" test suite in addition to the basic one.
+ - `-win`: signal that this is running in a Windows environment, and we
+ should run the tests.
+ - `--coverage`: this generates a basic coverage report for the RPC
+ interface.
+
+For a description of arguments recognized by test scripts, see
+`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
+
+"""
import os
+import shutil
import sys
import subprocess
+import tempfile
import re
+
from tests_config import *
-from sets import Set
#If imported values are not defined then set to zero (or disabled)
if not vars().has_key('ENABLE_WALLET'):
@@ -24,15 +40,20 @@ if not vars().has_key('ENABLE_UTILS'):
if not vars().has_key('ENABLE_ZMQ'):
ENABLE_ZMQ=0
+ENABLE_COVERAGE=0
+
#Create a set to store arguments and create the passOn string
-opts = Set()
+opts = set()
passOn = ""
p = re.compile("^--")
-for i in range(1,len(sys.argv)):
- if (p.match(sys.argv[i]) or sys.argv[i] == "-h"):
- passOn += " " + sys.argv[i]
+
+for arg in sys.argv[1:]:
+ if arg == '--coverage':
+ ENABLE_COVERAGE = 1
+ elif (p.match(arg) or arg == "-h"):
+ passOn += " " + arg
else:
- opts.add(sys.argv[i])
+ opts.add(arg)
#Set env vars
buildDir = BUILDDIR
@@ -98,24 +119,125 @@ testScriptsExt = [
if ENABLE_ZMQ == 1:
testScripts.append('zmq_test.py')
-if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
- rpcTestDir = buildDir + '/qa/rpc-tests/'
- #Run Tests
- for i in range(len(testScripts)):
- if (len(opts) == 0 or (len(opts) == 1 and "-win" in opts ) or '-extended' in opts
- or testScripts[i] in opts or re.sub(".py$", "", testScripts[i]) in opts ):
- print "Running testscript " + testScripts[i] + "..."
- subprocess.check_call(rpcTestDir + testScripts[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True)
- #exit if help is called so we print just one set of instructions
- p = re.compile(" -h| --help")
- if p.match(passOn):
- sys.exit(0)
-
- #Run Extended Tests
- for i in range(len(testScriptsExt)):
- if ('-extended' in opts or testScriptsExt[i] in opts
- or re.sub(".py$", "", testScriptsExt[i]) in opts):
- print "Running 2nd level testscript " + testScriptsExt[i] + "..."
- subprocess.check_call(rpcTestDir + testScriptsExt[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True)
-else:
- print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"
+
+def runtests():
+ coverage = None
+
+ if ENABLE_COVERAGE:
+ coverage = RPCCoverage()
+ print("Initializing coverage directory at %s" % coverage.dir)
+
+ if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
+ rpcTestDir = buildDir + '/qa/rpc-tests/'
+ run_extended = '-extended' in opts
+ cov_flag = coverage.flag if coverage else ''
+ flags = " --srcdir %s/src %s %s" % (buildDir, cov_flag, passOn)
+
+ #Run Tests
+ for i in range(len(testScripts)):
+ if (len(opts) == 0
+ or (len(opts) == 1 and "-win" in opts )
+ or run_extended
+ or testScripts[i] in opts
+ or re.sub(".py$", "", testScripts[i]) in opts ):
+ print("Running testscript " + testScripts[i] + "...")
+
+ subprocess.check_call(
+ rpcTestDir + testScripts[i] + flags, shell=True)
+
+ # exit if help is called so we print just one set of
+ # instructions
+ p = re.compile(" -h| --help")
+ if p.match(passOn):
+ sys.exit(0)
+
+ # Run Extended Tests
+ for i in range(len(testScriptsExt)):
+ if (run_extended or testScriptsExt[i] in opts
+ or re.sub(".py$", "", testScriptsExt[i]) in opts):
+ print(
+ "Running 2nd level testscript "
+ + testScriptsExt[i] + "...")
+
+ subprocess.check_call(
+ rpcTestDir + testScriptsExt[i] + flags, shell=True)
+
+ if coverage:
+ coverage.report_rpc_coverage()
+
+ print("Cleaning up coverage data")
+ coverage.cleanup()
+
+ else:
+ print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"
+
+
+class RPCCoverage(object):
+ """
+ Coverage reporting utilities for pull-tester.
+
+ Coverage calculation works by having each test script subprocess write
+ coverage files into a particular directory. These files contain the RPC
+ commands invoked during testing, as well as a complete listing of RPC
+ commands per `bitcoin-cli help` (`rpc_interface.txt`).
+
+ After all tests complete, the commands run are combined and diff'd against
+ the complete list to calculate uncovered RPC commands.
+
+ See also: qa/rpc-tests/test_framework/coverage.py
+
+ """
+ def __init__(self):
+ self.dir = tempfile.mkdtemp(prefix="coverage")
+ self.flag = '--coveragedir %s' % self.dir
+
+ def report_rpc_coverage(self):
+ """
+ Print out RPC commands that were unexercised by tests.
+
+ """
+ uncovered = self._get_uncovered_rpc_commands()
+
+ if uncovered:
+ print("Uncovered RPC commands:")
+ print("".join((" - %s\n" % i) for i in sorted(uncovered)))
+ else:
+ print("All RPC commands covered.")
+
+ def cleanup(self):
+ return shutil.rmtree(self.dir)
+
+ def _get_uncovered_rpc_commands(self):
+ """
+ Return a set of currently untested RPC commands.
+
+ """
+ # This is shared from `qa/rpc-tests/test-framework/coverage.py`
+ REFERENCE_FILENAME = 'rpc_interface.txt'
+ COVERAGE_FILE_PREFIX = 'coverage.'
+
+ coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME)
+ coverage_filenames = set()
+ all_cmds = set()
+ covered_cmds = set()
+
+ if not os.path.isfile(coverage_ref_filename):
+ raise RuntimeError("No coverage reference found")
+
+ with open(coverage_ref_filename, 'r') as f:
+ all_cmds.update([i.strip() for i in f.readlines()])
+
+ for root, dirs, files in os.walk(self.dir):
+ for filename in files:
+ if filename.startswith(COVERAGE_FILE_PREFIX):
+ coverage_filenames.add(os.path.join(root, filename))
+
+ for filename in coverage_filenames:
+ with open(filename, 'r') as f:
+ covered_cmds.update([i.strip() for i in f.readlines()])
+
+ return all_cmds - covered_cmds
+
+
+if __name__ == '__main__':
+ runtests()
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py
index aab4562422..1ddff8a298 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -38,7 +38,7 @@ class LongpollThread(threading.Thread):
self.longpollid = templat['longpollid']
# create a new connection to the node, we can't use the same
# connection from two threads
- self.node = AuthServiceProxy(node.url, timeout=600)
+ self.node = get_rpc_proxy(node.url, 1, timeout=600)
def run(self):
self.node.getblocktemplate({'longpollid':self.longpollid})
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index 67c4a50985..148c5f37e4 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -192,7 +192,8 @@ class MaxUploadTest(BitcoinTestFramework):
getdata_request.inv.append(CInv(2, big_old_block))
max_bytes_per_day = 200*1024*1024
- max_bytes_available = max_bytes_per_day - 144*1000000
+ daily_buffer = 144 * 1000000
+ max_bytes_available = max_bytes_per_day - daily_buffer
success_count = max_bytes_available / old_block_size
# 144MB will be reserved for relaying new blocks, so expect this to
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 6bc6e43f0b..746c26ff5e 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -11,6 +11,9 @@ from test_framework.util import *
def satoshi_round(amount):
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
+MAX_ANCESTORS = 25
+MAX_DESCENDANTS = 25
+
class MempoolPackagesTest(BitcoinTestFramework):
def setup_network(self):
@@ -45,17 +48,17 @@ class MempoolPackagesTest(BitcoinTestFramework):
value = utxo[0]['amount']
fee = Decimal("0.0001")
- # 100 transactions off a confirmed tx should be fine
+ # MAX_ANCESTORS transactions off a confirmed tx should be fine
chain = []
- for i in xrange(100):
+ for i in xrange(MAX_ANCESTORS):
(txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1)
value = sent_value
chain.append(txid)
- # Check mempool has 100 transactions in it, and descendant
+ # Check mempool has MAX_ANCESTORS transactions in it, and descendant
# count and fees should look correct
mempool = self.nodes[0].getrawmempool(True)
- assert_equal(len(mempool), 100)
+ assert_equal(len(mempool), MAX_ANCESTORS)
descendant_count = 1
descendant_fees = 0
descendant_size = 0
@@ -91,18 +94,18 @@ class MempoolPackagesTest(BitcoinTestFramework):
for i in xrange(10):
transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})
- for i in xrange(1000):
+ for i in xrange(MAX_DESCENDANTS):
utxo = transaction_package.pop(0)
try:
(txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
for j in xrange(10):
transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
- if i == 998:
+ if i == MAX_DESCENDANTS - 2:
mempool = self.nodes[0].getrawmempool(True)
- assert_equal(mempool[parent_transaction]['descendantcount'], 1000)
+ assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)
except JSONRPCException as e:
print e.error['message']
- assert_equal(i, 999)
+ assert_equal(i, MAX_DESCENDANTS - 1)
print "tx that would create too large descendant package successfully rejected"
# TODO: check that node1's mempool is as expected
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index 04110c2831..7a9da66787 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -47,7 +47,7 @@ def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
try:
# connect to node through non-loopback interface
url = "http://rt:rt@%s:%d" % (rpchost, rpcport,)
- node = AuthServiceProxy(url)
+ node = get_rpc_proxy(url, 1)
node.getinfo()
finally:
node = None # make sure connection will be garbage collected and closed
diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py
index 33014dc139..fba469a0dd 100644
--- a/qa/rpc-tests/test_framework/authproxy.py
+++ b/qa/rpc-tests/test_framework/authproxy.py
@@ -69,7 +69,7 @@ class AuthServiceProxy(object):
def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None):
self.__service_url = service_url
- self.__service_name = service_name
+ self._service_name = service_name
self.__url = urlparse.urlparse(service_url)
if self.__url.port is None:
port = 80
@@ -102,8 +102,8 @@ class AuthServiceProxy(object):
if name.startswith('__') and name.endswith('__'):
# Python internal stuff
raise AttributeError
- if self.__service_name is not None:
- name = "%s.%s" % (self.__service_name, name)
+ if self._service_name is not None:
+ name = "%s.%s" % (self._service_name, name)
return AuthServiceProxy(self.__service_url, name, connection=self.__conn)
def _request(self, method, path, postdata):
@@ -129,10 +129,10 @@ class AuthServiceProxy(object):
def __call__(self, *args):
AuthServiceProxy.__id_count += 1
- log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self.__service_name,
+ log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name,
json.dumps(args, default=EncodeDecimal)))
postdata = json.dumps({'version': '1.1',
- 'method': self.__service_name,
+ 'method': self._service_name,
'params': args,
'id': AuthServiceProxy.__id_count}, default=EncodeDecimal)
response = self._request('POST', self.__url.path, postdata)
diff --git a/qa/rpc-tests/test_framework/coverage.py b/qa/rpc-tests/test_framework/coverage.py
new file mode 100644
index 0000000000..50f066a850
--- /dev/null
+++ b/qa/rpc-tests/test_framework/coverage.py
@@ -0,0 +1,101 @@
+"""
+This module contains utilities for doing coverage analysis on the RPC
+interface.
+
+It provides a way to track which RPC commands are exercised during
+testing.
+
+"""
+import os
+
+
+REFERENCE_FILENAME = 'rpc_interface.txt'
+
+
+class AuthServiceProxyWrapper(object):
+ """
+ An object that wraps AuthServiceProxy to record specific RPC calls.
+
+ """
+ def __init__(self, auth_service_proxy_instance, coverage_logfile=None):
+ """
+ Kwargs:
+ auth_service_proxy_instance (AuthServiceProxy): the instance
+ being wrapped.
+ coverage_logfile (str): if specified, write each service_name
+ out to a file when called.
+
+ """
+ self.auth_service_proxy_instance = auth_service_proxy_instance
+ self.coverage_logfile = coverage_logfile
+
+ def __getattr__(self, *args, **kwargs):
+ return_val = self.auth_service_proxy_instance.__getattr__(
+ *args, **kwargs)
+
+ return AuthServiceProxyWrapper(return_val, self.coverage_logfile)
+
+ def __call__(self, *args, **kwargs):
+ """
+ Delegates to AuthServiceProxy, then writes the particular RPC method
+ called to a file.
+
+ """
+ return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
+ rpc_method = self.auth_service_proxy_instance._service_name
+
+ if self.coverage_logfile:
+ with open(self.coverage_logfile, 'a+') as f:
+ f.write("%s\n" % rpc_method)
+
+ return return_val
+
+ @property
+ def url(self):
+ return self.auth_service_proxy_instance.url
+
+
+def get_filename(dirname, n_node):
+ """
+ Get a filename unique to the test process ID and node.
+
+ This file will contain a list of RPC commands covered.
+ """
+ pid = str(os.getpid())
+ return os.path.join(
+ dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node)))
+
+
+def write_all_rpc_commands(dirname, node):
+ """
+ Write out a list of all RPC functions available in `bitcoin-cli` for
+ coverage comparison. This will only happen once per coverage
+ directory.
+
+ Args:
+ dirname (str): temporary test dir
+ node (AuthServiceProxy): client
+
+ Returns:
+ bool. if the RPC interface file was written.
+
+ """
+ filename = os.path.join(dirname, REFERENCE_FILENAME)
+
+ if os.path.isfile(filename):
+ return False
+
+ help_output = node.help().split('\n')
+ commands = set()
+
+ for line in help_output:
+ line = line.strip()
+
+ # Ignore blanks and headers
+ if line and not line.startswith('='):
+ commands.add("%s\n" % line.split()[0])
+
+ with open(filename, 'w') as f:
+ f.writelines(list(commands))
+
+ return True
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index 5671431f6e..ae2d91ab60 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -13,8 +13,20 @@ import shutil
import tempfile
import traceback
+from .util import (
+ initialize_chain,
+ assert_equal,
+ start_nodes,
+ connect_nodes_bi,
+ sync_blocks,
+ sync_mempools,
+ stop_nodes,
+ wait_bitcoinds,
+ enable_coverage,
+ check_json_precision,
+ initialize_chain_clean,
+)
from authproxy import AuthServiceProxy, JSONRPCException
-from util import *
class BitcoinTestFramework(object):
@@ -96,6 +108,8 @@ class BitcoinTestFramework(object):
help="Root directory for datadirs")
parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
help="Print out all RPC calls as they are made")
+ parser.add_option("--coveragedir", dest="coveragedir",
+ help="Write tested RPC commands into this directory")
self.add_options(parser)
(self.options, self.args) = parser.parse_args()
@@ -103,6 +117,9 @@ class BitcoinTestFramework(object):
import logging
logging.basicConfig(level=logging.DEBUG)
+ if self.options.coveragedir:
+ enable_coverage(self.options.coveragedir)
+
os.environ['PATH'] = self.options.srcdir+":"+os.environ['PATH']
check_json_precision()
@@ -173,7 +190,8 @@ class ComparisonTestFramework(BitcoinTestFramework):
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
def setup_network(self):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes,
- binary=[self.options.testbinary] +
- [self.options.refbinary]*(self.num_nodes-1))
+ self.nodes = start_nodes(
+ self.num_nodes, self.options.tmpdir,
+ extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes,
+ binary=[self.options.testbinary] +
+ [self.options.refbinary]*(self.num_nodes-1))
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 3759cc8162..30dd5de585 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -17,8 +17,43 @@ import subprocess
import time
import re
-from authproxy import AuthServiceProxy, JSONRPCException
-from util import *
+from . import coverage
+from .authproxy import AuthServiceProxy, JSONRPCException
+
+COVERAGE_DIR = None
+
+
+def enable_coverage(dirname):
+ """Maintain a log of which RPC calls are made during testing."""
+ global COVERAGE_DIR
+ COVERAGE_DIR = dirname
+
+
+def get_rpc_proxy(url, node_number, timeout=None):
+ """
+ Args:
+ url (str): URL of the RPC server to call
+ node_number (int): the node number (or id) that this calls to
+
+ Kwargs:
+ timeout (int): HTTP timeout in seconds
+
+ Returns:
+ AuthServiceProxy. convenience object for making RPC calls.
+
+ """
+ proxy_kwargs = {}
+ if timeout is not None:
+ proxy_kwargs['timeout'] = timeout
+
+ proxy = AuthServiceProxy(url, **proxy_kwargs)
+ proxy.url = url # store URL on proxy for info
+
+ coverage_logfile = coverage.get_filename(
+ COVERAGE_DIR, node_number) if COVERAGE_DIR else None
+
+ return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile)
+
def p2p_port(n):
return 11000 + n + os.getpid()%999
@@ -79,13 +114,13 @@ def initialize_chain(test_dir):
"""
if (not os.path.isdir(os.path.join("cache","node0"))
- or not os.path.isdir(os.path.join("cache","node1"))
- or not os.path.isdir(os.path.join("cache","node2"))
+ or not os.path.isdir(os.path.join("cache","node1"))
+ or not os.path.isdir(os.path.join("cache","node2"))
or not os.path.isdir(os.path.join("cache","node3"))):
#find and delete old cache directories if any exist
for i in range(4):
- if os.path.isdir(os.path.join("cache","node"+str(i))):
+ if os.path.isdir(os.path.join("cache","node"+str(i))):
shutil.rmtree(os.path.join("cache","node"+str(i)))
devnull = open(os.devnull, "w")
@@ -103,11 +138,13 @@ def initialize_chain(test_dir):
if os.getenv("PYTHON_DEBUG", ""):
print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed"
devnull.close()
+
rpcs = []
+
for i in range(4):
try:
- url = "http://rt:rt@127.0.0.1:%d"%(rpc_port(i),)
- rpcs.append(AuthServiceProxy(url))
+ url = "http://rt:rt@127.0.0.1:%d" % (rpc_port(i),)
+ rpcs.append(get_rpc_proxy(url, i))
except:
sys.stderr.write("Error connecting to "+url+"\n")
sys.exit(1)
@@ -190,11 +227,12 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
print "start_node: calling bitcoin-cli -rpcwait getblockcount returned"
devnull.close()
url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
- if timewait is not None:
- proxy = AuthServiceProxy(url, timeout=timewait)
- else:
- proxy = AuthServiceProxy(url)
- proxy.url = url # store URL on proxy for info
+
+ proxy = get_rpc_proxy(url, i, timeout=timewait)
+
+ if COVERAGE_DIR:
+ coverage.write_all_rpc_commands(COVERAGE_DIR, proxy)
+
return proxy
def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
diff --git a/src/Makefile.am b/src/Makefile.am
index c8d674686c..834c3dc891 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -151,6 +151,7 @@ BITCOIN_CORE_H = \
threadsafety.h \
timedata.h \
tinyformat.h \
+ torcontrol.h \
txdb.h \
txmempool.h \
ui_interface.h \
@@ -209,6 +210,7 @@ libbitcoin_server_a_SOURCES = \
rpcserver.cpp \
script/sigcache.cpp \
timedata.cpp \
+ torcontrol.cpp \
txdb.cpp \
txmempool.cpp \
validationinterface.cpp \
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index dd26c3b31a..5d6d1ef9d8 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -73,6 +73,8 @@ public:
consensus.nMajorityEnforceBlockUpgrade = 750;
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
+ consensus.BIP34Height = 227931;
+ consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -153,6 +155,8 @@ public:
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 100;
+ consensus.BIP34Height = 21111;
+ consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -216,6 +220,8 @@ public:
consensus.nMajorityEnforceBlockUpgrade = 750;
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
+ consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest
+ consensus.BIP34Hash = uint256();
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
diff --git a/src/consensus/params.h b/src/consensus/params.h
index efbbbed352..5ebc48a8df 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -19,6 +19,9 @@ struct Params {
int nMajorityEnforceBlockUpgrade;
int nMajorityRejectBlockOutdated;
int nMajorityWindow;
+ /** Block height and hash at which BIP34 becomes active */
+ int BIP34Height;
+ uint256 BIP34Hash;
/** Proof of work parameters */
uint256 powLimit;
bool fPowAllowMinDifficultyBlocks;
diff --git a/src/init.cpp b/src/init.cpp
index b58c47a940..f2001236a2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -25,9 +25,11 @@
#include "policy/policy.h"
#include "rpcserver.h"
#include "script/standard.h"
+#include "script/sigcache.h"
#include "scheduler.h"
#include "txdb.h"
#include "txmempool.h"
+#include "torcontrol.h"
#include "ui_interface.h"
#include "util.h"
#include "utilmoneystr.h"
@@ -159,6 +161,7 @@ void Interrupt(boost::thread_group& threadGroup)
InterruptHTTPRPC();
InterruptRPC();
InterruptREST();
+ InterruptTorControl();
threadGroup.interrupt_all();
}
@@ -187,6 +190,7 @@ void Shutdown()
#endif
GenerateBitcoins(false, 0, Params());
StopNode();
+ StopTorControl();
UnregisterNodeSignals(GetNodeSignals());
if (fFeeEstimatesInitialized)
@@ -347,6 +351,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address"));
strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0));
strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)"));
+ strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION));
strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), 5000));
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), 1000));
@@ -358,6 +363,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1));
strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect"));
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
+ strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
+ strUsage += HelpMessageOpt("-torpassword=<pass>", _("Tor control port password (default: empty)"));
#ifdef USE_UPNP
#if USE_UPNP
strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)"));
@@ -368,7 +375,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
- strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), 0));
+ strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:"));
@@ -437,7 +444,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15));
strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
- strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
+ strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
}
strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));
@@ -777,6 +784,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
if (SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
+ if (SoftSetBoolArg("-listenonion", false))
+ LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__);
}
if (mapArgs.count("-externalip")) {
@@ -1184,7 +1193,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
if (mapArgs.count("-maxuploadtarget")) {
- CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", 0)*1024*1024);
+ CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024);
}
// ********************************************************* Step 7: load block chain
@@ -1567,6 +1576,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
#endif
+ if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
+ StartTorControl(threadGroup, scheduler);
+
StartNode(threadGroup, scheduler);
// Monitor the chain, and alert if we get blocks much quicker or slower than expected
diff --git a/src/key.cpp b/src/key.cpp
index b772dff333..a24fa8a4ba 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -7,17 +7,120 @@
#include "arith_uint256.h"
#include "crypto/common.h"
#include "crypto/hmac_sha512.h"
-#include "eccryptoverify.h"
#include "pubkey.h"
#include "random.h"
#include <secp256k1.h>
-#include "ecwrapper.h"
+#include <secp256k1_recovery.h>
-static secp256k1_context_t* secp256k1_context = NULL;
+static secp256k1_context* secp256k1_context_sign = NULL;
+
+/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
+static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
+ const unsigned char *end = privkey + privkeylen;
+ int lenb = 0;
+ int len = 0;
+ memset(out32, 0, 32);
+ /* sequence header */
+ if (end < privkey+1 || *privkey != 0x30) {
+ return 0;
+ }
+ privkey++;
+ /* sequence length constructor */
+ if (end < privkey+1 || !(*privkey & 0x80)) {
+ return 0;
+ }
+ lenb = *privkey & ~0x80; privkey++;
+ if (lenb < 1 || lenb > 2) {
+ return 0;
+ }
+ if (end < privkey+lenb) {
+ return 0;
+ }
+ /* sequence length */
+ len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
+ privkey += lenb;
+ if (end < privkey+len) {
+ return 0;
+ }
+ /* sequence element 0: version number (=1) */
+ if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
+ return 0;
+ }
+ privkey += 3;
+ /* sequence element 1: octet string, up to 32 bytes */
+ if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
+ return 0;
+ }
+ memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
+ if (!secp256k1_ec_seckey_verify(ctx, out32)) {
+ memset(out32, 0, 32);
+ return 0;
+ }
+ return 1;
+}
+
+static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
+ secp256k1_pubkey pubkey;
+ size_t pubkeylen = 0;
+ if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
+ *privkeylen = 0;
+ return 0;
+ }
+ if (compressed) {
+ static const unsigned char begin[] = {
+ 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ memcpy(ptr, key32, 32); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ pubkeylen = 33;
+ secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
+ ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ } else {
+ static const unsigned char begin[] = {
+ 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
+ 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
+ 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ memcpy(ptr, key32, 32); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ pubkeylen = 65;
+ secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
+ ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ }
+ return 1;
+}
bool CKey::Check(const unsigned char *vch) {
- return eccrypto::Check(vch);
+ return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
}
void CKey::MakeNewKey(bool fCompressedIn) {
@@ -30,7 +133,7 @@ void CKey::MakeNewKey(bool fCompressedIn) {
}
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
- if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
+ if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
return false;
fCompressed = fCompressedIn;
fValid = true;
@@ -40,10 +143,11 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
- int privkeylen, ret;
+ int ret;
+ size_t privkeylen;
privkey.resize(279);
privkeylen = 279;
- ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
+ ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(ret);
privkey.resize(privkeylen);
return privkey;
@@ -51,11 +155,13 @@ CPrivKey CKey::GetPrivKey() const {
CPubKey CKey::GetPubKey() const {
assert(fValid);
+ secp256k1_pubkey pubkey;
+ size_t clen = 65;
CPubKey result;
- int clen = 65;
- int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed);
- assert((int)result.size() == clen);
+ int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
assert(ret);
+ secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
+ assert(result.size() == clen);
assert(result.IsValid());
return result;
}
@@ -64,11 +170,13 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_
if (!fValid)
return false;
vchSig.resize(72);
- int nSigLen = 72;
+ size_t nSigLen = 72;
unsigned char extra_entropy[32] = {0};
WriteLE32(extra_entropy, test_case);
- int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
+ secp256k1_ecdsa_signature sig;
+ int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
assert(ret);
+ secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig);
vchSig.resize(nSigLen);
return true;
}
@@ -92,7 +200,10 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
return false;
vchSig.resize(65);
int rec = -1;
- int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec);
+ secp256k1_ecdsa_recoverable_signature sig;
+ int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL);
+ assert(ret);
+ secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig);
assert(ret);
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
@@ -100,7 +211,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
- if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
+ if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
return false;
fCompressed = vchPubKey.IsCompressed();
fValid = true;
@@ -126,7 +237,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
}
memcpy(ccChild.begin(), out+32, 32);
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
- bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out);
+ bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out);
UnlockObject(out);
keyChild.fCompressed = true;
keyChild.fValid = ret;
@@ -184,20 +295,16 @@ void CExtKey::Decode(const unsigned char code[74]) {
}
bool ECC_InitSanityCheck() {
- if (!CECKey::SanityCheck()) {
- return false;
- }
CKey key;
key.MakeNewKey(true);
CPubKey pubkey = key.GetPubKey();
return key.VerifyPubKey(pubkey);
}
-
void ECC_Start() {
- assert(secp256k1_context == NULL);
+ assert(secp256k1_context_sign == NULL);
- secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
assert(ctx != NULL);
{
@@ -210,12 +317,12 @@ void ECC_Start() {
UnlockObject(seed);
}
- secp256k1_context = ctx;
+ secp256k1_context_sign = ctx;
}
void ECC_Stop() {
- secp256k1_context_t *ctx = secp256k1_context;
- secp256k1_context = NULL;
+ secp256k1_context *ctx = secp256k1_context_sign;
+ secp256k1_context_sign = NULL;
if (ctx) {
secp256k1_context_destroy(ctx);
diff --git a/src/main.cpp b/src/main.cpp
index 8eb8776558..5208fbb031 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1769,6 +1769,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash.
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
+
+ // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
+ // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the
+ // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first
+ // before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further
+ // duplicate transactions descending from the known pairs either.
+ // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.
+ CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height);
+ //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
+ fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash));
+
if (fEnforceBIP30) {
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
const CCoins* coins = view.AccessCoins(tx.GetHash());
@@ -1840,7 +1851,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
+ bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -4047,9 +4059,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
{
+ LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
pfrom->PushAddress(addr);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
+ LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
pfrom->PushAddress(addr);
}
}
@@ -4317,10 +4331,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> locator >> hashStop;
LOCK(cs_main);
-
- if (IsInitialBlockDownload())
+ if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
+ LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id);
return true;
-
+ }
CBlockIndex* pindex = NULL;
if (locator.IsNull())
{
diff --git a/src/main.h b/src/main.h
index 7a136075ac..5fb5534860 100644
--- a/src/main.h
+++ b/src/main.h
@@ -46,13 +46,13 @@ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
/** Default for -limitancestorcount, max number of in-mempool ancestors */
-static const unsigned int DEFAULT_ANCESTOR_LIMIT = 100;
+static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */
-static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 900;
+static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101;
/** Default for -limitdescendantcount, max number of in-mempool descendants */
-static const unsigned int DEFAULT_DESCENDANT_LIMIT = 1000;
+static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25;
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
-static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 2500;
+static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101;
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
diff --git a/src/net.cpp b/src/net.cpp
index e18e8d0e29..1ea50b2493 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -216,6 +216,7 @@ void AdvertizeLocal(CNode *pnode)
}
if (addrLocal.IsRoutable())
{
+ LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString());
pnode->PushAddress(addrLocal);
}
}
@@ -262,6 +263,14 @@ bool AddLocal(const CNetAddr &addr, int nScore)
return AddLocal(CService(addr, GetListenPort()), nScore);
}
+bool RemoveLocal(const CService& addr)
+{
+ LOCK(cs_mapLocalHost);
+ LogPrintf("RemoveLocal(%s)\n", addr.ToString());
+ mapLocalHost.erase(addr);
+ return true;
+}
+
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited(enum Network net, bool fLimited)
{
@@ -2108,8 +2117,8 @@ void CNode::SetMaxOutboundTarget(uint64_t limit)
uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE;
nMaxOutboundLimit = limit;
- if (limit < recommendedMinimum)
- LogPrintf("Max outbound target is very small (%s) and will be overshot. Recommended minimum is %s\n.", nMaxOutboundLimit, recommendedMinimum);
+ if (limit > 0 && limit < recommendedMinimum)
+ LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum);
}
uint64_t CNode::GetMaxOutboundTarget()
diff --git a/src/net.h b/src/net.h
index f90b3385af..cd2d225d73 100644
--- a/src/net.h
+++ b/src/net.h
@@ -60,6 +60,8 @@ static const bool DEFAULT_UPNP = false;
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
+/** The default for -maxuploadtarget. 0 = Unlimited */
+static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
@@ -128,6 +130,7 @@ bool IsLimited(enum Network net);
bool IsLimited(const CNetAddr& addr);
bool AddLocal(const CService& addr, int nScore = LOCAL_NONE);
bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
+bool RemoveLocal(const CService& addr);
bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index f5316965ce..83cedfb620 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -227,10 +227,7 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
return Lookup(pszName, addr, portDefault, false);
}
-/**
- * Convert milliseconds to a struct timeval for select.
- */
-struct timeval static MillisToTimeval(int64_t nTimeout)
+struct timeval MillisToTimeval(int64_t nTimeout)
{
struct timeval timeout;
timeout.tv_sec = nTimeout / 1000;
diff --git a/src/netbase.h b/src/netbase.h
index 6f8882b852..2a79f82d72 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -215,5 +215,9 @@ std::string NetworkErrorString(int err);
bool CloseSocket(SOCKET& hSocket);
/** Disable or enable blocking-mode for a socket */
bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking);
+/**
+ * Convert milliseconds to a struct timeval for e.g. select.
+ */
+struct timeval MillisToTimeval(int64_t nTimeout);
#endif // BITCOIN_NETBASE_H
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 099b4ad0e3..eee96e7c2d 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -5,17 +5,30 @@
#include "sigcache.h"
+#include "memusage.h"
#include "pubkey.h"
#include "random.h"
#include "uint256.h"
#include "util.h"
#include <boost/thread.hpp>
-#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/unordered_set.hpp>
namespace {
/**
+ * We're hashing a nonce into the entries themselves, so we don't need extra
+ * blinding in the set hash computation.
+ */
+class CSignatureCacheHasher
+{
+public:
+ size_t operator()(const uint256& key) const {
+ return key.GetCheapHash();
+ }
+};
+
+/**
* Valid signature cache, to avoid doing expensive ECDSA signature checking
* twice for every transaction (once when accepted into memory pool, and
* again when accepted into the block chain)
@@ -23,52 +36,54 @@ namespace {
class CSignatureCache
{
private:
- //! sigdata_type is (signature hash, signature, public key):
- typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
- std::set< sigdata_type> setValid;
+ //! Entries are SHA256(nonce || signature hash || public key || signature):
+ uint256 nonce;
+ typedef boost::unordered_set<uint256, CSignatureCacheHasher> map_type;
+ map_type setValid;
boost::shared_mutex cs_sigcache;
+
public:
+ CSignatureCache()
+ {
+ GetRandBytes(nonce.begin(), 32);
+ }
+
+ void
+ ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
+ {
+ CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
+ }
+
bool
- Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
+ Get(const uint256& entry)
{
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
+ return setValid.count(entry);
+ }
- sigdata_type k(hash, vchSig, pubKey);
- std::set<sigdata_type>::iterator mi = setValid.find(k);
- if (mi != setValid.end())
- return true;
- return false;
+ void Erase(const uint256& entry)
+ {
+ boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
+ setValid.erase(entry);
}
- void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
+ void Set(const uint256& entry)
{
- // DoS prevention: limit cache size to less than 10MB
- // (~200 bytes per cache entry times 50,000 entries)
- // Since there are a maximum of 20,000 signature operations per block
- // 50,000 is a reasonable default.
- int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
+ size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
if (nMaxCacheSize <= 0) return;
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
-
- while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
+ while (memusage::DynamicUsage(setValid) > nMaxCacheSize)
{
- // Evict a random entry. Random because that helps
- // foil would-be DoS attackers who might try to pre-generate
- // and re-use a set of valid signatures just-slightly-greater
- // than our cache size.
- uint256 randomHash = GetRandHash();
- std::vector<unsigned char> unused;
- std::set<sigdata_type>::iterator it =
- setValid.lower_bound(sigdata_type(randomHash, unused, unused));
- if (it == setValid.end())
- it = setValid.begin();
- setValid.erase(*it);
+ map_type::size_type s = GetRand(setValid.bucket_count());
+ map_type::local_iterator it = setValid.begin(s);
+ if (it != setValid.end(s)) {
+ setValid.erase(*it);
+ }
}
- sigdata_type k(hash, vchSig, pubKey);
- setValid.insert(k);
+ setValid.insert(entry);
}
};
@@ -78,13 +93,21 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsig
{
static CSignatureCache signatureCache;
- if (signatureCache.Get(sighash, vchSig, pubkey))
+ uint256 entry;
+ signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey);
+
+ if (signatureCache.Get(entry)) {
+ if (!store) {
+ signatureCache.Erase(entry);
+ }
return true;
+ }
if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
return false;
- if (store)
- signatureCache.Set(sighash, vchSig, pubkey);
+ if (store) {
+ signatureCache.Set(entry);
+ }
return true;
}
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index b299038daa..2269972560 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -10,6 +10,10 @@
#include <vector>
+// DoS prevention: limit cache size to less than 40MB (over 500000
+// entries on 64-bit systems).
+static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 40;
+
class CPubKey;
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index 076ff1295f..e0b7b7a48a 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -1,9 +1,12 @@
bench_inv
+bench_ecdh
bench_sign
bench_verify
+bench_schnorr_verify
bench_recover
bench_internal
tests
+gen_context
*.exe
*.so
*.a
@@ -28,6 +31,7 @@ build-aux/
*~
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
+src/ecmult_static_context.h
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index 0d8089cfe4..4e1e73c39f 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -8,20 +8,24 @@ compiler:
- gcc
env:
global:
- - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST=
+ - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no
matrix:
- - SCALAR=32bit
+ - SCALAR=32bit RECOVERY=yes
+ - SCALAR=32bit FIELD=32bit ECDH=yes
- SCALAR=64bit
- - FIELD=64bit
+ - FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
+ - FIELD=64bit ENDOMORPHISM=yes ECDH=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- - FIELD=32bit
+ - FIELD=32bit SCHNORR=yes
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- - BIGNUM=no ENDOMORPHISM=yes
+ - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
+ - BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck
- - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
+ - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
+ - EXTRAFLAGS=CFLAGS=-O0
matrix:
fast_finish: true
include:
@@ -55,5 +59,5 @@ before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
+ - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index cc15338b7e..f4121f1705 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -19,6 +19,8 @@ noinst_HEADERS += src/eckey.h
noinst_HEADERS += src/eckey_impl.h
noinst_HEADERS += src/ecmult.h
noinst_HEADERS += src/ecmult_impl.h
+noinst_HEADERS += src/ecmult_const.h
+noinst_HEADERS += src/ecmult_const_impl.h
noinst_HEADERS += src/ecmult_gen.h
noinst_HEADERS += src/ecmult_gen_impl.h
noinst_HEADERS += src/num.h
@@ -38,40 +40,72 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
+noinst_HEADERS += contrib/lax_der_parsing.h
+noinst_HEADERS += contrib/lax_der_parsing.c
+noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
+noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
libsecp256k1_la_SOURCES = src/secp256k1.c
-libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES)
+libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS)
noinst_PROGRAMS =
if USE_BENCHMARK
-noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal
+noinst_PROGRAMS += bench_verify bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
-bench_verify_LDFLAGS = -static
-bench_recover_SOURCES = src/bench_recover.c
-bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
-bench_recover_LDFLAGS = -static
bench_sign_SOURCES = src/bench_sign.c
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
-bench_sign_LDFLAGS = -static
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS)
-bench_internal_LDFLAGS = -static
bench_internal_CPPFLAGS = $(SECP_INCLUDES)
endif
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
tests_LDFLAGS = -static
TESTS = tests
endif
-EXTRA_DIST = autogen.sh
+if USE_ECMULT_STATIC_PRECOMPUTATION
+CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)/
+CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
+
+gen_context_OBJECTS = gen_context.o
+gen_context_BIN = gen_context$(BUILD_EXEEXT)
+gen_%.o: src/gen_%.c
+ $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
+
+$(gen_context_BIN): $(gen_context_OBJECTS)
+ $(CC_FOR_BUILD) $^ -o $@
+
+$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
+$(tests_OBJECTS): src/ecmult_static_context.h
+$(bench_internal_OBJECTS): src/ecmult_static_context.h
+
+src/ecmult_static_context.h: $(gen_context_BIN)
+ ./$(gen_context_BIN)
+
+CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
+endif
+
+EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
+
+if ENABLE_MODULE_ECDH
+include src/modules/ecdh/Makefile.am.include
+endif
+
+if ENABLE_MODULE_SCHNORR
+include src/modules/schnorr/Makefile.am.include
+endif
+
+if ENABLE_MODULE_RECOVERY
+include src/modules/recovery/Makefile.am.include
+endif
diff --git a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4
new file mode 100644
index 0000000000..77fd346a79
--- /dev/null
+++ b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4
@@ -0,0 +1,125 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PROG_CC_FOR_BUILD
+#
+# DESCRIPTION
+#
+# This macro searches for a C compiler that generates native executables,
+# that is a C compiler that surely is not a cross-compiler. This can be
+# useful if you have to generate source code at compile-time like for
+# example GCC does.
+#
+# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything
+# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD).
+# The value of these variables can be overridden by the user by specifying
+# a compiler with an environment variable (like you do for standard CC).
+#
+# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object
+# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if
+# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are
+# substituted in the Makefile.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Paolo Bonzini <bonzini@gnu.org>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 8
+
+AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD])
+AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_CPP])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+
+dnl Use the standard macros, but make them use other variable names
+dnl
+pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl
+pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl
+pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl
+pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl
+pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl
+pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl
+pushdef([ac_cv_objext], ac_cv_build_objext)dnl
+pushdef([ac_exeext], ac_build_exeext)dnl
+pushdef([ac_objext], ac_build_objext)dnl
+pushdef([CC], CC_FOR_BUILD)dnl
+pushdef([CPP], CPP_FOR_BUILD)dnl
+pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl
+pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl
+pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl
+pushdef([host], build)dnl
+pushdef([host_alias], build_alias)dnl
+pushdef([host_cpu], build_cpu)dnl
+pushdef([host_vendor], build_vendor)dnl
+pushdef([host_os], build_os)dnl
+pushdef([ac_cv_host], ac_cv_build)dnl
+pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl
+pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl
+pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl
+pushdef([ac_cv_host_os], ac_cv_build_os)dnl
+pushdef([ac_cpp], ac_build_cpp)dnl
+pushdef([ac_compile], ac_build_compile)dnl
+pushdef([ac_link], ac_build_link)dnl
+
+save_cross_compiling=$cross_compiling
+save_ac_tool_prefix=$ac_tool_prefix
+cross_compiling=no
+ac_tool_prefix=
+
+AC_PROG_CC
+AC_PROG_CPP
+AC_EXEEXT
+
+ac_tool_prefix=$save_ac_tool_prefix
+cross_compiling=$save_cross_compiling
+
+dnl Restore the old definitions
+dnl
+popdef([ac_link])dnl
+popdef([ac_compile])dnl
+popdef([ac_cpp])dnl
+popdef([ac_cv_host_os])dnl
+popdef([ac_cv_host_vendor])dnl
+popdef([ac_cv_host_cpu])dnl
+popdef([ac_cv_host_alias])dnl
+popdef([ac_cv_host])dnl
+popdef([host_os])dnl
+popdef([host_vendor])dnl
+popdef([host_cpu])dnl
+popdef([host_alias])dnl
+popdef([host])dnl
+popdef([LDFLAGS])dnl
+popdef([CPPFLAGS])dnl
+popdef([CFLAGS])dnl
+popdef([CPP])dnl
+popdef([CC])dnl
+popdef([ac_objext])dnl
+popdef([ac_exeext])dnl
+popdef([ac_cv_objext])dnl
+popdef([ac_cv_exeext])dnl
+popdef([ac_cv_prog_cc_g])dnl
+popdef([ac_cv_prog_cc_cross])dnl
+popdef([ac_cv_prog_cc_works])dnl
+popdef([ac_cv_prog_gcc])dnl
+popdef([ac_cv_prog_CPP])dnl
+
+dnl Finally, set Makefile variables
+dnl
+BUILD_EXEEXT=$ac_build_exeext
+BUILD_OBJEXT=$ac_build_objext
+AC_SUBST(BUILD_EXEEXT)dnl
+AC_SUBST(BUILD_OBJEXT)dnl
+AC_SUBST([CFLAGS_FOR_BUILD])dnl
+AC_SUBST([CPPFLAGS_FOR_BUILD])dnl
+AC_SUBST([LDFLAGS_FOR_BUILD])dnl
+])
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index 4a398d6c93..d41bbb6487 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -16,8 +16,7 @@ AC_MSG_RESULT([$has_64bit_asm])
dnl
AC_DEFUN([SECP_OPENSSL_CHECK],[
-if test x"$use_pkgconfig" = x"yes"; then
- : #NOP
+ has_libcrypto=no
m4_ifdef([PKG_CHECK_MODULES],[
PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no])
if test x"$has_libcrypto" = x"yes"; then
@@ -27,11 +26,16 @@ if test x"$use_pkgconfig" = x"yes"; then
LIBS="$TEMP_LIBS"
fi
])
-else
- AC_CHECK_HEADER(openssl/crypto.h,[AC_CHECK_LIB(crypto, main,[has_libcrypto=yes; CRYPTO_LIBS=-lcrypto; AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])]
-)])
- LIBS=
-fi
+ if test x$has_libcrypto = xno; then
+ AC_CHECK_HEADER(openssl/crypto.h,[
+ AC_CHECK_LIB(crypto, main,[
+ has_libcrypto=yes
+ CRYPTO_LIBS=-lcrypto
+ AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])
+ ])
+ ])
+ LIBS=
+ fi
if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
AC_MSG_CHECKING(for EC functions in libcrypto)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 3dc1829516..786d8dcfb9 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -17,25 +17,19 @@ PKG_PROG_PKG_CONFIG
AC_PATH_TOOL(AR, ar)
AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
+AX_PROG_CC_FOR_BUILD
if test "x$CFLAGS" = "x"; then
CFLAGS="-O3 -g"
fi
+AM_PROG_CC_C_O
+
AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
-case $host in
- *mingw*)
- use_pkgconfig=no
- ;;
- *)
- use_pkgconfig=yes
- ;;
-esac
-
case $host_os in
*darwin*)
if test x$cross_compiling != xyes; then
@@ -80,6 +74,14 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
CFLAGS="$saved_CFLAGS"
])
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -fvisibility=hidden"
+AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
+ [ AC_MSG_RESULT([yes]) ],
+ [ AC_MSG_RESULT([no])
+ CFLAGS="$saved_CFLAGS"
+ ])
AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
@@ -95,6 +97,26 @@ AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
+
+AC_ARG_ENABLE(ecmult_static_precomputation,
+ AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
+ [use_ecmult_static_precomputation=$enableval],
+ [use_ecmult_static_precomputation=yes])
+
+AC_ARG_ENABLE(module_ecdh,
+ AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]),
+ [enable_module_ecdh=$enableval],
+ [enable_module_ecdh=no])
+
+AC_ARG_ENABLE(module_schnorr,
+ AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]),
+ [enable_module_schnorr=$enableval],
+ [enable_module_schnorr=no])
+
+AC_ARG_ENABLE(module_recovery,
+ AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
+ [enable_module_recovery=$enableval],
+ [enable_module_recovery=no])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
@@ -305,6 +327,22 @@ if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
+if test x"$use_ecmult_static_precomputation" = x"yes"; then
+ AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
+fi
+
+if test x"$enable_module_ecdh" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
+fi
+
+if test x"$enable_module_schnorr" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module])
+fi
+
+if test x"$enable_module_recovery" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
+fi
+
AC_C_BIGENDIAN()
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
@@ -312,6 +350,10 @@ AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
+AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
+
+AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
+AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
@@ -321,6 +363,10 @@ AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
+AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c
new file mode 100644
index 0000000000..5b141a9948
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_parsing.c
@@ -0,0 +1,150 @@
+/**********************************************************************
+ * Copyright (c) 2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <string.h>
+#include <secp256k1.h>
+
+#include "lax_der_parsing.h"
+
+int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
+ size_t rpos, rlen, spos, slen;
+ size_t pos = 0;
+ size_t lenbyte;
+ unsigned char tmpsig[64] = {0};
+ int overflow = 0;
+
+ /* Hack to initialize sig with a correctly-parsed but invalid signature. */
+ secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
+
+ /* Sequence tag byte */
+ if (pos == inputlen || input[pos] != 0x30) {
+ return 0;
+ }
+ pos++;
+
+ /* Sequence length bytes */
+ if (pos == inputlen) {
+ return 0;
+ }
+ lenbyte = input[pos++];
+ if (lenbyte & 0x80) {
+ lenbyte -= 0x80;
+ if (pos + lenbyte > inputlen) {
+ return 0;
+ }
+ pos += lenbyte;
+ }
+
+ /* Integer tag byte for R */
+ if (pos == inputlen || input[pos] != 0x02) {
+ return 0;
+ }
+ pos++;
+
+ /* Integer length for R */
+ if (pos == inputlen) {
+ return 0;
+ }
+ lenbyte = input[pos++];
+ if (lenbyte & 0x80) {
+ lenbyte -= 0x80;
+ if (pos + lenbyte > inputlen) {
+ return 0;
+ }
+ while (lenbyte > 0 && input[pos] == 0) {
+ pos++;
+ lenbyte--;
+ }
+ if (lenbyte >= sizeof(size_t)) {
+ return 0;
+ }
+ rlen = 0;
+ while (lenbyte > 0) {
+ rlen = (rlen << 8) + input[pos];
+ pos++;
+ lenbyte--;
+ }
+ } else {
+ rlen = lenbyte;
+ }
+ if (rlen > inputlen - pos) {
+ return 0;
+ }
+ rpos = pos;
+ pos += rlen;
+
+ /* Integer tag byte for S */
+ if (pos == inputlen || input[pos] != 0x02) {
+ return 0;
+ }
+ pos++;
+
+ /* Integer length for S */
+ if (pos == inputlen) {
+ return 0;
+ }
+ lenbyte = input[pos++];
+ if (lenbyte & 0x80) {
+ lenbyte -= 0x80;
+ if (pos + lenbyte > inputlen) {
+ return 0;
+ }
+ while (lenbyte > 0 && input[pos] == 0) {
+ pos++;
+ lenbyte--;
+ }
+ if (lenbyte >= sizeof(size_t)) {
+ return 0;
+ }
+ slen = 0;
+ while (lenbyte > 0) {
+ slen = (slen << 8) + input[pos];
+ pos++;
+ lenbyte--;
+ }
+ } else {
+ slen = lenbyte;
+ }
+ if (slen > inputlen - pos) {
+ return 0;
+ }
+ spos = pos;
+ pos += slen;
+
+ /* Ignore leading zeroes in R */
+ while (rlen > 0 && input[rpos] == 0) {
+ rlen--;
+ rpos++;
+ }
+ /* Copy R value */
+ if (rlen > 32) {
+ overflow = 1;
+ } else {
+ memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
+ }
+
+ /* Ignore leading zeroes in S */
+ while (slen > 0 && input[spos] == 0) {
+ slen--;
+ spos++;
+ }
+ /* Copy S value */
+ if (slen > 32) {
+ overflow = 1;
+ } else {
+ memcpy(tmpsig + 64 - slen, input + spos, slen);
+ }
+
+ if (!overflow) {
+ overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
+ }
+ if (overflow) {
+ memset(tmpsig, 0, 64);
+ secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
+ }
+ return 1;
+}
+
diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h
new file mode 100644
index 0000000000..6d27871a7c
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_parsing.h
@@ -0,0 +1,91 @@
+/**********************************************************************
+ * Copyright (c) 2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/****
+ * Please do not link this file directly. It is not part of the libsecp256k1
+ * project and does not promise any stability in its API, functionality or
+ * presence. Projects which use this code should instead copy this header
+ * and its accompanying .c file directly into their codebase.
+ ****/
+
+/* This file defines a function that parses DER with various errors and
+ * violations. This is not a part of the library itself, because the allowed
+ * violations are chosen arbitrarily and do not follow or establish any
+ * standard.
+ *
+ * In many places it matters that different implementations do not only accept
+ * the same set of valid signatures, but also reject the same set of signatures.
+ * The only means to accomplish that is by strictly obeying a standard, and not
+ * accepting anything else.
+ *
+ * Nonetheless, sometimes there is a need for compatibility with systems that
+ * use signatures which do not strictly obey DER. The snippet below shows how
+ * certain violations are easily supported. You may need to adapt it.
+ *
+ * Do not use this for new systems. Use well-defined DER or compact signatures
+ * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and
+ * secp256k1_ecdsa_signature_parse_compact).
+ *
+ * The supported violations are:
+ * - All numbers are parsed as nonnegative integers, even though X.609-0207
+ * section 8.3.3 specifies that integers are always encoded as two's
+ * complement.
+ * - Integers can have length 0, even though section 8.3.1 says they can't.
+ * - Integers with overly long padding are accepted, violation section
+ * 8.3.2.
+ * - 127-byte long length descriptors are accepted, even though section
+ * 8.1.3.5.c says that they are not.
+ * - Trailing garbage data inside or after the signature is ignored.
+ * - The length descriptor of the sequence is ignored.
+ *
+ * Compared to for example OpenSSL, many violations are NOT supported:
+ * - Using overly long tag descriptors for the sequence or integers inside,
+ * violating section 8.1.2.2.
+ * - Encoding primitive integers as constructed values, violating section
+ * 8.3.1.
+ */
+
+#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
+#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
+
+#include <secp256k1.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Parse a signature in "lax DER" format
+ *
+ * Returns: 1 when the signature could be parsed, 0 otherwise.
+ * Args: ctx: a secp256k1 context object
+ * Out: sig: a pointer to a signature object
+ * In: input: a pointer to the signature to be parsed
+ * inputlen: the length of the array pointed to be input
+ *
+ * This function will accept any valid DER encoded signature, even if the
+ * encoded numbers are out of range. In addition, it will accept signatures
+ * which violate the DER spec in various ways. Its purpose is to allow
+ * validation of the Bitcoin blockchain, which includes non-DER signatures
+ * from before the network rules were updated to enforce DER. Note that
+ * the set of supported violations is a strict subset of what OpenSSL will
+ * accept.
+ *
+ * After the call, sig will always be initialized. If parsing failed or the
+ * encoded numbers are out of range, signature validation with it is
+ * guaranteed to fail for every message and public key.
+ */
+int ecdsa_signature_parse_der_lax(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature* sig,
+ const unsigned char *input,
+ size_t inputlen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/secp256k1/contrib/lax_der_privatekey_parsing.c
new file mode 100644
index 0000000000..c2e63b4b8d
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.c
@@ -0,0 +1,113 @@
+/**********************************************************************
+ * Copyright (c) 2014, 2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <string.h>
+#include <secp256k1.h>
+
+#include "lax_der_privatekey_parsing.h"
+
+int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
+ const unsigned char *end = privkey + privkeylen;
+ int lenb = 0;
+ int len = 0;
+ memset(out32, 0, 32);
+ /* sequence header */
+ if (end < privkey+1 || *privkey != 0x30) {
+ return 0;
+ }
+ privkey++;
+ /* sequence length constructor */
+ if (end < privkey+1 || !(*privkey & 0x80)) {
+ return 0;
+ }
+ lenb = *privkey & ~0x80; privkey++;
+ if (lenb < 1 || lenb > 2) {
+ return 0;
+ }
+ if (end < privkey+lenb) {
+ return 0;
+ }
+ /* sequence length */
+ len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
+ privkey += lenb;
+ if (end < privkey+len) {
+ return 0;
+ }
+ /* sequence element 0: version number (=1) */
+ if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
+ return 0;
+ }
+ privkey += 3;
+ /* sequence element 1: octet string, up to 32 bytes */
+ if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
+ return 0;
+ }
+ memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
+ if (!secp256k1_ec_seckey_verify(ctx, out32)) {
+ memset(out32, 0, 32);
+ return 0;
+ }
+ return 1;
+}
+
+int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
+ secp256k1_pubkey pubkey;
+ size_t pubkeylen = 0;
+ if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
+ *privkeylen = 0;
+ return 0;
+ }
+ if (compressed) {
+ static const unsigned char begin[] = {
+ 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ memcpy(ptr, key32, 32); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ pubkeylen = 33;
+ secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
+ ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ } else {
+ static const unsigned char begin[] = {
+ 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
+ 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
+ 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ memcpy(ptr, key32, 32); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ pubkeylen = 65;
+ secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
+ ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ }
+ return 1;
+}
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
new file mode 100644
index 0000000000..2fd088f8ab
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
@@ -0,0 +1,90 @@
+/**********************************************************************
+ * Copyright (c) 2014, 2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/****
+ * Please do not link this file directly. It is not part of the libsecp256k1
+ * project and does not promise any stability in its API, functionality or
+ * presence. Projects which use this code should instead copy this header
+ * and its accompanying .c file directly into their codebase.
+ ****/
+
+/* This file contains code snippets that parse DER private keys with
+ * various errors and violations. This is not a part of the library
+ * itself, because the allowed violations are chosen arbitrarily and
+ * do not follow or establish any standard.
+ *
+ * It also contains code to serialize private keys in a compatible
+ * manner.
+ *
+ * These functions are meant for compatibility with applications
+ * that require BER encoded keys. When working with secp256k1-specific
+ * code, the simple 32-byte private keys normally used by the
+ * library are sufficient.
+ */
+
+#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
+#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
+
+#include <secp256k1.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Export a private key in DER format.
+ *
+ * Returns: 1 if the private key was valid.
+ * Args: ctx: pointer to a context object, initialized for signing (cannot
+ * be NULL)
+ * Out: privkey: pointer to an array for storing the private key in BER.
+ * Should have space for 279 bytes, and cannot be NULL.
+ * privkeylen: Pointer to an int where the length of the private key in
+ * privkey will be stored.
+ * In: seckey: pointer to a 32-byte secret key to export.
+ * compressed: 1 if the key should be exported in
+ * compressed format, 0 otherwise
+ *
+ * This function is purely meant for compatibility with applications that
+ * require BER encoded keys. When working with secp256k1-specific code, the
+ * simple 32-byte private keys are sufficient.
+ *
+ * Note that this function does not guarantee correct DER output. It is
+ * guaranteed to be parsable by secp256k1_ec_privkey_import_der
+ */
+SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der(
+ const secp256k1_context* ctx,
+ unsigned char *privkey,
+ size_t *privkeylen,
+ const unsigned char *seckey,
+ int compressed
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Import a private key in DER format.
+ * Returns: 1 if a private key was extracted.
+ * Args: ctx: pointer to a context object (cannot be NULL).
+ * Out: seckey: pointer to a 32-byte array for storing the private key.
+ * (cannot be NULL).
+ * In: privkey: pointer to a private key in DER format (cannot be NULL).
+ * privkeylen: length of the DER private key pointed to be privkey.
+ *
+ * This function will accept more than just strict DER, and even allow some BER
+ * violations. The public key stored inside the DER-encoded private key is not
+ * verified for correctness, nor are the curve parameters. Use this function
+ * only if you know in advance it is supposed to contain a secp256k1 private
+ * key.
+ */
+SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
+ const secp256k1_context* ctx,
+ unsigned char *seckey,
+ const unsigned char *privkey,
+ size_t privkeylen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 06afd4c65b..7145dbcc54 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -5,6 +5,99 @@
extern "C" {
# endif
+#include <stddef.h>
+
+/* These rules specify the order of arguments in API calls:
+ *
+ * 1. Context pointers go first, followed by output arguments, combined
+ * output/input arguments, and finally input-only arguments.
+ * 2. Array lengths always immediately the follow the argument whose length
+ * they describe, even if this violates rule 1.
+ * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
+ * later go first. This means: signatures, public nonces, private nonces,
+ * messages, public keys, secret keys, tweaks.
+ * 4. Arguments that are not data pointers go last, from more complex to less
+ * complex: function pointers, algorithm names, messages, void pointers,
+ * counts, flags, booleans.
+ * 5. Opaque data pointers follow the function pointer they are to be passed to.
+ */
+
+/** Opaque data structure that holds context information (precomputed tables etc.).
+ *
+ * The purpose of context structures is to cache large precomputed data tables
+ * that are expensive to construct, and also to maintain the randomization data
+ * for blinding.
+ *
+ * Do not create a new context object for each operation, as construction is
+ * far slower than all other API calls (~100 times slower than an ECDSA
+ * verification).
+ *
+ * A constructed context can safely be used from multiple threads
+ * simultaneously, but API call that take a non-const pointer to a context
+ * need exclusive access to it. In particular this is the case for
+ * secp256k1_context_destroy and secp256k1_context_randomize.
+ *
+ * Regarding randomization, either do it once at creation time (in which case
+ * you do not need any locking for the other calls), or use a read-write lock.
+ */
+typedef struct secp256k1_context_struct secp256k1_context;
+
+/** Opaque data structure that holds a parsed and valid public key.
+ *
+ * The exact representation of data inside is implementation defined and not
+ * guaranteed to be portable between different platforms or versions. It is
+ * however guaranteed to be 64 bytes in size, and can be safely copied/moved.
+ * If you need to convert to a format suitable for storage or transmission, use
+ * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
+ *
+ * Furthermore, it is guaranteed that identical public keys (ignoring
+ * compression) will have identical representation, so they can be memcmp'ed.
+ */
+typedef struct {
+ unsigned char data[64];
+} secp256k1_pubkey;
+
+/** Opaque data structured that holds a parsed ECDSA signature.
+ *
+ * The exact representation of data inside is implementation defined and not
+ * guaranteed to be portable between different platforms or versions. It is
+ * however guaranteed to be 64 bytes in size, and can be safely copied/moved.
+ * If you need to convert to a format suitable for storage or transmission, use
+ * the secp256k1_ecdsa_signature_serialize_* and
+ * secp256k1_ecdsa_signature_serialize_* functions.
+ *
+ * Furthermore, it is guaranteed to identical signatures will have identical
+ * representation, so they can be memcmp'ed.
+ */
+typedef struct {
+ unsigned char data[64];
+} secp256k1_ecdsa_signature;
+
+/** A pointer to a function to deterministically generate a nonce.
+ *
+ * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
+ * Out: nonce32: pointer to a 32-byte array to be filled by the function.
+ * In: msg32: the 32-byte message hash being verified (will not be NULL)
+ * key32: pointer to a 32-byte secret key (will not be NULL)
+ * algo16: pointer to a 16-byte array describing the signature
+ * algorithm (will be NULL for ECDSA for compatibility).
+ * data: Arbitrary data pointer that is passed through.
+ * attempt: how many iterations we have tried to find a nonce.
+ * This will almost always be 0, but different attempt values
+ * are required to result in a different nonce.
+ *
+ * Except for test cases, this function should compute some cryptographic hash of
+ * the message, the algorithm, the key and the attempt.
+ */
+typedef int (*secp256k1_nonce_function)(
+ unsigned char *nonce32,
+ const unsigned char *msg32,
+ const unsigned char *key32,
+ const unsigned char *algo16,
+ void *data,
+ unsigned int attempt
+);
+
# if !defined(SECP256K1_GNUC_PREREQ)
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
# define SECP256K1_GNUC_PREREQ(_maj,_min) \
@@ -26,6 +119,20 @@ extern "C" {
# define SECP256K1_INLINE inline
# endif
+#ifndef SECP256K1_API
+# if defined(_WIN32)
+# ifdef SECP256K1_BUILD
+# define SECP256K1_API __declspec(dllexport)
+# else
+# define SECP256K1_API
+# endif
+# elif defined(__GNUC__) && defined(SECP256K1_BUILD)
+# define SECP256K1_API __attribute__ ((visibility ("default")))
+# else
+# define SECP256K1_API
+# endif
+#endif
+
/**Warning attributes
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
* some paranoid null checks. */
@@ -40,305 +147,434 @@ extern "C" {
# define SECP256K1_ARG_NONNULL(_x)
# endif
-/** Opaque data structure that holds context information (precomputed tables etc.).
- * Only functions that take a pointer to a non-const context require exclusive
- * access to it. Multiple functions that take a pointer to a const context may
- * run simultaneously.
- */
-typedef struct secp256k1_context_struct secp256k1_context_t;
+/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
+#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
+#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
+#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
+/** The higher bits contain the actual data. Do not use directly. */
+#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
+#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
+#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
/** Flags to pass to secp256k1_context_create. */
-# define SECP256K1_CONTEXT_VERIFY (1 << 0)
-# define SECP256K1_CONTEXT_SIGN (1 << 1)
+#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
+#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
+#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
+
+/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
+#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
+#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
/** Create a secp256k1 context object.
+ *
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
*/
-secp256k1_context_t* secp256k1_context_create(
- int flags
+SECP256K1_API secp256k1_context* secp256k1_context_create(
+ unsigned int flags
) SECP256K1_WARN_UNUSED_RESULT;
/** Copies a secp256k1 context object.
+ *
* Returns: a newly created context object.
- * In: ctx: an existing context to copy
+ * Args: ctx: an existing context to copy (cannot be NULL)
*/
-secp256k1_context_t* secp256k1_context_clone(
- const secp256k1_context_t* ctx
-) SECP256K1_WARN_UNUSED_RESULT;
+SECP256K1_API secp256k1_context* secp256k1_context_clone(
+ const secp256k1_context* ctx
+) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object.
+ *
* The context pointer may not be used afterwards.
+ * Args: ctx: an existing context to destroy (cannot be NULL)
+ */
+SECP256K1_API void secp256k1_context_destroy(
+ secp256k1_context* ctx
+);
+
+/** Set a callback function to be called when an illegal argument is passed to
+ * an API call. It will only trigger for violations that are mentioned
+ * explicitly in the header.
+ *
+ * The philosophy is that these shouldn't be dealt with through a
+ * specific return value, as calling code should not have branches to deal with
+ * the case that this code itself is broken.
+ *
+ * On the other hand, during debug stage, one would want to be informed about
+ * such mistakes, and the default (crashing) may be inadvisable.
+ * When this callback is triggered, the API function called is guaranteed not
+ * to cause a crash, though its return value and output arguments are
+ * undefined.
+ *
+ * Args: ctx: an existing context object (cannot be NULL)
+ * In: fun: a pointer to a function to call when an illegal argument is
+ * passed to the API, taking a message and an opaque pointer
+ * (NULL restores a default handler that calls abort).
+ * data: the opaque pointer to pass to fun above.
*/
-void secp256k1_context_destroy(
- secp256k1_context_t* ctx
+SECP256K1_API void secp256k1_context_set_illegal_callback(
+ secp256k1_context* ctx,
+ void (*fun)(const char* message, void* data),
+ const void* data
) SECP256K1_ARG_NONNULL(1);
+/** Set a callback function to be called when an internal consistency check
+ * fails. The default is crashing.
+ *
+ * This can only trigger in case of a hardware failure, miscompilation,
+ * memory corruption, serious bug in the library, or other error would can
+ * otherwise result in undefined behaviour. It will not trigger due to mere
+ * incorrect usage of the API (see secp256k1_context_set_illegal_callback
+ * for that). After this callback returns, anything may happen, including
+ * crashing.
+ *
+ * Args: ctx: an existing context object (cannot be NULL)
+ * In: fun: a pointer to a function to call when an internal error occurs,
+ * taking a message and an opaque pointer (NULL restores a default
+ * handler that calls abort).
+ * data: the opaque pointer to pass to fun above.
+ */
+SECP256K1_API void secp256k1_context_set_error_callback(
+ secp256k1_context* ctx,
+ void (*fun)(const char* message, void* data),
+ const void* data
+) SECP256K1_ARG_NONNULL(1);
+
+/** Parse a variable-length public key into the pubkey object.
+ *
+ * Returns: 1 if the public key was fully valid.
+ * 0 if the public key could not be parsed or is invalid.
+ * Args: ctx: a secp256k1 context object.
+ * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
+ * parsed version of input. If not, its value is undefined.
+ * In: input: pointer to a serialized public key
+ * inputlen: length of the array pointed to by input
+ *
+ * This function supports parsing compressed (33 bytes, header byte 0x02 or
+ * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
+ * byte 0x06 or 0x07) format public keys.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey* pubkey,
+ const unsigned char *input,
+ size_t inputlen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Serialize a pubkey object into a serialized byte sequence.
+ *
+ * Returns: 1 always.
+ * Args: ctx: a secp256k1 context object.
+ * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if
+ * compressed==1) byte array to place the serialized key
+ * in.
+ * In/Out: outputlen: a pointer to an integer which is initially set to the
+ * size of output, and is overwritten with the written
+ * size.
+ * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * initialized public key.
+ * flags: SECP256K1_EC_COMPRESSED if serialization should be in
+ * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
+ */
+SECP256K1_API int secp256k1_ec_pubkey_serialize(
+ const secp256k1_context* ctx,
+ unsigned char *output,
+ size_t *outputlen,
+ const secp256k1_pubkey* pubkey,
+ unsigned int flags
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Parse an ECDSA signature in compact (64 bytes) format.
+ *
+ * Returns: 1 when the signature could be parsed, 0 otherwise.
+ * Args: ctx: a secp256k1 context object
+ * Out: sig: a pointer to a signature object
+ * In: input64: a pointer to the 64-byte array to parse
+ *
+ * The signature must consist of a 32-byte big endian R value, followed by a
+ * 32-byte big endian S value. If R or S fall outside of [0..order-1], the
+ * encoding is invalid. R and S with value 0 are allowed in the encoding.
+ *
+ * After the call, sig will always be initialized. If parsing failed or R or
+ * S are zero, the resulting sig value is guaranteed to fail validation for any
+ * message and public key.
+ */
+SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature* sig,
+ const unsigned char *input64
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Parse a DER ECDSA signature.
+ *
+ * Returns: 1 when the signature could be parsed, 0 otherwise.
+ * Args: ctx: a secp256k1 context object
+ * Out: sig: a pointer to a signature object
+ * In: input: a pointer to the signature to be parsed
+ * inputlen: the length of the array pointed to be input
+ *
+ * This function will accept any valid DER encoded signature, even if the
+ * encoded numbers are out of range.
+ *
+ * After the call, sig will always be initialized. If parsing failed or the
+ * encoded numbers are out of range, signature validation with it is
+ * guaranteed to fail for every message and public key.
+ */
+SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature* sig,
+ const unsigned char *input,
+ size_t inputlen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Serialize an ECDSA signature in DER format.
+ *
+ * Returns: 1 if enough space was available to serialize, 0 otherwise
+ * Args: ctx: a secp256k1 context object
+ * Out: output: a pointer to an array to store the DER serialization
+ * In/Out: outputlen: a pointer to a length integer. Initially, this integer
+ * should be set to the length of output. After the call
+ * it will be set to the length of the serialization (even
+ * if 0 was returned).
+ * In: sig: a pointer to an initialized signature object
+ */
+SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
+ const secp256k1_context* ctx,
+ unsigned char *output,
+ size_t *outputlen,
+ const secp256k1_ecdsa_signature* sig
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Serialize an ECDSA signature in compact (64 byte) format.
+ *
+ * Returns: 1
+ * Args: ctx: a secp256k1 context object
+ * Out: output64: a pointer to a 64-byte array to store the compact serialization
+ * In: sig: a pointer to an initialized signature object
+ *
+ * See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
+ */
+SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
+ const secp256k1_context* ctx,
+ unsigned char *output64,
+ const secp256k1_ecdsa_signature* sig
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
/** Verify an ECDSA signature.
+ *
* Returns: 1: correct signature
- * 0: incorrect signature
- * -1: invalid public key
- * -2: invalid signature
- * In: ctx: a secp256k1 context object, initialized for verification.
+ * 0: incorrect or unparseable signature
+ * Args: ctx: a secp256k1 context object, initialized for verification.
+ * In: sig: the signature being verified (cannot be NULL)
* msg32: the 32-byte message hash being verified (cannot be NULL)
- * sig: the signature being verified (cannot be NULL)
- * siglen: the length of the signature
- * pubkey: the public key to verify with (cannot be NULL)
- * pubkeylen: the length of pubkey
+ * pubkey: pointer to an initialized public key to verify with (cannot be NULL)
+ *
+ * To avoid accepting malleable signatures, only ECDSA signatures in lower-S
+ * form are accepted.
+ *
+ * If you need to accept ECDSA signatures from sources that do not obey this
+ * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
+ * validation, but be aware that doing so results in malleable signatures.
+ *
+ * For details, see the comments for that function.
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
- const secp256k1_context_t* ctx,
- const unsigned char *msg32,
- const unsigned char *sig,
- int siglen,
- const unsigned char *pubkey,
- int pubkeylen
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
+ const secp256k1_context* ctx,
+ const secp256k1_ecdsa_signature *sig,
+ const unsigned char *msg32,
+ const secp256k1_pubkey *pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-/** A pointer to a function to deterministically generate a nonce.
- * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
- * In: msg32: the 32-byte message hash being verified (will not be NULL)
- * key32: pointer to a 32-byte secret key (will not be NULL)
- * attempt: how many iterations we have tried to find a nonce.
- * This will almost always be 0, but different attempt values
- * are required to result in a different nonce.
- * data: Arbitrary data pointer that is passed through.
- * Out: nonce32: pointer to a 32-byte array to be filled by the function.
- * Except for test cases, this function should compute some cryptographic hash of
- * the message, the key and the attempt.
+/** Convert a signature to a normalized lower-S form.
+ *
+ * Returns: 1 if sigin was not normalized, 0 if it already was.
+ * Args: ctx: a secp256k1 context object
+ * Out: sigout: a pointer to a signature to fill with the normalized form,
+ * or copy if the input was already normalized. (can be NULL if
+ * you're only interested in whether the input was already
+ * normalized).
+ * In: sigin: a pointer to a signature to check/normalize (cannot be NULL,
+ * can be identical to sigout)
+ *
+ * With ECDSA a third-party can forge a second distinct signature of the same
+ * message, given a single initial signature, but without knowing the key. This
+ * is done by negating the S value modulo the order of the curve, 'flipping'
+ * the sign of the random point R which is not included in the signature.
+ *
+ * Forgery of the same message isn't universally problematic, but in systems
+ * where message malleability or uniqueness of signatures is important this can
+ * cause issues. This forgery can be blocked by all verifiers forcing signers
+ * to use a normalized form.
+ *
+ * The lower-S form reduces the size of signatures slightly on average when
+ * variable length encodings (such as DER) are used and is cheap to verify,
+ * making it a good choice. Security of always using lower-S is assured because
+ * anyone can trivially modify a signature after the fact to enforce this
+ * property anyway.
+ *
+ * The lower S value is always between 0x1 and
+ * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
+ * inclusive.
+ *
+ * No other forms of ECDSA malleability are known and none seem likely, but
+ * there is no formal proof that ECDSA, even with this additional restriction,
+ * is free of other malleability. Commonly used serialization schemes will also
+ * accept various non-unique encodings, so care should be taken when this
+ * property is required for an application.
+ *
+ * The secp256k1_ecdsa_sign function will by default create signatures in the
+ * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case
+ * signatures come from a system that cannot enforce this property,
+ * secp256k1_ecdsa_signature_normalize must be called before verification.
*/
-typedef int (*secp256k1_nonce_function_t)(
- unsigned char *nonce32,
- const unsigned char *msg32,
- const unsigned char *key32,
- unsigned int attempt,
- const void *data
-);
+SECP256K1_API int secp256k1_ecdsa_signature_normalize(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature *sigout,
+ const secp256k1_ecdsa_signature *sigin
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* extra entropy.
*/
-extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979;
+SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
-extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
-
+SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;
/** Create an ECDSA signature.
+ *
* Returns: 1: signature created
- * 0: the nonce generation function failed, the private key was invalid, or there is not
- * enough space in the signature (as indicated by siglen).
- * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
- * msg32: the 32-byte message hash being signed (cannot be NULL)
- * seckey: pointer to a 32-byte secret key (cannot be NULL)
- * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
- * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
+ * 0: the nonce generation function failed, or the private key was invalid.
+ * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
- * In/Out: siglen: pointer to an int with the length of sig, which will be updated
- * to contain the actual signature length (<=72).
- *
- * The sig always has an s value in the lower half of the range (From 0x1
- * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
- * inclusive), unlike many other implementations.
- * With ECDSA a third-party can can forge a second distinct signature
- * of the same message given a single initial signature without knowing
- * the key by setting s to its additive inverse mod-order, 'flipping' the
- * sign of the random point R which is not included in the signature.
- * Since the forgery is of the same message this isn't universally
- * problematic, but in systems where message malleability or uniqueness
- * of signatures is important this can cause issues. This forgery can be
- * blocked by all verifiers forcing signers to use a canonical form. The
- * lower-S form reduces the size of signatures slightly on average when
- * variable length encodings (such as DER) are used and is cheap to
- * verify, making it a good choice. Security of always using lower-S is
- * assured because anyone can trivially modify a signature after the
- * fact to enforce this property. Adjusting it inside the signing
- * function avoids the need to re-serialize or have curve specific
- * constants outside of the library. By always using a canonical form
- * even in applications where it isn't needed it becomes possible to
- * impose a requirement later if a need is discovered.
- * No other forms of ECDSA malleability are known and none seem likely,
- * but there is no formal proof that ECDSA, even with this additional
- * restriction, is free of other malleability. Commonly used serialization
- * schemes will also accept various non-unique encodings, so care should
- * be taken when this property is required for an application.
- */
-int secp256k1_ecdsa_sign(
- const secp256k1_context_t* ctx,
- const unsigned char *msg32,
- unsigned char *sig,
- int *siglen,
- const unsigned char *seckey,
- secp256k1_nonce_function_t noncefp,
- const void *ndata
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
-
-/** Create a compact ECDSA signature (64 byte + recovery id).
- * Returns: 1: signature created
- * 0: the nonce generation function failed, or the secret key was invalid.
- * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
- * msg32: the 32-byte message hash being signed (cannot be NULL)
+ * In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
- * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL)
- * In case 0 is returned, the returned signature length will be zero.
- * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
+ *
+ * The created signature is always in lower-S form. See
+ * secp256k1_ecdsa_signature_normalize for more details.
*/
-int secp256k1_ecdsa_sign_compact(
- const secp256k1_context_t* ctx,
- const unsigned char *msg32,
- unsigned char *sig64,
- const unsigned char *seckey,
- secp256k1_nonce_function_t noncefp,
- const void *ndata,
- int *recid
+SECP256K1_API int secp256k1_ecdsa_sign(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature *sig,
+ const unsigned char *msg32,
+ const unsigned char *seckey,
+ secp256k1_nonce_function noncefp,
+ const void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-/** Recover an ECDSA public key from a compact signature.
- * Returns: 1: public key successfully recovered (which guarantees a correct signature).
- * 0: otherwise.
- * In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
- * msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
- * sig64: signature as 64 byte array (cannot be NULL)
- * compressed: whether to recover a compressed or uncompressed pubkey
- * recid: the recovery id (0-3, as returned by ecdsa_sign_compact)
- * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL)
- * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL)
- */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact(
- const secp256k1_context_t* ctx,
- const unsigned char *msg32,
- const unsigned char *sig64,
- unsigned char *pubkey,
- int *pubkeylen,
- int compressed,
- int recid
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
-
/** Verify an ECDSA secret key.
+ *
* Returns: 1: secret key is valid
* 0: secret key is invalid
- * In: ctx: pointer to a context object (cannot be NULL)
- * seckey: pointer to a 32-byte secret key (cannot be NULL)
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * In: seckey: pointer to a 32-byte secret key (cannot be NULL)
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
- const secp256k1_context_t* ctx,
- const unsigned char *seckey
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
-
-/** Just validate a public key.
- * Returns: 1: public key is valid
- * 0: public key is invalid
- * In: ctx: pointer to a context object (cannot be NULL)
- * pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL).
- * pubkeylen: length of pubkey
- */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify(
- const secp256k1_context_t* ctx,
- const unsigned char *pubkey,
- int pubkeylen
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
+ const secp256k1_context* ctx,
+ const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Compute the public key for a secret key.
- * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
- * compressed: whether the computed public key should be compressed
- * seckey: pointer to a 32-byte private key (cannot be NULL)
- * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
- * area to store the public key (cannot be NULL)
- * pubkeylen: pointer to int that will be updated to contains the pubkey's
- * length (cannot be NULL)
+ *
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again
+ * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
+ * Out: pubkey: pointer to the created public key (cannot be NULL)
+ * In: seckey: pointer to a 32-byte private key (cannot be NULL)
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
- const secp256k1_context_t* ctx,
- unsigned char *pubkey,
- int *pubkeylen,
- const unsigned char *seckey,
- int compressed
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
-/** Decompress a public key.
- * In: ctx: pointer to a context object (cannot be NULL)
- * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key.
- * It must contain a 33-byte or 65-byte public key already (cannot be NULL)
- * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL)
- * It will be updated to reflect the new size.
- * Returns: 0: pubkey was invalid
- * 1: pubkey was valid, and was replaced with its decompressed version
- */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress(
- const secp256k1_context_t* ctx,
- unsigned char *pubkey,
- int *pubkeylen
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Export a private key in DER format.
- * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
+/** Tweak a private key by adding tweak to it.
+ * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
+ * uniformly random 32-byte arrays, or if the resulting private key
+ * would be invalid (only when the tweak is the complement of the
+ * private key). 1 otherwise.
+ * Args: ctx: pointer to a context object (cannot be NULL).
+ * In/Out: seckey: pointer to a 32-byte private key.
+ * In: tweak: pointer to a 32-byte tweak.
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export(
- const secp256k1_context_t* ctx,
- const unsigned char *seckey,
- unsigned char *privkey,
- int *privkeylen,
- int compressed
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
-/** Import a private key in DER format. */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import(
- const secp256k1_context_t* ctx,
- unsigned char *seckey,
- const unsigned char *privkey,
- int privkeylen
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
+ const secp256k1_context* ctx,
+ unsigned char *seckey,
+ const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Tweak a private key by adding tweak to it. */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
- const secp256k1_context_t* ctx,
- unsigned char *seckey,
- const unsigned char *tweak
+/** Tweak a public key by adding tweak times the generator to it.
+ * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
+ * uniformly random 32-byte arrays, or if the resulting public key
+ * would be invalid (only when the tweak is the complement of the
+ * corresponding private key). 1 otherwise.
+ * Args: ctx: pointer to a context object initialized for validation
+ * (cannot be NULL).
+ * In/Out: pubkey: pointer to a public key object.
+ * In: tweak: pointer to a 32-byte tweak.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Tweak a public key by adding tweak times the generator to it.
- * In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
+/** Tweak a private key by multiplying it by a tweak.
+ * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
+ * uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
+ * Args: ctx: pointer to a context object (cannot be NULL).
+ * In/Out: seckey: pointer to a 32-byte private key.
+ * In: tweak: pointer to a 32-byte tweak.
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
- const secp256k1_context_t* ctx,
- unsigned char *pubkey,
- int pubkeylen,
- const unsigned char *tweak
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
-
-/** Tweak a private key by multiplying it with tweak. */
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
- const secp256k1_context_t* ctx,
- unsigned char *seckey,
- const unsigned char *tweak
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
+ const secp256k1_context* ctx,
+ unsigned char *seckey,
+ const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Tweak a public key by multiplying it with tweak.
- * In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
+/** Tweak a public key by multiplying it by a tweak value.
+ * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
+ * uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
+ * Args: ctx: pointer to a context object initialized for validation
+ * (cannot be NULL).
+ * In/Out: pubkey: pointer to a public key obkect.
+ * In: tweak: pointer to a 32-byte tweak.
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
- const secp256k1_context_t* ctx,
- unsigned char *pubkey,
- int pubkeylen,
- const unsigned char *tweak
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *tweak
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization.
* Returns: 1: randomization successfully updated
* 0: error
- * In: ctx: pointer to a context object (cannot be NULL)
- * seed32: pointer to a 32-byte random seed (NULL resets to initial state)
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
*/
-SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
- secp256k1_context_t* ctx,
- const unsigned char *seed32
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
+ secp256k1_context* ctx,
+ const unsigned char *seed32
) SECP256K1_ARG_NONNULL(1);
+/** Add a number of public keys together.
+ * Returns: 1: the sum of the public keys is valid.
+ * 0: the sum of the public keys is not valid.
+ * Args: ctx: pointer to a context object
+ * Out: out: pointer to a public key object for placing the resulting public key
+ * (cannot be NULL)
+ * In: ins: pointer to array of pointers to public keys (cannot be NULL)
+ * n: the number of public keys to add together (must be at least 1)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *out,
+ const secp256k1_pubkey * const * ins,
+ size_t n
+) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
# ifdef __cplusplus
}
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
new file mode 100644
index 0000000000..4b84d7a963
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -0,0 +1,31 @@
+#ifndef _SECP256K1_ECDH_
+# define _SECP256K1_ECDH_
+
+# include "secp256k1.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Compute an EC Diffie-Hellman secret in constant time
+ * Returns: 1: exponentiation was successful
+ * 0: scalar was invalid (zero or overflow)
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * Out: result: a 32-byte array which will be populated by an ECDH
+ * secret computed from the point and scalar
+ * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * initialized public key
+ * privkey: a 32-byte scalar with which to multiply the point
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
+ const secp256k1_context* ctx,
+ unsigned char *result,
+ const secp256k1_pubkey *pubkey,
+ const unsigned char *privkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
new file mode 100644
index 0000000000..0553797253
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -0,0 +1,110 @@
+#ifndef _SECP256K1_RECOVERY_
+# define _SECP256K1_RECOVERY_
+
+# include "secp256k1.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Opaque data structured that holds a parsed ECDSA signature,
+ * supporting pubkey recovery.
+ *
+ * The exact representation of data inside is implementation defined and not
+ * guaranteed to be portable between different platforms or versions. It is
+ * however guaranteed to be 65 bytes in size, and can be safely copied/moved.
+ * If you need to convert to a format suitable for storage or transmission, use
+ * the secp256k1_ecdsa_signature_serialize_* and
+ * secp256k1_ecdsa_signature_parse_* functions.
+ *
+ * Furthermore, it is guaranteed that identical signatures (including their
+ * recoverability) will have identical representation, so they can be
+ * memcmp'ed.
+ */
+typedef struct {
+ unsigned char data[65];
+} secp256k1_ecdsa_recoverable_signature;
+
+/** Parse a compact ECDSA signature (64 bytes + recovery id).
+ *
+ * Returns: 1 when the signature could be parsed, 0 otherwise
+ * Args: ctx: a secp256k1 context object
+ * Out: sig: a pointer to a signature object
+ * In: input64: a pointer to a 64-byte compact signature
+ * recid: the recovery id (0, 1, 2 or 3)
+ */
+SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_recoverable_signature* sig,
+ const unsigned char *input64,
+ int recid
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Convert a recoverable signature into a normal signature.
+ *
+ * Returns: 1
+ * Out: sig: a pointer to a normal signature (cannot be NULL).
+ * In: sigin: a pointer to a recoverable signature (cannot be NULL).
+ */
+SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature* sig,
+ const secp256k1_ecdsa_recoverable_signature* sigin
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
+ *
+ * Returns: 1
+ * Args: ctx: a secp256k1 context object
+ * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)
+ * recid: a pointer to an integer to hold the recovery id (can be NULL).
+ * In: sig: a pointer to an initialized signature object (cannot be NULL)
+ */
+SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
+ const secp256k1_context* ctx,
+ unsigned char *output64,
+ int *recid,
+ const secp256k1_ecdsa_recoverable_signature* sig
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Create a recoverable ECDSA signature.
+ *
+ * Returns: 1: signature created
+ * 0: the nonce generation function failed, or the private key was invalid.
+ * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
+ * Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
+ * In: msg32: the 32-byte message hash being signed (cannot be NULL)
+ * seckey: pointer to a 32-byte secret key (cannot be NULL)
+ * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
+ * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
+ */
+SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_recoverable_signature *sig,
+ const unsigned char *msg32,
+ const unsigned char *seckey,
+ secp256k1_nonce_function noncefp,
+ const void *ndata
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Recover an ECDSA public key from a signature.
+ *
+ * Returns: 1: public key successfully recovered (which guarantees a correct signature).
+ * 0: otherwise.
+ * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL)
+ * Out: pubkey: pointer to the recovered public key (cannot be NULL)
+ * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
+ * msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const secp256k1_ecdsa_recoverable_signature *sig,
+ const unsigned char *msg32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h
new file mode 100644
index 0000000000..dc32fec1ea
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_schnorr.h
@@ -0,0 +1,173 @@
+#ifndef _SECP256K1_SCHNORR_
+# define _SECP256K1_SCHNORR_
+
+# include "secp256k1.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
+ * produces non-malleable 64-byte signatures which support public key recovery
+ * batch validation, and multiparty signing.
+ * Returns: 1: signature created
+ * 0: the nonce generation function failed, or the private key was
+ * invalid.
+ * Args: ctx: pointer to a context object, initialized for signing
+ * (cannot be NULL)
+ * Out: sig64: pointer to a 64-byte array where the signature will be
+ * placed (cannot be NULL)
+ * In: msg32: the 32-byte message hash being signed (cannot be NULL)
+ * seckey: pointer to a 32-byte secret key (cannot be NULL)
+ * noncefp:pointer to a nonce generation function. If NULL,
+ * secp256k1_nonce_function_default is used
+ * ndata: pointer to arbitrary data used by the nonce generation
+ * function (can be NULL)
+ */
+SECP256K1_API int secp256k1_schnorr_sign(
+ const secp256k1_context* ctx,
+ unsigned char *sig64,
+ const unsigned char *msg32,
+ const unsigned char *seckey,
+ secp256k1_nonce_function noncefp,
+ const void *ndata
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Verify a signature created by secp256k1_schnorr_sign.
+ * Returns: 1: correct signature
+ * 0: incorrect signature
+ * Args: ctx: a secp256k1 context object, initialized for verification.
+ * In: sig64: the 64-byte signature being verified (cannot be NULL)
+ * msg32: the 32-byte message hash being verified (cannot be NULL)
+ * pubkey: the public key to verify with (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
+ const secp256k1_context* ctx,
+ const unsigned char *sig64,
+ const unsigned char *msg32,
+ const secp256k1_pubkey *pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Recover an EC public key from a Schnorr signature created using
+ * secp256k1_schnorr_sign.
+ * Returns: 1: public key successfully recovered (which guarantees a correct
+ * signature).
+ * 0: otherwise.
+ * Args: ctx: pointer to a context object, initialized for
+ * verification (cannot be NULL)
+ * Out: pubkey: pointer to a pubkey to set to the recovered public key
+ * (cannot be NULL).
+ * In: sig64: signature as 64 byte array (cannot be NULL)
+ * msg32: the 32-byte message hash assumed to be signed (cannot
+ * be NULL)
+ */
+SECP256K1_API int secp256k1_schnorr_recover(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *sig64,
+ const unsigned char *msg32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Generate a nonce pair deterministically for use with
+ * secp256k1_schnorr_partial_sign.
+ * Returns: 1: valid nonce pair was generated.
+ * 0: otherwise (nonce generation function failed)
+ * Args: ctx: pointer to a context object, initialized for signing
+ * (cannot be NULL)
+ * Out: pubnonce: public side of the nonce (cannot be NULL)
+ * privnonce32: private side of the nonce (32 byte) (cannot be NULL)
+ * In: msg32: the 32-byte message hash assumed to be signed (cannot
+ * be NULL)
+ * sec32: the 32-byte private key (cannot be NULL)
+ * noncefp: pointer to a nonce generation function. If NULL,
+ * secp256k1_nonce_function_default is used
+ * noncedata: pointer to arbitrary data used by the nonce generation
+ * function (can be NULL)
+ *
+ * Do not use the output as a private/public key pair for signing/validation.
+ */
+SECP256K1_API int secp256k1_schnorr_generate_nonce_pair(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubnonce,
+ unsigned char *privnonce32,
+ const unsigned char *msg32,
+ const unsigned char *sec32,
+ secp256k1_nonce_function noncefp,
+ const void* noncedata
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Produce a partial Schnorr signature, which can be combined using
+ * secp256k1_schnorr_partial_combine, to end up with a full signature that is
+ * verifiable using secp256k1_schnorr_verify.
+ * Returns: 1: signature created successfully.
+ * 0: no valid signature exists with this combination of keys, nonces
+ * and message (chance around 1 in 2^128)
+ * -1: invalid private key, nonce, or public nonces.
+ * Args: ctx: pointer to context object, initialized for signing (cannot
+ * be NULL)
+ * Out: sig64: pointer to 64-byte array to put partial signature in
+ * In: msg32: pointer to 32-byte message to sign
+ * sec32: pointer to 32-byte private key
+ * pubnonce_others: pointer to pubkey containing the sum of the other's
+ * nonces (see secp256k1_ec_pubkey_combine)
+ * secnonce32: pointer to 32-byte array containing our nonce
+ *
+ * The intended procedure for creating a multiparty signature is:
+ * - Each signer S[i] with private key x[i] and public key Q[i] runs
+ * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of
+ * private/public nonces.
+ * - All signers communicate their public nonces to each other (revealing your
+ * private nonce can lead to discovery of your private key, so it should be
+ * considered secret).
+ * - All signers combine all the public nonces they received (excluding their
+ * own) using secp256k1_ec_pubkey_combine to obtain an
+ * Rall[i] = sum(R[0..i-1,i+1..n]).
+ * - All signers produce a partial signature using
+ * secp256k1_schnorr_partial_sign, passing in their own private key x[i],
+ * their own private nonce k[i], and the sum of the others' public nonces
+ * Rall[i].
+ * - All signers communicate their partial signatures to each other.
+ * - Someone combines all partial signatures using
+ * secp256k1_schnorr_partial_combine, to obtain a full signature.
+ * - The resulting signature is validatable using secp256k1_schnorr_verify, with
+ * public key equal to the result of secp256k1_ec_pubkey_combine of the
+ * signers' public keys (sum(Q[0..n])).
+ *
+ * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine
+ * function take their arguments in any order, and it is possible to
+ * pre-combine several inputs already with one call, and add more inputs later
+ * by calling the function again (they are commutative and associative).
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
+ const secp256k1_context* ctx,
+ unsigned char *sig64,
+ const unsigned char *msg32,
+ const unsigned char *sec32,
+ const secp256k1_pubkey *pubnonce_others,
+ const unsigned char *secnonce32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
+
+/** Combine multiple Schnorr partial signatures.
+ * Returns: 1: the passed signatures were successfully combined.
+ * 0: the resulting signature is not valid (chance of 1 in 2^256)
+ * -1: some inputs were invalid, or the signatures were not created
+ * using the same set of nonces
+ * Args: ctx: pointer to a context object
+ * Out: sig64: pointer to a 64-byte array to place the combined signature
+ * (cannot be NULL)
+ * In: sig64sin: pointer to an array of n pointers to 64-byte input
+ * signatures
+ * n: the number of signatures to combine (at least 1)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
+ const secp256k1_context* ctx,
+ unsigned char *sig64,
+ const unsigned char * const * sig64sin,
+ size_t n
+) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h
new file mode 100644
index 0000000000..c4c16eb7ca
--- /dev/null
+++ b/src/secp256k1/src/basic-config.h
@@ -0,0 +1,32 @@
+/**********************************************************************
+ * Copyright (c) 2013, 2014 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_BASIC_CONFIG_
+#define _SECP256K1_BASIC_CONFIG_
+
+#ifdef USE_BASIC_CONFIG
+
+#undef USE_ASM_X86_64
+#undef USE_ENDOMORPHISM
+#undef USE_FIELD_10X26
+#undef USE_FIELD_5X52
+#undef USE_FIELD_INV_BUILTIN
+#undef USE_FIELD_INV_NUM
+#undef USE_NUM_GMP
+#undef USE_NUM_NONE
+#undef USE_SCALAR_4X64
+#undef USE_SCALAR_8X32
+#undef USE_SCALAR_INV_BUILTIN
+#undef USE_SCALAR_INV_NUM
+
+#define USE_NUM_NONE 1
+#define USE_FIELD_INV_BUILTIN 1
+#define USE_SCALAR_INV_BUILTIN 1
+#define USE_FIELD_10X26 1
+#define USE_SCALAR_8X32 1
+
+#endif // USE_BASIC_CONFIG
+#endif // _SECP256K1_BASIC_CONFIG_
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index db5f68cee1..3a71b4aafa 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -20,7 +20,9 @@ static double gettimedouble(void) {
void print_number(double x) {
double y = x;
int c = 0;
- if (y < 0.0) y = -y;
+ if (y < 0.0) {
+ y = -y;
+ }
while (y < 100.0) {
y *= 10.0;
c++;
@@ -35,13 +37,21 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
double max = 0.0;
for (i = 0; i < count; i++) {
double begin, total;
- if (setup) setup(data);
+ if (setup != NULL) {
+ setup(data);
+ }
begin = gettimedouble();
benchmark(data);
total = gettimedouble() - begin;
- if (teardown) teardown(data);
- if (total < min) min = total;
- if (total > max) max = total;
+ if (teardown != NULL) {
+ teardown(data);
+ }
+ if (total < min) {
+ min = total;
+ }
+ if (total > max) {
+ max = total;
+ }
sum += total;
}
printf("%s: min ", name);
diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c
new file mode 100644
index 0000000000..5a7c6376e0
--- /dev/null
+++ b/src/secp256k1/src/bench_ecdh.c
@@ -0,0 +1,53 @@
+/**********************************************************************
+ * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <string.h>
+
+#include "include/secp256k1.h"
+#include "include/secp256k1_ecdh.h"
+#include "util.h"
+#include "bench.h"
+
+typedef struct {
+ secp256k1_context *ctx;
+ secp256k1_pubkey point;
+ unsigned char scalar[32];
+} bench_ecdh_t;
+
+static void bench_ecdh_setup(void* arg) {
+ int i;
+ bench_ecdh_t *data = (bench_ecdh_t*)arg;
+ const unsigned char point[] = {
+ 0x03,
+ 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
+ 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
+ 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
+ 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
+ };
+
+ data->ctx = secp256k1_context_create(0);
+ for (i = 0; i < 32; i++) {
+ data->scalar[i] = i + 1;
+ }
+ CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
+}
+
+static void bench_ecdh(void* arg) {
+ int i;
+ unsigned char res[32];
+ bench_ecdh_t *data = (bench_ecdh_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
+ }
+}
+
+int main(void) {
+ bench_ecdh_t data;
+
+ run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);
+ return 0;
+}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index a960549b94..7809f5f8cf 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -13,15 +13,17 @@
#include "field_impl.h"
#include "group_impl.h"
#include "scalar_impl.h"
+#include "ecmult_const_impl.h"
#include "ecmult_impl.h"
#include "bench.h"
+#include "secp256k1.c"
typedef struct {
- secp256k1_scalar_t scalar_x, scalar_y;
- secp256k1_fe_t fe_x, fe_y;
- secp256k1_ge_t ge_x, ge_y;
- secp256k1_gej_t gej_x, gej_y;
- unsigned char data[32];
+ secp256k1_scalar scalar_x, scalar_y;
+ secp256k1_fe fe_x, fe_y;
+ secp256k1_ge ge_x, ge_y;
+ secp256k1_gej gej_x, gej_y;
+ unsigned char data[64];
int wnaf[256];
} bench_inv_t;
@@ -51,6 +53,7 @@ void bench_setup(void* arg) {
secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);
secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);
memcpy(data->data, init_x, 32);
+ memcpy(data->data + 32, init_y, 32);
}
void bench_scalar_add(void* arg) {
@@ -95,8 +98,8 @@ void bench_scalar_split(void* arg) {
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
- secp256k1_scalar_t l, r;
- secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x);
+ secp256k1_scalar l, r;
+ secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
@@ -193,7 +196,7 @@ void bench_group_double_var(void* arg) {
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 200000; i++) {
- secp256k1_gej_double_var(&data->gej_x, &data->gej_x);
+ secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
}
}
@@ -202,7 +205,7 @@ void bench_group_add_var(void* arg) {
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 200000; i++) {
- secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y);
+ secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
}
}
@@ -220,7 +223,7 @@ void bench_group_add_affine_var(void* arg) {
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 200000; i++) {
- secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y);
+ secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
}
}
@@ -229,7 +232,17 @@ void bench_ecmult_wnaf(void* arg) {
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
- secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A);
+ secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
+ secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+
+void bench_wnaf_const(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
@@ -265,11 +278,27 @@ void bench_rfc6979_hmac_sha256(void* arg) {
secp256k1_rfc6979_hmac_sha256_t rng;
for (i = 0; i < 20000; i++) {
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);
}
}
+void bench_context_verify(void* arg) {
+ int i;
+ (void)arg;
+ for (i = 0; i < 20; i++) {
+ secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
+ }
+}
+
+void bench_context_sign(void* arg) {
+ int i;
+ (void)arg;
+ for (i = 0; i < 200; i++) {
+ secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
+ }
+}
+
int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
@@ -278,7 +307,9 @@ int have_flag(int argc, char** argv, char *flag) {
return 1;
}
while (argv != NULL && argv != argm) {
- if (strcmp(*argv, flag) == 0) return 1;
+ if (strcmp(*argv, flag) == 0) {
+ return 1;
+ }
argv++;
}
return 0;
@@ -309,10 +340,15 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
+
+ if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
+ if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
+
return 0;
}
diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c
index 56faed11a0..6489378cc6 100644
--- a/src/secp256k1/src/bench_recover.c
+++ b/src/secp256k1/src/bench_recover.c
@@ -1,15 +1,16 @@
/**********************************************************************
- * Copyright (c) 2014 Pieter Wuille *
+ * Copyright (c) 2014-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include "include/secp256k1.h"
+#include "include/secp256k1_recovery.h"
#include "util.h"
#include "bench.h"
typedef struct {
- secp256k1_context_t *ctx;
+ secp256k1_context *ctx;
unsigned char msg[32];
unsigned char sig[64];
} bench_recover_t;
@@ -17,16 +18,20 @@ typedef struct {
void bench_recover(void* arg) {
int i;
bench_recover_t *data = (bench_recover_t*)arg;
- unsigned char pubkey[33];
+ secp256k1_pubkey pubkey;
+ unsigned char pubkeyc[33];
for (i = 0; i < 20000; i++) {
int j;
- int pubkeylen = 33;
- CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2));
+ size_t pubkeylen = 33;
+ secp256k1_ecdsa_recoverable_signature sig;
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
+ CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg));
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
for (j = 0; j < 32; j++) {
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */
data->msg[j] = data->sig[j]; /* Move former R to message. */
- data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
+ data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
}
}
}
@@ -35,8 +40,12 @@ void bench_recover_setup(void* arg) {
int i;
bench_recover_t *data = (bench_recover_t*)arg;
- for (i = 0; i < 32; i++) data->msg[i] = 1 + i;
- for (i = 0; i < 64; i++) data->sig[i] = 65 + i;
+ for (i = 0; i < 32; i++) {
+ data->msg[i] = 1 + i;
+ }
+ for (i = 0; i < 64; i++) {
+ data->sig[i] = 65 + i;
+ }
}
int main(void) {
diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c
new file mode 100644
index 0000000000..5f137dda23
--- /dev/null
+++ b/src/secp256k1/src/bench_schnorr_verify.c
@@ -0,0 +1,73 @@
+/**********************************************************************
+ * Copyright (c) 2014 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "include/secp256k1.h"
+#include "include/secp256k1_schnorr.h"
+#include "util.h"
+#include "bench.h"
+
+typedef struct {
+ unsigned char key[32];
+ unsigned char sig[64];
+ unsigned char pubkey[33];
+ size_t pubkeylen;
+} benchmark_schnorr_sig_t;
+
+typedef struct {
+ secp256k1_context *ctx;
+ unsigned char msg[32];
+ benchmark_schnorr_sig_t sigs[64];
+ int numsigs;
+} benchmark_schnorr_verify_t;
+
+static void benchmark_schnorr_init(void* arg) {
+ int i, k;
+ benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
+
+ for (i = 0; i < 32; i++) {
+ data->msg[i] = 1 + i;
+ }
+ for (k = 0; k < data->numsigs; k++) {
+ secp256k1_pubkey pubkey;
+ for (i = 0; i < 32; i++) {
+ data->sigs[k].key[i] = 33 + i + k;
+ }
+ secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
+ data->sigs[k].pubkeylen = 33;
+ CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
+ }
+}
+
+static void benchmark_schnorr_verify(void* arg) {
+ int i;
+ benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
+
+ for (i = 0; i < 20000 / data->numsigs; i++) {
+ secp256k1_pubkey pubkey;
+ data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
+ CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
+ CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
+ data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
+ }
+}
+
+
+
+int main(void) {
+ benchmark_schnorr_verify_t data;
+
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ data.numsigs = 1;
+ run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000);
+
+ secp256k1_context_destroy(data.ctx);
+ return 0;
+}
diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c
index 072a37af51..ed7224d757 100644
--- a/src/secp256k1/src/bench_sign.c
+++ b/src/secp256k1/src/bench_sign.c
@@ -9,7 +9,7 @@
#include "bench.h"
typedef struct {
- secp256k1_context_t* ctx;
+ secp256k1_context* ctx;
unsigned char msg[32];
unsigned char key[32];
} bench_sign_t;
@@ -18,22 +18,28 @@ static void bench_sign_setup(void* arg) {
int i;
bench_sign_t *data = (bench_sign_t*)arg;
- for (i = 0; i < 32; i++) data->msg[i] = i + 1;
- for (i = 0; i < 32; i++) data->key[i] = i + 65;
+ for (i = 0; i < 32; i++) {
+ data->msg[i] = i + 1;
+ }
+ for (i = 0; i < 32; i++) {
+ data->key[i] = i + 65;
+ }
}
static void bench_sign(void* arg) {
int i;
bench_sign_t *data = (bench_sign_t*)arg;
- unsigned char sig[64];
+ unsigned char sig[74];
for (i = 0; i < 20000; i++) {
+ size_t siglen = 74;
int j;
- int recid = 0;
- CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid));
+ secp256k1_ecdsa_signature signature;
+ CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL));
+ CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature));
for (j = 0; j < 32; j++) {
- data->msg[j] = sig[j]; /* Move former R to message. */
- data->key[j] = sig[j + 32]; /* Move former S to key. */
+ data->msg[j] = sig[j];
+ data->key[j] = sig[j + 32];
}
}
}
diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c
index c8c82752ce..5718320cda 100644
--- a/src/secp256k1/src/bench_verify.c
+++ b/src/secp256k1/src/bench_verify.c
@@ -12,13 +12,13 @@
#include "bench.h"
typedef struct {
- secp256k1_context_t *ctx;
+ secp256k1_context *ctx;
unsigned char msg[32];
unsigned char key[32];
unsigned char sig[72];
- int siglen;
+ size_t siglen;
unsigned char pubkey[33];
- int pubkeylen;
+ size_t pubkeylen;
} benchmark_verify_t;
static void benchmark_verify(void* arg) {
@@ -26,10 +26,14 @@ static void benchmark_verify(void* arg) {
benchmark_verify_t* data = (benchmark_verify_t*)arg;
for (i = 0; i < 20000; i++) {
+ secp256k1_pubkey pubkey;
+ secp256k1_ecdsa_signature sig;
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
- CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0));
+ CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);
+ CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0));
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -38,16 +42,24 @@ static void benchmark_verify(void* arg) {
int main(void) {
int i;
+ secp256k1_pubkey pubkey;
+ secp256k1_ecdsa_signature sig;
benchmark_verify_t data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- for (i = 0; i < 32; i++) data.msg[i] = 1 + i;
- for (i = 0; i < 32; i++) data.key[i] = 33 + i;
+ for (i = 0; i < 32; i++) {
+ data.msg[i] = 1 + i;
+ }
+ for (i = 0; i < 32; i++) {
+ data.key[i] = 33 + i;
+ }
data.siglen = 72;
- secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL);
+ CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL));
+ CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));
+ CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
data.pubkeylen = 33;
- CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1));
+ CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h
index 4ef78e8afb..54ae101b92 100644
--- a/src/secp256k1/src/ecdsa.h
+++ b/src/secp256k1/src/ecdsa.h
@@ -7,18 +7,15 @@
#ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_
+#include <stddef.h>
+
#include "scalar.h"
#include "group.h"
#include "ecmult.h"
-typedef struct {
- secp256k1_scalar_t r, s;
-} secp256k1_ecdsa_sig_t;
-
-static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
-static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
-static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
-static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
-static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
+static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size);
+static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s);
+static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
+static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
#endif
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index ed1d228189..d110b4bb1d 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -1,5 +1,5 @@
/**********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
+ * Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
@@ -28,7 +28,7 @@
* sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
* 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
*/
-static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
+static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL
);
@@ -42,82 +42,150 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CON
* sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
* '14551231950b75fc4402da1722fc9baee'
*/
-static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
+static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
);
-static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
- unsigned char ra[32] = {0}, sa[32] = {0};
- const unsigned char *rp;
- const unsigned char *sp;
- int lenr;
- int lens;
- int overflow;
- if (sig[0] != 0x30) {
- return 0;
+static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) {
+ int lenleft, b1;
+ size_t ret = 0;
+ if (*sigp >= sigend) {
+ return -1;
}
- lenr = sig[3];
- if (5+lenr >= size) {
- return 0;
+ b1 = *((*sigp)++);
+ if (b1 == 0xFF) {
+ /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
+ return -1;
}
- lens = sig[lenr+5];
- if (sig[1] != lenr+lens+4) {
- return 0;
+ if ((b1 & 0x80) == 0) {
+ /* X.690-0207 8.1.3.4 short form length octets */
+ return b1;
}
- if (lenr+lens+6 > size) {
- return 0;
+ if (b1 == 0x80) {
+ /* Indefinite length is not allowed in DER. */
+ return -1;
+ }
+ /* X.690-207 8.1.3.5 long form length octets */
+ lenleft = b1 & 0x7F;
+ if (lenleft > sigend - *sigp) {
+ return -1;
+ }
+ if (**sigp == 0) {
+ /* Not the shortest possible length encoding. */
+ return -1;
+ }
+ if ((size_t)lenleft > sizeof(size_t)) {
+ /* The resulting length would exceed the range of a size_t, so
+ * certainly longer than the passed array size.
+ */
+ return -1;
+ }
+ while (lenleft > 0) {
+ if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {
+ }
+ ret = (ret << 8) | **sigp;
+ if (ret + lenleft > (size_t)(sigend - *sigp)) {
+ /* Result exceeds the length of the passed array. */
+ return -1;
+ }
+ (*sigp)++;
+ lenleft--;
+ }
+ if (ret < 128) {
+ /* Not the shortest possible length encoding. */
+ return -1;
}
- if (sig[2] != 0x02) {
+ return ret;
+}
+
+static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {
+ int overflow = 0;
+ unsigned char ra[32] = {0};
+ int rlen;
+
+ if (*sig == sigend || **sig != 0x02) {
+ /* Not a primitive integer (X.690-0207 8.3.1). */
return 0;
}
- if (lenr == 0) {
+ (*sig)++;
+ rlen = secp256k1_der_read_len(sig, sigend);
+ if (rlen <= 0 || (*sig) + rlen > sigend) {
+ /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */
return 0;
}
- if (sig[lenr+4] != 0x02) {
+ if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) {
+ /* Excessive 0x00 padding. */
return 0;
}
- if (lens == 0) {
+ if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) {
+ /* Excessive 0xFF padding. */
return 0;
}
- sp = sig + 6 + lenr;
- while (lens > 0 && sp[0] == 0) {
- lens--;
- sp++;
+ if ((**sig & 0x80) == 0x80) {
+ /* Negative. */
+ overflow = 1;
+ }
+ while (rlen > 0 && **sig == 0) {
+ /* Skip leading zero bytes */
+ rlen--;
+ (*sig)++;
}
- if (lens > 32) {
+ if (rlen > 32) {
+ overflow = 1;
+ }
+ if (!overflow) {
+ memcpy(ra + 32 - rlen, *sig, rlen);
+ secp256k1_scalar_set_b32(r, ra, &overflow);
+ }
+ if (overflow) {
+ secp256k1_scalar_set_int(r, 0);
+ }
+ (*sig) += rlen;
+ return 1;
+}
+
+static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
+ const unsigned char *sigend = sig + size;
+ int rlen;
+ if (sig == sigend || *(sig++) != 0x30) {
+ /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
return 0;
}
- rp = sig + 4;
- while (lenr > 0 && rp[0] == 0) {
- lenr--;
- rp++;
+ rlen = secp256k1_der_read_len(&sig, sigend);
+ if (rlen < 0 || sig + rlen > sigend) {
+ /* Tuple exceeds bounds */
+ return 0;
}
- if (lenr > 32) {
+ if (sig + rlen != sigend) {
+ /* Garbage after tuple. */
return 0;
}
- memcpy(ra + 32 - lenr, rp, lenr);
- memcpy(sa + 32 - lens, sp, lens);
- overflow = 0;
- secp256k1_scalar_set_b32(&r->r, ra, &overflow);
- if (overflow) {
+
+ if (!secp256k1_der_parse_integer(rr, &sig, sigend)) {
return 0;
}
- secp256k1_scalar_set_b32(&r->s, sa, &overflow);
- if (overflow) {
+ if (!secp256k1_der_parse_integer(rs, &sig, sigend)) {
return 0;
}
+
+ if (sig != sigend) {
+ /* Trailing garbage inside tuple. */
+ return 0;
+ }
+
return 1;
}
-static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
+static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) {
unsigned char r[33] = {0}, s[33] = {0};
unsigned char *rp = r, *sp = s;
- int lenR = 33, lenS = 33;
- secp256k1_scalar_get_b32(&r[1], &a->r);
- secp256k1_scalar_get_b32(&s[1], &a->s);
+ size_t lenR = 33, lenS = 33;
+ secp256k1_scalar_get_b32(&r[1], ar);
+ secp256k1_scalar_get_b32(&s[1], as);
while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }
while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }
if (*size < 6+lenS+lenR) {
+ *size = 6 + lenS + lenR;
return 0;
}
*size = 6 + lenS + lenR;
@@ -132,26 +200,26 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
return 1;
}
-static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
+static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
unsigned char c[32];
- secp256k1_scalar_t sn, u1, u2;
- secp256k1_fe_t xr;
- secp256k1_gej_t pubkeyj;
- secp256k1_gej_t pr;
+ secp256k1_scalar sn, u1, u2;
+ secp256k1_fe xr;
+ secp256k1_gej pubkeyj;
+ secp256k1_gej pr;
- if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) {
+ if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
return 0;
}
- secp256k1_scalar_inverse_var(&sn, &sig->s);
+ secp256k1_scalar_inverse_var(&sn, sigs);
secp256k1_scalar_mul(&u1, &sn, message);
- secp256k1_scalar_mul(&u2, &sn, &sig->r);
+ secp256k1_scalar_mul(&u2, &sn, sigr);
secp256k1_gej_set_ge(&pubkeyj, pubkey);
secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1);
if (secp256k1_gej_is_infinity(&pr)) {
return 0;
}
- secp256k1_scalar_get_b32(c, &sig->r);
+ secp256k1_scalar_get_b32(c, sigr);
secp256k1_fe_set_b32(&xr, c);
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
@@ -171,11 +239,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con
* secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
*/
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
- /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */
+ /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */
return 1;
}
if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
- /* xr + p >= n, so we can skip testing the second case. */
+ /* xr + n >= p, so we can skip testing the second case. */
return 0;
}
secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
@@ -186,44 +254,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con
return 0;
}
-static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
- unsigned char brx[32];
- secp256k1_fe_t fx;
- secp256k1_ge_t x;
- secp256k1_gej_t xj;
- secp256k1_scalar_t rn, u1, u2;
- secp256k1_gej_t qj;
-
- if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) {
- return 0;
- }
-
- secp256k1_scalar_get_b32(brx, &sig->r);
- VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
- if (recid & 2) {
- if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
- return 0;
- }
- secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
- }
- if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
- return 0;
- }
- secp256k1_gej_set_ge(&xj, &x);
- secp256k1_scalar_inverse_var(&rn, &sig->r);
- secp256k1_scalar_mul(&u1, &rn, message);
- secp256k1_scalar_negate(&u1, &u1);
- secp256k1_scalar_mul(&u2, &rn, &sig->s);
- secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
- secp256k1_ge_set_gej_var(pubkey, &qj);
- return !secp256k1_gej_is_infinity(&qj);
-}
-
-static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) {
+static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
unsigned char b[32];
- secp256k1_gej_t rp;
- secp256k1_ge_t r;
- secp256k1_scalar_t n;
+ secp256k1_gej rp;
+ secp256k1_ge r;
+ secp256k1_scalar n;
int overflow = 0;
secp256k1_ecmult_gen(ctx, &rp, nonce);
@@ -231,28 +266,33 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s
secp256k1_fe_normalize(&r.x);
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
- secp256k1_scalar_set_b32(&sig->r, b, &overflow);
- if (secp256k1_scalar_is_zero(&sig->r)) {
- /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */
+ secp256k1_scalar_set_b32(sigr, b, &overflow);
+ if (secp256k1_scalar_is_zero(sigr)) {
+ /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature.
+ * This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
+ */
secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r);
return 0;
}
if (recid) {
+ /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
+ * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
+ */
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
}
- secp256k1_scalar_mul(&n, &sig->r, seckey);
+ secp256k1_scalar_mul(&n, sigr, seckey);
secp256k1_scalar_add(&n, &n, message);
- secp256k1_scalar_inverse(&sig->s, nonce);
- secp256k1_scalar_mul(&sig->s, &sig->s, &n);
+ secp256k1_scalar_inverse(sigs, nonce);
+ secp256k1_scalar_mul(sigs, sigs, &n);
secp256k1_scalar_clear(&n);
secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r);
- if (secp256k1_scalar_is_zero(&sig->s)) {
+ if (secp256k1_scalar_is_zero(sigs)) {
return 0;
}
- if (secp256k1_scalar_is_high(&sig->s)) {
- secp256k1_scalar_negate(&sig->s, &sig->s);
+ if (secp256k1_scalar_is_high(sigs)) {
+ secp256k1_scalar_negate(sigs, sigs);
if (recid) {
*recid ^= 1;
}
diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h
index 53b818485e..42739a3bea 100644
--- a/src/secp256k1/src/eckey.h
+++ b/src/secp256k1/src/eckey.h
@@ -7,20 +7,19 @@
#ifndef _SECP256K1_ECKEY_
#define _SECP256K1_ECKEY_
+#include <stddef.h>
+
#include "group.h"
#include "scalar.h"
#include "ecmult.h"
#include "ecmult_gen.h"
-static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
-static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
-
-static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen);
-static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed);
+static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
+static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);
-static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
-static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
-static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
-static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
+static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
+static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
+static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
+static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
#endif
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index a332bd34ec..ce38071ac2 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -14,12 +14,12 @@
#include "group.h"
#include "ecmult_gen.h"
-static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
+static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
- secp256k1_fe_t x;
+ secp256k1_fe x;
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
- secp256k1_fe_t x, y;
+ secp256k1_fe x, y;
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
return 0;
}
@@ -33,7 +33,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned cha
}
}
-static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) {
+static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
if (secp256k1_ge_is_infinity(elem)) {
return 0;
}
@@ -51,110 +51,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char
return 1;
}
-static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) {
- unsigned char c[32] = {0};
- const unsigned char *end = privkey + privkeylen;
- int lenb = 0;
- int len = 0;
- int overflow = 0;
- /* sequence header */
- if (end < privkey+1 || *privkey != 0x30) {
- return 0;
- }
- privkey++;
- /* sequence length constructor */
- if (end < privkey+1 || !(*privkey & 0x80)) {
- return 0;
- }
- lenb = *privkey & ~0x80; privkey++;
- if (lenb < 1 || lenb > 2) {
- return 0;
- }
- if (end < privkey+lenb) {
- return 0;
- }
- /* sequence length */
- len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
- privkey += lenb;
- if (end < privkey+len) {
- return 0;
- }
- /* sequence element 0: version number (=1) */
- if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
- return 0;
- }
- privkey += 3;
- /* sequence element 1: octet string, up to 32 bytes */
- if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
- return 0;
- }
- memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]);
- secp256k1_scalar_set_b32(key, c, &overflow);
- memset(c, 0, 32);
- return !overflow;
-}
-
-static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) {
- secp256k1_gej_t rp;
- secp256k1_ge_t r;
- int pubkeylen = 0;
- secp256k1_ecmult_gen(ctx, &rp, key);
- secp256k1_ge_set_gej(&r, &rp);
- if (compressed) {
- static const unsigned char begin[] = {
- 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
- };
- static const unsigned char middle[] = {
- 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
- 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
- 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
- 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
- 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
- 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
- };
- unsigned char *ptr = privkey;
- memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
- secp256k1_scalar_get_b32(ptr, key); ptr += 32;
- memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
- if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) {
- return 0;
- }
- ptr += pubkeylen;
- *privkeylen = ptr - privkey;
- } else {
- static const unsigned char begin[] = {
- 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
- };
- static const unsigned char middle[] = {
- 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
- 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
- 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
- 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
- 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
- 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
- 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
- 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
- };
- unsigned char *ptr = privkey;
- memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
- secp256k1_scalar_get_b32(ptr, key); ptr += 32;
- memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
- if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) {
- return 0;
- }
- ptr += pubkeylen;
- *privkeylen = ptr - privkey;
- }
- return 1;
-}
-
-static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) {
+static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
secp256k1_scalar_add(key, key, tweak);
if (secp256k1_scalar_is_zero(key)) {
return 0;
@@ -162,9 +59,9 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp
return 1;
}
-static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
- secp256k1_gej_t pt;
- secp256k1_scalar_t one;
+static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
+ secp256k1_gej pt;
+ secp256k1_scalar one;
secp256k1_gej_set_ge(&pt, key);
secp256k1_scalar_set_int(&one, 1);
secp256k1_ecmult(ctx, &pt, &pt, &one, tweak);
@@ -176,7 +73,7 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ct
return 1;
}
-static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) {
+static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
if (secp256k1_scalar_is_zero(tweak)) {
return 0;
}
@@ -185,9 +82,9 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp
return 1;
}
-static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
- secp256k1_scalar_t zero;
- secp256k1_gej_t pt;
+static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
+ secp256k1_scalar zero;
+ secp256k1_gej pt;
if (secp256k1_scalar_is_zero(tweak)) {
return 0;
}
diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h
index bab9e4ef52..20484134f5 100644
--- a/src/secp256k1/src/ecmult.h
+++ b/src/secp256k1/src/ecmult.h
@@ -12,20 +12,20 @@
typedef struct {
/* For accelerating the computation of a*P + b*G: */
- secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */
+ secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */
#ifdef USE_ENDOMORPHISM
- secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */
+ secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
#endif
-} secp256k1_ecmult_context_t;
+} secp256k1_ecmult_context;
-static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx);
-static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx);
-static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst,
- const secp256k1_ecmult_context_t *src);
-static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx);
-static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx);
+static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
+static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
+static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
+ const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
+static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
+static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
/** Double multiply: R = na*A + ng*G */
-static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng);
+static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
#endif
diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h
new file mode 100644
index 0000000000..2b0097655c
--- /dev/null
+++ b/src/secp256k1/src/ecmult_const.h
@@ -0,0 +1,15 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_ECMULT_CONST_
+#define _SECP256K1_ECMULT_CONST_
+
+#include "scalar.h"
+#include "group.h"
+
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
+
+#endif
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
new file mode 100644
index 0000000000..90ac94770e
--- /dev/null
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -0,0 +1,260 @@
+/**********************************************************************
+ * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_ECMULT_CONST_IMPL_
+#define _SECP256K1_ECMULT_CONST_IMPL_
+
+#include "scalar.h"
+#include "group.h"
+#include "ecmult_const.h"
+#include "ecmult_impl.h"
+
+#ifdef USE_ENDOMORPHISM
+ #define WNAF_BITS 128
+#else
+ #define WNAF_BITS 256
+#endif
+#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w))
+
+/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
+#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
+ int m; \
+ int abs_n = (n) * (((n) > 0) * 2 - 1); \
+ int idx_n = abs_n / 2; \
+ secp256k1_fe neg_y; \
+ VERIFY_CHECK(((n) & 1) == 1); \
+ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
+ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
+ VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
+ VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
+ for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
+ /* This loop is used to avoid secret data in array indices. See
+ * the comment in ecmult_gen_impl.h for rationale. */ \
+ secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
+ secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \
+ } \
+ (r)->infinity = 0; \
+ secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
+ secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \
+} while(0)
+
+
+/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)
+ * with the following guarantees:
+ * - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
+ * - each wnaf[i] is nonzero
+ * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w
+ *
+ * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
+ * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
+ * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003
+ *
+ * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
+ */
+static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
+ int global_sign;
+ int skew = 0;
+ int word = 0;
+ /* 1 2 3 */
+ int u_last;
+ int u;
+
+#ifdef USE_ENDOMORPHISM
+ int flip;
+ int bit;
+ secp256k1_scalar neg_s;
+ int not_neg_one;
+ /* If we are using the endomorphism, we cannot handle even numbers by negating
+ * them, since we are working with 128-bit numbers whose negations would be 256
+ * bits, eliminating the performance advantage. Instead we use a technique from
+ * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
+ * or 2 (for odd) to the number we are encoding, then compensating after the
+ * multiplication. */
+ /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */
+ flip = secp256k1_scalar_is_high(&s);
+ /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
+ bit = flip ^ (s.d[0] & 1);
+ /* We check for negative one, since adding 2 to it will cause an overflow */
+ secp256k1_scalar_negate(&neg_s, &s);
+ not_neg_one = !secp256k1_scalar_is_one(&neg_s);
+ secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
+ /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
+ * that we added two to it and flipped it. In fact for -1 these operations are
+ * identical. We only flipped, but since skewing is required (in the sense that
+ * the skew must be 1 or 2, never zero) and flipping is not, we need to change
+ * our flags to claim that we only skewed. */
+ global_sign = secp256k1_scalar_cond_negate(&s, flip);
+ global_sign *= not_neg_one * 2 - 1;
+ skew = 1 << bit;
+#else
+ /* Otherwise, we just negate to force oddness */
+ int is_even = secp256k1_scalar_is_even(&s);
+ global_sign = secp256k1_scalar_cond_negate(&s, is_even);
+#endif
+
+ /* 4 */
+ u_last = secp256k1_scalar_shr_int(&s, w);
+ while (word * w < WNAF_BITS) {
+ int sign;
+ int even;
+
+ /* 4.1 4.4 */
+ u = secp256k1_scalar_shr_int(&s, w);
+ /* 4.2 */
+ even = ((u & 1) == 0);
+ sign = 2 * (u_last > 0) - 1;
+ u += sign * even;
+ u_last -= sign * even * (1 << w);
+
+ /* 4.3, adapted for global sign change */
+ wnaf[word++] = u_last * global_sign;
+
+ u_last = u;
+ }
+ wnaf[word] = u * global_sign;
+
+ VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
+ VERIFY_CHECK(word == WNAF_SIZE(w));
+ return skew;
+}
+
+
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
+ secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_ge tmpa;
+ secp256k1_fe Z;
+
+#ifdef USE_ENDOMORPHISM
+ secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
+ int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
+ int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
+ int skew_1;
+ int skew_lam;
+ secp256k1_scalar q_1, q_lam;
+#else
+ int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)];
+#endif
+
+ int i;
+ secp256k1_scalar sc = *scalar;
+
+ /* build wnaf representation for q. */
+#ifdef USE_ENDOMORPHISM
+ /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
+ secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
+ /* no need for zero correction when using endomorphism since even
+ * numbers have one added to them anyway */
+ skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
+ skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
+#else
+ int is_zero = secp256k1_scalar_is_zero(scalar);
+ /* the wNAF ladder cannot handle zero, so bump this to one .. we will
+ * correct the result after the fact */
+ sc.d[0] += is_zero;
+ VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc));
+
+ secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1);
+#endif
+
+ /* Calculate odd multiples of a.
+ * All multiples are brought to the same Z 'denominator', which is stored
+ * in Z. Due to secp256k1' isomorphism we can do all operations pretending
+ * that the Z coordinate was 1, use affine addition formulae, and correct
+ * the Z coordinate of the result once at the end.
+ */
+ secp256k1_gej_set_ge(r, a);
+ secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_fe_normalize_weak(&pre_a[i].y);
+ }
+#ifdef USE_ENDOMORPHISM
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
+ }
+#endif
+
+ /* first loop iteration (separated out so we can directly set r, rather
+ * than having it start at infinity, get doubled several times, then have
+ * its new value added to it) */
+#ifdef USE_ENDOMORPHISM
+ i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
+ VERIFY_CHECK(i != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
+ secp256k1_gej_set_ge(r, &tmpa);
+
+ i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
+ VERIFY_CHECK(i != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+#else
+ i = wnaf[WNAF_SIZE(WINDOW_A - 1)];
+ VERIFY_CHECK(i != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
+ secp256k1_gej_set_ge(r, &tmpa);
+#endif
+ /* remaining loop iterations */
+ for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
+ int n;
+ int j;
+ for (j = 0; j < WINDOW_A - 1; ++j) {
+ secp256k1_gej_double_nonzero(r, r, NULL);
+ }
+#ifdef USE_ENDOMORPHISM
+ n = wnaf_1[i];
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
+ VERIFY_CHECK(n != 0);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+
+ n = wnaf_lam[i];
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
+ VERIFY_CHECK(n != 0);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+#else
+ n = wnaf[i];
+ VERIFY_CHECK(n != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+#endif
+ }
+
+ secp256k1_fe_mul(&r->z, &r->z, &Z);
+
+#ifdef USE_ENDOMORPHISM
+ {
+ /* Correct for wNAF skew */
+ secp256k1_ge correction = *a;
+ secp256k1_ge_storage correction_1_stor;
+ secp256k1_ge_storage correction_lam_stor;
+ secp256k1_ge_storage a2_stor;
+ secp256k1_gej tmpj;
+ secp256k1_gej_set_ge(&tmpj, &correction);
+ secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
+ secp256k1_ge_set_gej(&correction, &tmpj);
+ secp256k1_ge_to_storage(&correction_1_stor, a);
+ secp256k1_ge_to_storage(&correction_lam_stor, a);
+ secp256k1_ge_to_storage(&a2_stor, &correction);
+
+ /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
+ secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
+ secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
+
+ /* Apply the correction */
+ secp256k1_ge_from_storage(&correction, &correction_1_stor);
+ secp256k1_ge_neg(&correction, &correction);
+ secp256k1_gej_add_ge(r, r, &correction);
+
+ secp256k1_ge_from_storage(&correction, &correction_lam_stor);
+ secp256k1_ge_neg(&correction, &correction);
+ secp256k1_ge_mul_lambda(&correction, &correction);
+ secp256k1_gej_add_ge(r, r, &correction);
+ }
+#else
+ /* correct for zero */
+ r->infinity |= is_zero;
+#endif
+}
+
+#endif
diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h
index 3745633c47..eb2cc9ead6 100644
--- a/src/secp256k1/src/ecmult_gen.h
+++ b/src/secp256k1/src/ecmult_gen.h
@@ -23,21 +23,21 @@ typedef struct {
* None of the resulting prec group elements have a known scalar, and neither do any of
* the intermediate sums while computing a*G.
*/
- secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
- secp256k1_scalar_t blind;
- secp256k1_gej_t initial;
-} secp256k1_ecmult_gen_context_t;
+ secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
+ secp256k1_scalar blind;
+ secp256k1_gej initial;
+} secp256k1_ecmult_gen_context;
-static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx);
-static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx);
-static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst,
- const secp256k1_ecmult_gen_context_t* src);
-static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx);
-static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx);
+static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
+static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);
+static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
+ const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);
+static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
+static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
/** Multiply with the generator: R = a*G */
-static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a);
+static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);
-static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32);
+static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
#endif
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 4697753ac8..b63c4d8662 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -11,22 +11,26 @@
#include "group.h"
#include "ecmult_gen.h"
#include "hash_impl.h"
-
-static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) {
+#ifdef USE_ECMULT_STATIC_PRECOMPUTATION
+#include "ecmult_static_context.h"
+#endif
+static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {
ctx->prec = NULL;
}
-static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) {
- secp256k1_ge_t prec[1024];
- secp256k1_gej_t gj;
- secp256k1_gej_t nums_gej;
+static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {
+#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
+ secp256k1_ge prec[1024];
+ secp256k1_gej gj;
+ secp256k1_gej nums_gej;
int i, j;
+#endif
if (ctx->prec != NULL) {
return;
}
-
- ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec));
+#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
+ ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));
/* get the generator */
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
@@ -34,77 +38,93 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
{
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
- secp256k1_fe_t nums_x;
- secp256k1_ge_t nums_ge;
- VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
- VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0));
+ secp256k1_fe nums_x;
+ secp256k1_ge nums_ge;
+ int r;
+ r = secp256k1_fe_set_b32(&nums_x, nums_b32);
+ (void)r;
+ VERIFY_CHECK(r);
+ r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
+ (void)r;
+ VERIFY_CHECK(r);
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
/* Add G to make the bits in x uniformly distributed. */
- secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g);
+ secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL);
}
/* compute prec. */
{
- secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */
- secp256k1_gej_t gbase;
- secp256k1_gej_t numsbase;
+ secp256k1_gej precj[1024]; /* Jacobian versions of prec. */
+ secp256k1_gej gbase;
+ secp256k1_gej numsbase;
gbase = gj; /* 16^j * G */
numsbase = nums_gej; /* 2^j * nums. */
for (j = 0; j < 64; j++) {
/* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */
precj[j*16] = numsbase;
for (i = 1; i < 16; i++) {
- secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase);
+ secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL);
}
/* Multiply gbase by 16. */
for (i = 0; i < 4; i++) {
- secp256k1_gej_double_var(&gbase, &gbase);
+ secp256k1_gej_double_var(&gbase, &gbase, NULL);
}
/* Multiply numbase by 2. */
- secp256k1_gej_double_var(&numsbase, &numsbase);
+ secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
if (j == 62) {
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
secp256k1_gej_neg(&numsbase, &numsbase);
- secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej);
+ secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
}
}
- secp256k1_ge_set_all_gej_var(1024, prec, precj);
+ secp256k1_ge_set_all_gej_var(1024, prec, precj, cb);
}
for (j = 0; j < 64; j++) {
for (i = 0; i < 16; i++) {
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]);
}
}
+#else
+ (void)cb;
+ ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
+#endif
secp256k1_ecmult_gen_blind(ctx, NULL);
}
-static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) {
+static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) {
return ctx->prec != NULL;
}
-static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst,
- const secp256k1_ecmult_gen_context_t *src) {
+static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
+ const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {
if (src->prec == NULL) {
dst->prec = NULL;
} else {
- dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec));
+#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
+ dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
+#else
+ (void)cb;
+ dst->prec = src->prec;
+#endif
dst->initial = src->initial;
dst->blind = src->blind;
}
}
-static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) {
+static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
+#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
free(ctx->prec);
+#endif
secp256k1_scalar_clear(&ctx->blind);
secp256k1_gej_clear(&ctx->initial);
ctx->prec = NULL;
}
-static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) {
- secp256k1_ge_t add;
- secp256k1_ge_storage_t adds;
- secp256k1_scalar_t gnb;
+static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
+ secp256k1_ge add;
+ secp256k1_ge_storage adds;
+ secp256k1_scalar gnb;
int bits;
int i, j;
memset(&adds, 0, sizeof(adds));
@@ -136,14 +156,15 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp
}
/* Setup blinding values for secp256k1_ecmult_gen. */
-static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) {
- secp256k1_scalar_t b;
- secp256k1_gej_t gb;
- secp256k1_fe_t s;
+static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
+ secp256k1_scalar b;
+ secp256k1_gej gb;
+ secp256k1_fe s;
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256_t rng;
int retry;
- if (!seed32) {
+ unsigned char keydata[64] = {0};
+ if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
@@ -155,13 +176,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
* asking the caller for blinding values directly and expecting them to retry on failure.
*/
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0);
+ memcpy(keydata, nonce32, 32);
+ if (seed32 != NULL) {
+ memcpy(keydata + 32, seed32, 32);
+ }
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
+ memset(keydata, 0, sizeof(keydata));
/* Retry for out of range results to achieve uniformity. */
do {
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
retry = !secp256k1_fe_set_b32(&s, nonce32);
retry |= secp256k1_fe_is_zero(&s);
- } while (retry);
+ } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
/* Randomize the projection to defend against multiplier sidechannels. */
secp256k1_gej_rescale(&ctx->initial, &s);
secp256k1_fe_clear(&s);
@@ -170,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons
secp256k1_scalar_set_b32(&b, nonce32, &retry);
/* A blinding value of 0 works, but would undermine the projection hardening. */
retry |= secp256k1_scalar_is_zero(&b);
- } while (retry);
+ } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);
secp256k1_ecmult_gen(ctx, &gb, &b);
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 1b2856f83d..e6e5f47188 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -24,62 +24,107 @@
#define WINDOW_G 16
#endif
-/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
- * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
- * 2^(w-2) entries.
- *
- * There are two versions of this function:
- * - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation,
- * fast to precompute, but slower to use in later additions.
- * - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations,
- * (much) slower to precompute, but a bit faster to use in later additions.
- * To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as
- * G is constant, so it only needs to be done once in advance.
+/** The number of entries a table with precomputed multiples needs to have. */
+#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
+
+/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
+ * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
+ * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
+ * Prej's Z values are undefined, except for the last value.
*/
-static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
- secp256k1_gej_t d;
+static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {
+ secp256k1_gej d;
+ secp256k1_ge a_ge, d_ge;
int i;
- pre[0] = *a;
- secp256k1_gej_double_var(&d, &pre[0]);
- for (i = 1; i < (1 << (w-2)); i++) {
- secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]);
+
+ VERIFY_CHECK(!a->infinity);
+
+ secp256k1_gej_double_var(&d, a, NULL);
+
+ /*
+ * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate
+ * of 'd', and scale the 1P starting value's x/y coordinates without changing its z.
+ */
+ d_ge.x = d.x;
+ d_ge.y = d.y;
+ d_ge.infinity = 0;
+
+ secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);
+ prej[0].x = a_ge.x;
+ prej[0].y = a_ge.y;
+ prej[0].z = a->z;
+ prej[0].infinity = 0;
+
+ zr[0] = d.z;
+ for (i = 1; i < n; i++) {
+ secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);
}
+
+ /*
+ * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only
+ * the final point's z coordinate is actually used though, so just update that.
+ */
+ secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);
+}
+
+/** Fill a table 'pre' with precomputed odd multiples of a.
+ *
+ * There are two versions of this function:
+ * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its
+ * resulting point set to a single constant Z denominator, stores the X and Y
+ * coordinates as ge_storage points in pre, and stores the global Z in rz.
+ * It only operates on tables sized for WINDOW_A wnaf multiples.
+ * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its
+ * resulting point set to actually affine points, and stores those in pre.
+ * It operates on tables of any size, but uses heap-allocated temporaries.
+ *
+ * To compute a*P + b*G, we compute a table for P using the first function,
+ * and for G using the second (which requires an inverse, but it only needs to
+ * happen once).
+ */
+static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
+ secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
+
+ /* Compute the odd multiples in Jacobian form. */
+ secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);
+ /* Bring them to the same Z denominator. */
+ secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
}
-static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) {
- secp256k1_gej_t d;
+static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) {
+ secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n);
+ secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n);
+ secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n);
int i;
- const int table_size = 1 << (w-2);
- secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size);
- secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size);
- prej[0] = *a;
- secp256k1_gej_double_var(&d, a);
- for (i = 1; i < table_size; i++) {
- secp256k1_gej_add_var(&prej[i], &d, &prej[i-1]);
- }
- secp256k1_ge_set_all_gej_var(table_size, prea, prej);
- for (i = 0; i < table_size; i++) {
+
+ /* Compute the odd multiples in Jacobian form. */
+ secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);
+ /* Convert them in batch to affine coordinates. */
+ secp256k1_ge_set_table_gej_var(n, prea, prej, zr);
+ /* Convert them to compact storage form. */
+ for (i = 0; i < n; i++) {
secp256k1_ge_to_storage(&pre[i], &prea[i]);
}
- free(prej);
+
free(prea);
+ free(prej);
+ free(zr);
}
-/** The number of entries a table with precomputed multiples needs to have. */
-#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
-
/** The following two macro retrieves a particular odd multiple from a table
* of precomputed multiples. */
-#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) do { \
+#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
if ((n) > 0) { \
*(r) = (pre)[((n)-1)/2]; \
} else { \
- secp256k1_gej_neg((r), &(pre)[(-(n)-1)/2]); \
+ secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \
} \
} while(0)
+
#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
@@ -92,15 +137,15 @@ static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t
} \
} while(0)
-static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) {
+static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {
ctx->pre_g = NULL;
#ifdef USE_ENDOMORPHISM
ctx->pre_g_128 = NULL;
#endif
}
-static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) {
- secp256k1_gej_t gj;
+static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) {
+ secp256k1_gej gj;
if (ctx->pre_g != NULL) {
return;
@@ -109,35 +154,35 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) {
/* get the generator */
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
- ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
+ ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
/* precompute the tables with odd multiples */
- secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g, &gj, WINDOW_G);
+ secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb);
#ifdef USE_ENDOMORPHISM
{
- secp256k1_gej_t g_128j;
+ secp256k1_gej g_128j;
int i;
- ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
+ ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
/* calculate 2^128*generator */
g_128j = gj;
for (i = 0; i < 128; i++) {
- secp256k1_gej_double_var(&g_128j, &g_128j);
+ secp256k1_gej_double_var(&g_128j, &g_128j, NULL);
}
- secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G);
+ secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb);
}
#endif
}
-static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst,
- const secp256k1_ecmult_context_t *src) {
+static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
+ const secp256k1_ecmult_context *src, const secp256k1_callback *cb) {
if (src->pre_g == NULL) {
dst->pre_g = NULL;
} else {
size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G);
- dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size);
+ dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
memcpy(dst->pre_g, src->pre_g, size);
}
#ifdef USE_ENDOMORPHISM
@@ -145,17 +190,17 @@ static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst,
dst->pre_g_128 = NULL;
} else {
size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G);
- dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size);
+ dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
memcpy(dst->pre_g_128, src->pre_g_128, size);
}
#endif
}
-static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) {
+static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) {
return ctx->pre_g != NULL;
}
-static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) {
+static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {
free(ctx->pre_g);
#ifdef USE_ENDOMORPHISM
free(ctx->pre_g_128);
@@ -168,54 +213,68 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) {
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
* - two non-zero entries in wnaf are separated by at least w-1 zeroes.
* - the number of set values in wnaf is returned. This number is at most 256, and at most one more
- * - than the number of bits in the (absolute value) of the input.
+ * than the number of bits in the (absolute value) of the input.
*/
-static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) {
- secp256k1_scalar_t s = *a;
- int set_bits = 0;
+static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) {
+ secp256k1_scalar s = *a;
+ int last_set_bit = -1;
int bit = 0;
int sign = 1;
+ int carry = 0;
+
+ VERIFY_CHECK(wnaf != NULL);
+ VERIFY_CHECK(0 <= len && len <= 256);
+ VERIFY_CHECK(a != NULL);
+ VERIFY_CHECK(2 <= w && w <= 31);
+
+ memset(wnaf, 0, len * sizeof(wnaf[0]));
if (secp256k1_scalar_get_bits(&s, 255, 1)) {
secp256k1_scalar_negate(&s, &s);
sign = -1;
}
- while (bit < 256) {
+ while (bit < len) {
int now;
int word;
- if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) {
+ if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) {
bit++;
continue;
}
- while (set_bits < bit) {
- wnaf[set_bits++] = 0;
- }
+
now = w;
- if (bit + now > 256) {
- now = 256 - bit;
- }
- word = secp256k1_scalar_get_bits_var(&s, bit, now);
- if (word & (1 << (w-1))) {
- secp256k1_scalar_add_bit(&s, bit + w);
- wnaf[set_bits++] = sign * (word - (1 << w));
- } else {
- wnaf[set_bits++] = sign * word;
+ if (now > len - bit) {
+ now = len - bit;
}
+
+ word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry;
+
+ carry = (word >> (w-1)) & 1;
+ word -= carry << w;
+
+ wnaf[bit] = sign * word;
+ last_set_bit = bit;
+
bit += now;
}
- return set_bits;
+#ifdef VERIFY
+ CHECK(carry == 0);
+ while (bit < 256) {
+ CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
+ }
+#endif
+ return last_set_bit + 1;
}
-static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) {
- secp256k1_gej_t tmpj;
- secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
- secp256k1_ge_t tmpa;
+static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
+ secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_ge tmpa;
+ secp256k1_fe Z;
#ifdef USE_ENDOMORPHISM
- secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
- secp256k1_scalar_t na_1, na_lam;
+ secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_scalar na_1, na_lam;
/* Splitted G factors. */
- secp256k1_scalar_t ng_1, ng_128;
+ secp256k1_scalar ng_1, ng_128;
int wnaf_na_1[130];
int wnaf_na_lam[130];
int bits_na_1;
@@ -227,7 +286,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
#else
int wnaf_na[256];
int bits_na;
- int wnaf_ng[257];
+ int wnaf_ng[256];
int bits_ng;
#endif
int i;
@@ -235,11 +294,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
#ifdef USE_ENDOMORPHISM
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
- secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na);
+ secp256k1_scalar_split_lambda(&na_1, &na_lam, na);
/* build wnaf representation for na_1 and na_lam. */
- bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
- bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
+ bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A);
+ bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A);
VERIFY_CHECK(bits_na_1 <= 130);
VERIFY_CHECK(bits_na_lam <= 130);
bits = bits_na_1;
@@ -248,24 +307,33 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
}
#else
/* build wnaf representation for na. */
- bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
+ bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A);
bits = bits_na;
#endif
- /* calculate odd multiples of a */
- secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A);
+ /* Calculate odd multiples of a.
+ * All multiples are brought to the same Z 'denominator', which is stored
+ * in Z. Due to secp256k1' isomorphism we can do all operations pretending
+ * that the Z coordinate was 1, use affine addition formulae, and correct
+ * the Z coordinate of the result once at the end.
+ * The exception is the precomputed G table points, which are actually
+ * affine. Compared to the base used for other points, they have a Z ratio
+ * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
+ * isomorphism to efficiently add with a known Z inverse.
+ */
+ secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a);
#ifdef USE_ENDOMORPHISM
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]);
+ secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
/* Build wnaf representation for ng_1 and ng_128 */
- bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
- bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
+ bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
+ bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);
if (bits_ng_1 > bits) {
bits = bits_ng_1;
}
@@ -273,7 +341,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
bits = bits_ng_128;
}
#else
- bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G);
+ bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
if (bits_ng > bits) {
bits = bits_ng;
}
@@ -281,37 +349,41 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
secp256k1_gej_set_infinity(r);
- for (i = bits-1; i >= 0; i--) {
+ for (i = bits - 1; i >= 0; i--) {
int n;
- secp256k1_gej_double_var(r, r);
+ secp256k1_gej_double_var(r, r, NULL);
#ifdef USE_ENDOMORPHISM
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
- ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
- secp256k1_gej_add_var(r, r, &tmpj);
+ ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
+ secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
- ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
- secp256k1_gej_add_var(r, r, &tmpj);
+ ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
+ secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
- secp256k1_gej_add_ge_var(r, r, &tmpa);
+ secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G);
- secp256k1_gej_add_ge_var(r, r, &tmpa);
+ secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
#else
if (i < bits_na && (n = wnaf_na[i])) {
- ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
- secp256k1_gej_add_var(r, r, &tmpj);
+ ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
+ secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
if (i < bits_ng && (n = wnaf_ng[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
- secp256k1_gej_add_ge_var(r, r, &tmpa);
+ secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
#endif
}
+
+ if (!r->infinity) {
+ secp256k1_fe_mul(&r->z, &r->z, &Z);
+ }
}
#endif
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 41b280892d..2d52af5e36 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -10,7 +10,7 @@
/** Field element module.
*
* Field elements can be represented in several ways, but code accessing
- * it (and implementations) need to take certain properaties into account:
+ * it (and implementations) need to take certain properties into account:
* - Each field element can be normalized or not.
* - Each field element has a magnitude, which represents how far away
* its representation is away from normalization. Normalized elements
@@ -31,89 +31,91 @@
#endif
/** Normalize a field element. */
-static void secp256k1_fe_normalize(secp256k1_fe_t *r);
+static void secp256k1_fe_normalize(secp256k1_fe *r);
/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */
-static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r);
+static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
/** Normalize a field element, without constant-time guarantee. */
-static void secp256k1_fe_normalize_var(secp256k1_fe_t *r);
+static void secp256k1_fe_normalize_var(secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
* implementation may optionally normalize the input, but this should not be relied upon. */
-static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r);
+static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
* implementation may optionally normalize the input, but this should not be relied upon. */
-static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r);
+static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
/** Set a field element equal to a small integer. Resulting field element is normalized. */
-static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a);
+static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
/** Verify whether a field element is zero. Requires the input to be normalized. */
-static int secp256k1_fe_is_zero(const secp256k1_fe_t *a);
+static int secp256k1_fe_is_zero(const secp256k1_fe *a);
/** Check the "oddness" of a field element. Requires the input to be normalized. */
-static int secp256k1_fe_is_odd(const secp256k1_fe_t *a);
+static int secp256k1_fe_is_odd(const secp256k1_fe *a);
/** Compare two field elements. Requires magnitude-1 inputs. */
-static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
+static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
/** Compare two field elements. Requires both inputs to be normalized */
-static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
+static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */
-static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
+/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */
+static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a);
+static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
* as an argument. The magnitude of the output is one higher. */
-static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m);
+static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */
-static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a);
+static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
-static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
-static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b);
+static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
-static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
-/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the
- * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be
- * normalized). Return value indicates whether a square root was found. */
-static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+/** If a has a square root, it is computed in r and 1 is returned. If a does not
+ * have a square root, the root of its negation is computed and 0 is returned.
+ * The input's magnitude can be at most 8. The output magnitude is 1 (but not
+ * guaranteed to be normalized). The result in r will always be a square
+ * itself. */
+static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
-static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
-static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be
* at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and
* outputs must not overlap in memory. */
-static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a);
+static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a);
/** Convert a field element to the storage type. */
-static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*);
+static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
/** Convert a field element back from the storage type. */
-static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*);
+static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
-static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag);
+static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
-static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag);
+static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
#endif
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 44bce6525d..61ee1e0965 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -16,20 +16,20 @@ typedef struct {
int magnitude;
int normalized;
#endif
-} secp256k1_fe_t;
+} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
(d0) & 0x3FFFFFFUL, \
- ((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \
- ((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \
- ((d2) >> 14) | ((d3) & 0xFFUL) << 18, \
- ((d3) >> 8) | ((d4) & 0x3) << 24, \
- ((d4) >> 2) & 0x3FFFFFFUL, \
- ((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \
- ((d5) >> 22) | ((d6) & 0xFFFF) << 10, \
- ((d6) >> 16) | ((d7) & 0x3FF) << 16, \
- ((d7) >> 10) \
+ (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \
+ (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \
+ (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \
+ (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \
+ (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \
+ (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \
+ (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \
+ (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \
+ (((uint32_t)d7) >> 10) \
}
#ifdef VERIFY
@@ -40,8 +40,8 @@ typedef struct {
typedef struct {
uint32_t n[8];
-} secp256k1_fe_storage_t;
+} secp256k1_fe_storage;
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
-
+#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]
#endif
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 871b91f912..212cc5396a 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -14,7 +14,7 @@
#include "field.h"
#ifdef VERIFY
-static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
const uint32_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
r &= (d[0] <= 0x3FFFFFFUL * m);
@@ -41,12 +41,12 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
VERIFY_CHECK(r == 1);
}
#else
-static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
(void)a;
}
#endif
-static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
+static void secp256k1_fe_normalize(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -101,7 +101,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
#endif
}
-static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
+static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -132,7 +132,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
#endif
}
-static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
+static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -188,7 +188,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
#endif
}
-static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
+static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -217,7 +217,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
-static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
+static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {
uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
uint32_t z0, z1;
uint32_t x;
@@ -252,7 +252,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
t9 &= 0x03FFFFFUL;
t1 += (x << 6);
- t1 += (t0 >> 26); t0 = z0;
+ t1 += (t0 >> 26);
t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL;
t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2;
t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3;
@@ -269,7 +269,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
#ifdef VERIFY
@@ -279,7 +279,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
#endif
}
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
const uint32_t *t = a->n;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
@@ -288,7 +288,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;
}
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
@@ -296,7 +296,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
return a->n[0] & 1;
}
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
+SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
int i;
#ifdef VERIFY
a->magnitude = 0;
@@ -307,7 +307,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
}
}
-static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
@@ -326,7 +326,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b
return 0;
}
-static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
int i;
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
@@ -350,7 +350,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
@@ -368,7 +368,7 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
}
}
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
+SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_verify(a);
@@ -390,7 +390,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25
#endif
}
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
@@ -408,7 +408,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a);
#endif
@@ -1039,7 +1039,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
}
-static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
+static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
@@ -1055,7 +1055,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s
#endif
}
-static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
secp256k1_fe_verify(a);
@@ -1068,7 +1068,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
-static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
+static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1;
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
@@ -1083,12 +1083,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
#ifdef VERIFY
- r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1);
- r->normalized = (r->normalized & mask0) | (a->normalized & mask1);
+ if (a->magnitude > r->magnitude) {
+ r->magnitude = a->magnitude;
+ }
+ r->normalized &= a->normalized;
#endif
}
-static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) {
+static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
@@ -1102,7 +1104,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
}
-static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
@@ -1116,7 +1118,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f
r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
}
-static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) {
+static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0x3FFFFFFUL;
r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);
r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index 4513d36f49..8e69a560dc 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -16,15 +16,15 @@ typedef struct {
int magnitude;
int normalized;
#endif
-} secp256k1_fe_t;
+} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
- (d0) | ((uint64_t)(d1) & 0xFFFFFUL) << 32, \
- ((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \
- ((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \
- ((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \
- ((d6) >> 16) | ((uint64_t)(d7)) << 16 \
+ (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \
+ ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \
+ ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \
+ ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \
+ ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \
}
#ifdef VERIFY
@@ -35,13 +35,13 @@ typedef struct {
typedef struct {
uint64_t n[4];
-} secp256k1_fe_storage_t;
+} secp256k1_fe_storage;
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \
- (d0) | ((uint64_t)(d1)) << 32, \
- (d2) | ((uint64_t)(d3)) << 32, \
- (d4) | ((uint64_t)(d5)) << 32, \
- (d6) | ((uint64_t)(d7)) << 32 \
+ (d0) | (((uint64_t)(d1)) << 32), \
+ (d2) | (((uint64_t)(d3)) << 32), \
+ (d4) | (((uint64_t)(d5)) << 32), \
+ (d6) | (((uint64_t)(d7)) << 32) \
}}
#endif
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index bda4c3dfc2..b31e24ab81 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -31,7 +31,7 @@
*/
#ifdef VERIFY
-static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
const uint64_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
/* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
@@ -51,12 +51,12 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
VERIFY_CHECK(r == 1);
}
#else
-static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
(void)a;
}
#endif
-static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
+static void secp256k1_fe_normalize(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -99,7 +99,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
#endif
}
-static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
+static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -123,7 +123,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
#endif
}
-static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
+static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -167,7 +167,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
#endif
}
-static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
+static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
@@ -190,7 +190,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
-static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
+static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {
uint64_t t0, t1, t2, t3, t4;
uint64_t z0, z1;
uint64_t x;
@@ -219,7 +219,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
t4 &= 0x0FFFFFFFFFFFFULL;
- t1 += (t0 >> 52); t0 = z0;
+ t1 += (t0 >> 52);
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;
@@ -231,7 +231,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
#ifdef VERIFY
@@ -241,7 +241,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
#endif
}
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
const uint64_t *t = a->n;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
@@ -250,7 +250,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
}
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
@@ -258,7 +258,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
return a->n[0] & 1;
}
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
+SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
int i;
#ifdef VERIFY
a->magnitude = 0;
@@ -269,7 +269,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
}
}
-static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
@@ -288,7 +288,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b
return 0;
}
-static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
int i;
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
for (i=0; i<32; i++) {
@@ -311,7 +311,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
@@ -329,7 +329,7 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
}
}
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
+SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_verify(a);
@@ -346,7 +346,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25
#endif
}
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
@@ -359,7 +359,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a);
#endif
@@ -375,7 +375,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
#endif
}
-static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
+static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
@@ -391,7 +391,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s
#endif
}
-static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
secp256k1_fe_verify(a);
@@ -404,7 +404,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
-static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
+static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1;
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
@@ -414,12 +414,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
#ifdef VERIFY
- r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1);
- r->normalized = (r->normalized & mask0) | (a->normalized & mask1);
+ if (a->magnitude > r->magnitude) {
+ r->magnitude = a->magnitude;
+ }
+ r->normalized &= a->normalized;
#endif
}
-static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) {
+static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
@@ -429,7 +431,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
}
-static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
@@ -439,7 +441,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f
r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
}
-static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) {
+static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index e6ec11e8f2..77f4aae2f9 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -21,15 +21,24 @@
#error "Please select field implementation"
#endif
-SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
- secp256k1_fe_t na;
+SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe na;
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero_var(&na);
}
-static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
- secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
+static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
+ /** Given that p is congruent to 3 mod 4, we can compute the square root of
+ * a mod p as the (p+1)/4'th power of a.
+ *
+ * As (p+1)/4 is an even number, it will have the same result for a and for
+ * (-a). Only one of these two numbers actually has a square root however,
+ * so we test at the end by squaring and comparing to the input.
+ * Also because (p+1)/4 is an even number, the computed square root is
+ * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
+ */
+ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
@@ -117,8 +126,8 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
return secp256k1_fe_equal_var(&t1, a);
}
-static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
- secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
+static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
+ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
/** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
@@ -207,11 +216,15 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_fe_mul(r, a, &t1);
}
-static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {
#if defined(USE_FIELD_INV_BUILTIN)
secp256k1_fe_inv(r, a);
#elif defined(USE_FIELD_INV_NUM)
- secp256k1_num_t n, m;
+ secp256k1_num n, m;
+ static const secp256k1_fe negone = SECP256K1_FE_CONST(
+ 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+ 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL
+ );
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
static const unsigned char prime[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
@@ -220,21 +233,28 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
};
unsigned char b[32];
- secp256k1_fe_t c = *a;
+ int res;
+ secp256k1_fe c = *a;
secp256k1_fe_normalize_var(&c);
secp256k1_fe_get_b32(b, &c);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_set_bin(&m, prime, 32);
secp256k1_num_mod_inverse(&n, &n, &m);
secp256k1_num_get_bin(b, 32, &n);
- VERIFY_CHECK(secp256k1_fe_set_b32(r, b));
+ res = secp256k1_fe_set_b32(r, b);
+ (void)res;
+ VERIFY_CHECK(res);
+ /* Verify the result is the (unique) valid inverse using non-GMP code. */
+ secp256k1_fe_mul(&c, &c, r);
+ secp256k1_fe_add(&c, &negone);
+ CHECK(secp256k1_fe_normalizes_to_zero_var(&c));
#else
#error "Please select field inverse implementation"
#endif
}
-static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) {
- secp256k1_fe_t u;
+static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) {
+ secp256k1_fe u;
size_t i;
if (len < 1) {
return;
@@ -252,7 +272,7 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25
secp256k1_fe_inv_var(&u, &r[--i]);
while (i > 0) {
- int j = i--;
+ size_t j = i--;
secp256k1_fe_mul(&r[j], &r[i], &u);
secp256k1_fe_mul(&u, &u, &a[j]);
}
diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c
new file mode 100644
index 0000000000..1835fd491d
--- /dev/null
+++ b/src/secp256k1/src/gen_context.c
@@ -0,0 +1,74 @@
+/**********************************************************************
+ * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#define USE_BASIC_CONFIG 1
+
+#include "basic-config.h"
+#include "include/secp256k1.h"
+#include "field_impl.h"
+#include "scalar_impl.h"
+#include "group_impl.h"
+#include "ecmult_gen_impl.h"
+
+static void default_error_callback_fn(const char* str, void* data) {
+ (void)data;
+ fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
+ abort();
+}
+
+static const secp256k1_callback default_error_callback = {
+ default_error_callback_fn,
+ NULL
+};
+
+int main(int argc, char **argv) {
+ secp256k1_ecmult_gen_context ctx;
+ int inner;
+ int outer;
+ FILE* fp;
+
+ (void)argc;
+ (void)argv;
+
+ fp = fopen("src/ecmult_static_context.h","w");
+ if (fp == NULL) {
+ fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
+ return -1;
+ }
+
+ fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
+ fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
+ fprintf(fp, "#include \"group.h\"\n");
+ fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
+ fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
+
+ secp256k1_ecmult_gen_context_init(&ctx);
+ secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);
+ for(outer = 0; outer != 64; outer++) {
+ fprintf(fp,"{\n");
+ for(inner = 0; inner != 16; inner++) {
+ fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner]));
+ if (inner != 15) {
+ fprintf(fp,",\n");
+ } else {
+ fprintf(fp,"\n");
+ }
+ }
+ if (outer != 63) {
+ fprintf(fp,"},\n");
+ } else {
+ fprintf(fp,"}\n");
+ }
+ }
+ fprintf(fp,"};\n");
+ secp256k1_ecmult_gen_context_clear(&ctx);
+
+ fprintf(fp, "#undef SC\n");
+ fprintf(fp, "#endif\n");
+ fclose(fp);
+
+ return 0;
+}
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index 0b08b3b991..ebfe1ca70c 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -12,110 +12,130 @@
/** A group element of the secp256k1 curve, in affine coordinates. */
typedef struct {
- secp256k1_fe_t x;
- secp256k1_fe_t y;
+ secp256k1_fe x;
+ secp256k1_fe y;
int infinity; /* whether this represents the point at infinity */
-} secp256k1_ge_t;
+} secp256k1_ge;
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
/** A group element of the secp256k1 curve, in jacobian coordinates. */
typedef struct {
- secp256k1_fe_t x; /* actual X: x/z^2 */
- secp256k1_fe_t y; /* actual Y: y/z^3 */
- secp256k1_fe_t z;
+ secp256k1_fe x; /* actual X: x/z^2 */
+ secp256k1_fe y; /* actual Y: y/z^3 */
+ secp256k1_fe z;
int infinity; /* whether this represents the point at infinity */
-} secp256k1_gej_t;
+} secp256k1_gej;
#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0}
#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
typedef struct {
- secp256k1_fe_storage_t x;
- secp256k1_fe_storage_t y;
-} secp256k1_ge_storage_t;
+ secp256k1_fe_storage x;
+ secp256k1_fe_storage y;
+} secp256k1_ge_storage;
#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))}
-/** Set a group element equal to the point at infinity */
-static void secp256k1_ge_set_infinity(secp256k1_ge_t *r);
+#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y)
/** Set a group element equal to the point with given X and Y coordinates */
-static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
+static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y);
+
+/** Set a group element (affine) equal to the point with the given X coordinate
+ * and a Y coordinate that is a quadratic residue modulo p. The return value
+ * is true iff a coordinate with the given X coordinate exists.
+ */
+static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x);
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
* for Y. Return value indicates whether the result is valid. */
-static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd);
+static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
/** Check whether a group element is the point at infinity. */
-static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a);
+static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
/** Check whether a group element is valid (i.e., on the curve). */
-static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a);
+static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
-static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a);
+static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
/** Set a group element equal to another which is given in jacobian coordinates */
-static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a);
+static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
-static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a);
+static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb);
+/** Set a batch of group elements equal to the inputs given in jacobian
+ * coordinates (with known z-ratios). zr must contain the known z-ratios such
+ * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
+static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr);
-/** Set a group element (jacobian) equal to the point at infinity. */
-static void secp256k1_gej_set_infinity(secp256k1_gej_t *r);
+/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
+ * the same global z "denominator". zr must contain the known z-ratios such
+ * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y
+ * coordinates of the result are stored in r, the common z coordinate is
+ * stored in globalz. */
+static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
-/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */
-static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
+/** Set a group element (jacobian) equal to the point at infinity. */
+static void secp256k1_gej_set_infinity(secp256k1_gej *r);
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
-static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a);
+static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
/** Compare the X coordinate of a group element (jacobian). */
-static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a);
+static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
-static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a);
+static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
/** Check whether a group element is the point at infinity. */
-static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a);
+static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
-/** Set r equal to the double of a. */
-static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a);
+/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
+ * a may not be zero. Constant time. */
+static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
-/** Set r equal to the sum of a and b. */
-static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b);
+/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */
+static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
+
+/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
+static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
-static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
+static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b);
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
- guarantee, and b is allowed to be infinity. */
-static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
+ guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
+static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);
+
+/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */
+static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv);
#ifdef USE_ENDOMORPHISM
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
-static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
+static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);
#endif
-/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */
-static void secp256k1_gej_clear(secp256k1_gej_t *r);
+/** Clear a secp256k1_gej to prevent leaking sensitive information. */
+static void secp256k1_gej_clear(secp256k1_gej *r);
-/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */
-static void secp256k1_ge_clear(secp256k1_ge_t *r);
+/** Clear a secp256k1_ge to prevent leaking sensitive information. */
+static void secp256k1_ge_clear(secp256k1_ge *r);
/** Convert a group element to the storage type. */
-static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t*);
+static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a);
/** Convert a group element back from the storage type. */
-static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t*);
+static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
-static void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag);
+static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
-static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *b);
+static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
#endif
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 0f64576fbb..42e2f6e6eb 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -16,35 +16,41 @@
/** Generator for secp256k1, value 'g' defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
*/
-static const secp256k1_ge_t secp256k1_ge_const_g = SECP256K1_GE_CONST(
+static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,
0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,
0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
);
-static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) {
- r->infinity = 1;
+static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
+ secp256k1_fe zi2;
+ secp256k1_fe zi3;
+ secp256k1_fe_sqr(&zi2, zi);
+ secp256k1_fe_mul(&zi3, &zi2, zi);
+ secp256k1_fe_mul(&r->x, &a->x, &zi2);
+ secp256k1_fe_mul(&r->y, &a->y, &zi3);
+ r->infinity = a->infinity;
}
-static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
+static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
r->infinity = 0;
r->x = *x;
r->y = *y;
}
-static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a) {
+static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
return a->infinity;
}
-static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) {
+static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
*r = *a;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
}
-static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
- secp256k1_fe_t z2, z3;
+static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
+ secp256k1_fe z2, z3;
r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
@@ -56,8 +62,8 @@ static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
r->y = a->y;
}
-static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) {
- secp256k1_fe_t z2, z3;
+static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
+ secp256k1_fe z2, z3;
r->infinity = a->infinity;
if (a->infinity) {
return;
@@ -72,19 +78,19 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) {
r->y = a->y;
}
-static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) {
- secp256k1_fe_t *az;
- secp256k1_fe_t *azi;
+static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) {
+ secp256k1_fe *az;
+ secp256k1_fe *azi;
size_t i;
size_t count = 0;
- az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len);
+ az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);
for (i = 0; i < len; i++) {
if (!a[i].infinity) {
az[count++] = a[i].z;
}
}
- azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count);
+ azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
secp256k1_fe_inv_all_var(count, azi, az);
free(az);
@@ -92,53 +98,86 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const se
for (i = 0; i < len; i++) {
r[i].infinity = a[i].infinity;
if (!a[i].infinity) {
- secp256k1_fe_t zi2, zi3;
- secp256k1_fe_t *zi = &azi[count++];
- secp256k1_fe_sqr(&zi2, zi);
- secp256k1_fe_mul(&zi3, &zi2, zi);
- secp256k1_fe_mul(&r[i].x, &a[i].x, &zi2);
- secp256k1_fe_mul(&r[i].y, &a[i].y, &zi3);
+ secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
}
}
free(azi);
}
-static void secp256k1_gej_set_infinity(secp256k1_gej_t *r) {
+static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) {
+ size_t i = len - 1;
+ secp256k1_fe zi;
+
+ if (len > 0) {
+ /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */
+ secp256k1_fe_inv(&zi, &a[i].z);
+ secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
+
+ /* Work out way backwards, using the z-ratios to scale the x/y values. */
+ while (i > 0) {
+ secp256k1_fe_mul(&zi, &zi, &zr[i]);
+ i--;
+ secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
+ }
+ }
+}
+
+static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {
+ size_t i = len - 1;
+ secp256k1_fe zs;
+
+ if (len > 0) {
+ /* The z of the final point gives us the "global Z" for the table. */
+ r[i].x = a[i].x;
+ r[i].y = a[i].y;
+ *globalz = a[i].z;
+ r[i].infinity = 0;
+ zs = zr[i];
+
+ /* Work our way backwards, using the z-ratios to scale the x/y values. */
+ while (i > 0) {
+ if (i != len - 1) {
+ secp256k1_fe_mul(&zs, &zs, &zr[i]);
+ }
+ i--;
+ secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);
+ }
+ }
+}
+
+static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
r->infinity = 1;
secp256k1_fe_set_int(&r->x, 0);
secp256k1_fe_set_int(&r->y, 0);
secp256k1_fe_set_int(&r->z, 0);
}
-static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
- r->infinity = 0;
- r->x = *x;
- r->y = *y;
- secp256k1_fe_set_int(&r->z, 1);
-}
-
-static void secp256k1_gej_clear(secp256k1_gej_t *r) {
+static void secp256k1_gej_clear(secp256k1_gej *r) {
r->infinity = 0;
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z);
}
-static void secp256k1_ge_clear(secp256k1_ge_t *r) {
+static void secp256k1_ge_clear(secp256k1_ge *r) {
r->infinity = 0;
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
}
-static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) {
- secp256k1_fe_t x2, x3, c;
+static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
+ secp256k1_fe x2, x3, c;
r->x = *x;
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&c, &x3);
- if (!secp256k1_fe_sqrt_var(&r->y, &c)) {
+ return secp256k1_fe_sqrt_var(&r->y, &c);
+}
+
+static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
+ if (!secp256k1_ge_set_xquad_var(r, x)) {
return 0;
}
secp256k1_fe_normalize_var(&r->y);
@@ -146,24 +185,25 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, i
secp256k1_fe_negate(&r->y, &r->y, 1);
}
return 1;
+
}
-static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) {
+static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_set_int(&r->z, 1);
}
-static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) {
- secp256k1_fe_t r, r2;
+static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
+ secp256k1_fe r, r2;
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
return secp256k1_fe_equal_var(&r, &r2);
}
-static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
+static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
@@ -172,12 +212,12 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
secp256k1_fe_negate(&r->y, &r->y, 1);
}
-static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) {
+static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
return a->infinity;
}
-static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
- secp256k1_fe_t y2, x3, z2, z6;
+static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
+ secp256k1_fe y2, x3, z2, z6;
if (a->infinity) {
return 0;
}
@@ -196,8 +236,8 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
return secp256k1_fe_equal_var(&y2, &x3);
}
-static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) {
- secp256k1_fe_t y2, x3, c;
+static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
+ secp256k1_fe y2, x3, c;
if (a->infinity) {
return 0;
}
@@ -210,18 +250,27 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) {
return secp256k1_fe_equal_var(&y2, &x3);
}
-static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
+static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
- secp256k1_fe_t t1,t2,t3,t4;
+ secp256k1_fe t1,t2,t3,t4;
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
*/
r->infinity = a->infinity;
if (r->infinity) {
+ if (rzr != NULL) {
+ secp256k1_fe_set_int(rzr, 1);
+ }
return;
}
+ if (rzr != NULL) {
+ *rzr = a->y;
+ secp256k1_fe_normalize_weak(rzr);
+ secp256k1_fe_mul_int(rzr, 2);
+ }
+
secp256k1_fe_mul(&r->z, &a->z, &a->y);
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
secp256k1_fe_sqr(&t1, &a->x);
@@ -244,17 +293,29 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
}
-static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
+static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
+ VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
+ secp256k1_gej_double_var(r, a, rzr);
+}
+
+static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
/* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */
- secp256k1_fe_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
+ secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
+
if (a->infinity) {
+ VERIFY_CHECK(rzr == NULL);
*r = *b;
return;
}
+
if (b->infinity) {
+ if (rzr != NULL) {
+ secp256k1_fe_set_int(rzr, 1);
+ }
*r = *a;
return;
}
+
r->infinity = 0;
secp256k1_fe_sqr(&z22, &b->z);
secp256k1_fe_sqr(&z12, &a->z);
@@ -266,8 +327,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
- secp256k1_gej_double_var(r, a);
+ secp256k1_gej_double_var(r, a, rzr);
} else {
+ if (rzr != NULL) {
+ secp256k1_fe_set_int(rzr, 0);
+ }
r->infinity = 1;
}
return;
@@ -275,7 +339,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
secp256k1_fe_sqr(&i2, &i);
secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_mul(&h3, &h, &h2);
- secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h);
+ secp256k1_fe_mul(&h, &h, &b->z);
+ if (rzr != NULL) {
+ *rzr = h;
+ }
+ secp256k1_fe_mul(&r->z, &a->z, &h);
secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
@@ -283,21 +351,23 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
secp256k1_fe_add(&r->y, &h3);
}
-static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
+static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
/* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */
- secp256k1_fe_t z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
+ secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
if (a->infinity) {
- r->infinity = b->infinity;
- r->x = b->x;
- r->y = b->y;
- secp256k1_fe_set_int(&r->z, 1);
+ VERIFY_CHECK(rzr == NULL);
+ secp256k1_gej_set_ge(r, b);
return;
}
if (b->infinity) {
+ if (rzr != NULL) {
+ secp256k1_fe_set_int(rzr, 1);
+ }
*r = *a;
return;
}
r->infinity = 0;
+
secp256k1_fe_sqr(&z12, &a->z);
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
secp256k1_fe_mul(&u2, &b->x, &z12);
@@ -307,7 +377,69 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
- secp256k1_gej_double_var(r, a);
+ secp256k1_gej_double_var(r, a, rzr);
+ } else {
+ if (rzr != NULL) {
+ secp256k1_fe_set_int(rzr, 0);
+ }
+ r->infinity = 1;
+ }
+ return;
+ }
+ secp256k1_fe_sqr(&i2, &i);
+ secp256k1_fe_sqr(&h2, &h);
+ secp256k1_fe_mul(&h3, &h, &h2);
+ if (rzr != NULL) {
+ *rzr = h;
+ }
+ secp256k1_fe_mul(&r->z, &a->z, &h);
+ secp256k1_fe_mul(&t, &u1, &h2);
+ r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
+ secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
+ secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
+ secp256k1_fe_add(&r->y, &h3);
+}
+
+static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
+ /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */
+ secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
+
+ if (b->infinity) {
+ *r = *a;
+ return;
+ }
+ if (a->infinity) {
+ secp256k1_fe bzinv2, bzinv3;
+ r->infinity = b->infinity;
+ secp256k1_fe_sqr(&bzinv2, bzinv);
+ secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv);
+ secp256k1_fe_mul(&r->x, &b->x, &bzinv2);
+ secp256k1_fe_mul(&r->y, &b->y, &bzinv3);
+ secp256k1_fe_set_int(&r->z, 1);
+ return;
+ }
+ r->infinity = 0;
+
+ /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to
+ * secp256k1's isomorphism we can multiply the Z coordinates on both sides
+ * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1).
+ * This means that (rx,ry,rz) can be calculated as
+ * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz.
+ * The variable az below holds the modified Z coordinate for a, which is used
+ * for the computation of rx and ry, but not for rz.
+ */
+ secp256k1_fe_mul(&az, &a->z, bzinv);
+
+ secp256k1_fe_sqr(&z12, &az);
+ u1 = a->x; secp256k1_fe_normalize_weak(&u1);
+ secp256k1_fe_mul(&u2, &b->x, &z12);
+ s1 = a->y; secp256k1_fe_normalize_weak(&s1);
+ secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az);
+ secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
+ secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
+ if (secp256k1_fe_normalizes_to_zero_var(&h)) {
+ if (secp256k1_fe_normalizes_to_zero_var(&i)) {
+ secp256k1_gej_double_var(r, a, NULL);
} else {
r->infinity = 1;
}
@@ -324,11 +456,13 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
secp256k1_fe_add(&r->y, &h3);
}
-static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
- /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */
- static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
- secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr;
- int infinity;
+
+static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
+ /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */
+ static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+ secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
+ secp256k1_fe m_alt, rr_alt;
+ int infinity, degenerate;
VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
@@ -352,53 +486,102 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
* Y3 = 4*(R*(3*Q-2*R^2)-M^4)
* Z3 = 2*M*Z
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
+ *
+ * This formula has the benefit of being the same for both addition
+ * of distinct points and doubling. However, it breaks down in the
+ * case that either point is infinity, or that y1 = -y2. We handle
+ * these cases in the following ways:
+ *
+ * - If b is infinity we simply bail by means of a VERIFY_CHECK.
+ *
+ * - If a is infinity, we detect this, and at the end of the
+ * computation replace the result (which will be meaningless,
+ * but we compute to be constant-time) with b.x : b.y : 1.
+ *
+ * - If a = -b, we have y1 = -y2, which is a degenerate case.
+ * But here the answer is infinity, so we simply set the
+ * infinity flag of the result, overriding the computed values
+ * without even needing to cmov.
+ *
+ * - If y1 = -y2 but x1 != x2, which does occur thanks to certain
+ * properties of our curve (specifically, 1 has nontrivial cube
+ * roots in our field, and the curve equation has no x coefficient)
+ * then the answer is not infinity but also not given by the above
+ * equation. In this case, we cmov in place an alternate expression
+ * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these
+ * expressions for lambda are defined, they are equal, and can be
+ * obtained from each other by multiplication by (y1 + y2)/(y1 + y2)
+ * then substitution of x^3 + 7 for y^2 (using the curve equation).
+ * For all pairs of nonzero points (a, b) at least one is defined,
+ * so this covers everything.
*/
secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */
u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */
secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */
s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */
- secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */
+ secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */
secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */
- z = a->z; /* z = Z = Z1*Z2 (8) */
t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */
m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */
- secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */
- secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */
- secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */
secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */
- secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */
- secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */
- secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */
- secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */
+ secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
+ secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
+ secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */
+ /** If lambda = R/M = 0/0 we have a problem (except in the "trivial"
+ * case that Z = z1z2 = 0, and this is special-cased later on). */
+ degenerate = secp256k1_fe_normalizes_to_zero(&m) &
+ secp256k1_fe_normalizes_to_zero(&rr);
+ /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.
+ * This means either x1 == beta*x2 or beta*x1 == x2, where beta is
+ * a nontrivial cube root of one. In either case, an alternate
+ * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2),
+ * so we set R/M equal to this. */
+ rr_alt = s1;
+ secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */
+ secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */
+
+ secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
+ secp256k1_fe_cmov(&m_alt, &m, !degenerate);
+ /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0.
+ * From here on out Ralt and Malt represent the numerator
+ * and denominator of lambda; R and M represent the explicit
+ * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
+ secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
+ secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */
+ /* These two lines use the observation that either M == Malt or M == 0,
+ * so M^3 * Malt is either Malt^4 (which is computed by squaring), or
+ * zero (which is "computed" by cmov). So the cost is one squaring
+ * versus two multiplications. */
+ secp256k1_fe_sqr(&n, &n);
+ secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
+ secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
+ secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */
infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
- secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */
- r->x = t; /* r->x = R^2 (1) */
+ secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
- secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */
- secp256k1_fe_normalize(&r->x);
- secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */
- secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */
- secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */
- secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */
- secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */
- secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */
+ secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */
+ secp256k1_fe_normalize_weak(&t);
+ r->x = t; /* r->x = Ralt^2-Q (1) */
+ secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */
+ secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */
+ secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */
+ secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */
+ secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */
secp256k1_fe_normalize_weak(&r->y);
- secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */
- secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */
+ secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */
+ secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
- /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0.
- * Replace r with b->x, b->y, 1 in that case.
- */
+ /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);
r->infinity = infinity;
}
-static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) {
+static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
/* Operations: 4 mul, 1 sqr */
- secp256k1_fe_t zz;
+ secp256k1_fe zz;
VERIFY_CHECK(!secp256k1_fe_is_zero(s));
secp256k1_fe_sqr(&zz, s);
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
@@ -407,8 +590,8 @@ static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) {
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
}
-static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) {
- secp256k1_fe_t x, y;
+static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
+ secp256k1_fe x, y;
VERIFY_CHECK(!a->infinity);
x = a->x;
secp256k1_fe_normalize(&x);
@@ -418,20 +601,20 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_g
secp256k1_fe_to_storage(&r->y, &y);
}
-static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) {
+static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) {
secp256k1_fe_from_storage(&r->x, &a->x);
secp256k1_fe_from_storage(&r->y, &a->y);
r->infinity = 0;
}
-static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag) {
+static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
secp256k1_fe_storage_cmov(&r->x, &a->x, flag);
secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
}
#ifdef USE_ENDOMORPHISM
-static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
- static const secp256k1_fe_t beta = SECP256K1_FE_CONST(
+static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
+ static const secp256k1_fe beta = SECP256K1_FE_CONST(
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
);
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index 843423d7f7..0ff01e63fa 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -34,7 +34,7 @@ typedef struct {
int retry;
} secp256k1_rfc6979_hmac_sha256_t;
-static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen);
+static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen);
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index 9828827bcd..ae55df6d8a 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -202,7 +202,7 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign
}
-static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen) {
+static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) {
secp256k1_hmac_sha256_t hmac;
static const unsigned char zero[1] = {0x00};
static const unsigned char one[1] = {0x01};
@@ -215,11 +215,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
secp256k1_hmac_sha256_write(&hmac, zero, 1);
secp256k1_hmac_sha256_write(&hmac, key, keylen);
- secp256k1_hmac_sha256_write(&hmac, msg, msglen);
- if (rnd && rndlen) {
- /* RFC6979 3.6 "Additional data". */
- secp256k1_hmac_sha256_write(&hmac, rnd, rndlen);
- }
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
@@ -230,11 +225,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
secp256k1_hmac_sha256_write(&hmac, one, 1);
secp256k1_hmac_sha256_write(&hmac, key, keylen);
- secp256k1_hmac_sha256_write(&hmac, msg, msglen);
- if (rnd && rndlen) {
- /* RFC6979 3.6 "Additional data". */
- secp256k1_hmac_sha256_write(&hmac, rnd, rndlen);
- }
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include
new file mode 100644
index 0000000000..670b9c1152
--- /dev/null
+++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include
@@ -0,0 +1,8 @@
+include_HEADERS += include/secp256k1_ecdh.h
+noinst_HEADERS += src/modules/ecdh/main_impl.h
+noinst_HEADERS += src/modules/ecdh/tests_impl.h
+if USE_BENCHMARK
+noinst_PROGRAMS += bench_ecdh
+bench_ecdh_SOURCES = src/bench_ecdh.c
+bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS)
+endif
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
new file mode 100644
index 0000000000..c23e4f82f7
--- /dev/null
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_ECDH_MAIN_
+#define _SECP256K1_MODULE_ECDH_MAIN_
+
+#include "include/secp256k1_ecdh.h"
+#include "ecmult_const_impl.h"
+
+int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
+ int ret = 0;
+ int overflow = 0;
+ secp256k1_gej res;
+ secp256k1_ge pt;
+ secp256k1_scalar s;
+ ARG_CHECK(result != NULL);
+ ARG_CHECK(point != NULL);
+ ARG_CHECK(scalar != NULL);
+ (void)ctx;
+
+ secp256k1_pubkey_load(ctx, &pt, point);
+ secp256k1_scalar_set_b32(&s, scalar, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&s)) {
+ ret = 0;
+ } else {
+ unsigned char x[32];
+ unsigned char y[1];
+ secp256k1_sha256_t sha;
+
+ secp256k1_ecmult_const(&res, &pt, &s);
+ secp256k1_ge_set_gej(&pt, &res);
+ /* Compute a hash of the point in compressed form
+ * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
+ * expect its output to be secret and has a timing sidechannel. */
+ secp256k1_fe_normalize(&pt.x);
+ secp256k1_fe_normalize(&pt.y);
+ secp256k1_fe_get_b32(x, &pt.x);
+ y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
+
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, y, sizeof(y));
+ secp256k1_sha256_write(&sha, x, sizeof(x));
+ secp256k1_sha256_finalize(&sha, result);
+ ret = 1;
+ }
+
+ secp256k1_scalar_clear(&s);
+ return ret;
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
new file mode 100644
index 0000000000..7badc9033f
--- /dev/null
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -0,0 +1,75 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_ECDH_TESTS_
+#define _SECP256K1_MODULE_ECDH_TESTS_
+
+void test_ecdh_generator_basepoint(void) {
+ unsigned char s_one[32] = { 0 };
+ secp256k1_pubkey point[2];
+ int i;
+
+ s_one[31] = 1;
+ /* Check against pubkey creation when the basepoint is the generator */
+ for (i = 0; i < 100; ++i) {
+ secp256k1_sha256_t sha;
+ unsigned char s_b32[32];
+ unsigned char output_ecdh[32];
+ unsigned char output_ser[32];
+ unsigned char point_ser[33];
+ size_t point_ser_len = sizeof(point_ser);
+ secp256k1_scalar s;
+
+ random_scalar_order(&s);
+ secp256k1_scalar_get_b32(s_b32, &s);
+
+ /* compute using ECDH function */
+ CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
+ CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);
+ /* compute "explicitly" */
+ CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(point_ser_len == sizeof(point_ser));
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, point_ser, point_ser_len);
+ secp256k1_sha256_finalize(&sha, output_ser);
+ /* compare */
+ CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
+ }
+}
+
+void test_bad_scalar(void) {
+ unsigned char s_zero[32] = { 0 };
+ unsigned char s_overflow[32] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+ 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
+ };
+ unsigned char s_rand[32] = { 0 };
+ unsigned char output[32];
+ secp256k1_scalar rand;
+ secp256k1_pubkey point;
+
+ /* Create random point */
+ random_scalar_order(&rand);
+ secp256k1_scalar_get_b32(s_rand, &rand);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
+
+ /* Try to multiply it by bad values */
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
+ /* ...and a good one */
+ s_overflow[31] -= 1;
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
+}
+
+void run_ecdh_tests(void) {
+ test_ecdh_generator_basepoint();
+ test_bad_scalar();
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include
new file mode 100644
index 0000000000..5de3ea33ea
--- /dev/null
+++ b/src/secp256k1/src/modules/recovery/Makefile.am.include
@@ -0,0 +1,8 @@
+include_HEADERS += include/secp256k1_recovery.h
+noinst_HEADERS += src/modules/recovery/main_impl.h
+noinst_HEADERS += src/modules/recovery/tests_impl.h
+if USE_BENCHMARK
+noinst_PROGRAMS += bench_recover
+bench_recover_SOURCES = src/bench_recover.c
+bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
+endif
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
new file mode 100644
index 0000000000..ec42f4bb6c
--- /dev/null
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -0,0 +1,193 @@
+/**********************************************************************
+ * Copyright (c) 2013-2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
+#define _SECP256K1_MODULE_RECOVERY_MAIN_
+
+#include "include/secp256k1_recovery.h"
+
+static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) {
+ (void)ctx;
+ if (sizeof(secp256k1_scalar) == 32) {
+ /* When the secp256k1_scalar type is exactly 32 byte, use its
+ * representation inside secp256k1_ecdsa_signature, as conversion is very fast.
+ * Note that secp256k1_ecdsa_signature_save must use the same representation. */
+ memcpy(r, &sig->data[0], 32);
+ memcpy(s, &sig->data[32], 32);
+ } else {
+ secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
+ secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
+ }
+ *recid = sig->data[64];
+}
+
+static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) {
+ if (sizeof(secp256k1_scalar) == 32) {
+ memcpy(&sig->data[0], r, 32);
+ memcpy(&sig->data[32], s, 32);
+ } else {
+ secp256k1_scalar_get_b32(&sig->data[0], r);
+ secp256k1_scalar_get_b32(&sig->data[32], s);
+ }
+ sig->data[64] = recid;
+}
+
+int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) {
+ secp256k1_scalar r, s;
+ int ret = 1;
+ int overflow = 0;
+
+ (void)ctx;
+ ARG_CHECK(sig != NULL);
+ ARG_CHECK(input64 != NULL);
+ ARG_CHECK(recid >= 0 && recid <= 3);
+
+ secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
+ ret &= !overflow;
+ secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
+ ret &= !overflow;
+ if (ret) {
+ secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid);
+ } else {
+ memset(sig, 0, sizeof(*sig));
+ }
+ return ret;
+}
+
+int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) {
+ secp256k1_scalar r, s;
+
+ (void)ctx;
+ ARG_CHECK(output64 != NULL);
+ ARG_CHECK(sig != NULL);
+ ARG_CHECK(recid != NULL);
+
+ secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig);
+ secp256k1_scalar_get_b32(&output64[0], &r);
+ secp256k1_scalar_get_b32(&output64[32], &s);
+ return 1;
+}
+
+int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) {
+ secp256k1_scalar r, s;
+ int recid;
+
+ (void)ctx;
+ ARG_CHECK(sig != NULL);
+ ARG_CHECK(sigin != NULL);
+
+ secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin);
+ secp256k1_ecdsa_signature_save(sig, &r, &s);
+ return 1;
+}
+
+static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {
+ unsigned char brx[32];
+ secp256k1_fe fx;
+ secp256k1_ge x;
+ secp256k1_gej xj;
+ secp256k1_scalar rn, u1, u2;
+ secp256k1_gej qj;
+ int r;
+
+ if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
+ return 0;
+ }
+
+ secp256k1_scalar_get_b32(brx, sigr);
+ r = secp256k1_fe_set_b32(&fx, brx);
+ (void)r;
+ VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
+ if (recid & 2) {
+ if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
+ return 0;
+ }
+ secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
+ }
+ if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
+ return 0;
+ }
+ secp256k1_gej_set_ge(&xj, &x);
+ secp256k1_scalar_inverse_var(&rn, sigr);
+ secp256k1_scalar_mul(&u1, &rn, message);
+ secp256k1_scalar_negate(&u1, &u1);
+ secp256k1_scalar_mul(&u2, &rn, sigs);
+ secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
+ secp256k1_ge_set_gej_var(pubkey, &qj);
+ return !secp256k1_gej_is_infinity(&qj);
+}
+
+int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
+ secp256k1_scalar r, s;
+ secp256k1_scalar sec, non, msg;
+ int recid;
+ int ret = 0;
+ int overflow = 0;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(signature != NULL);
+ ARG_CHECK(seckey != NULL);
+ if (noncefp == NULL) {
+ noncefp = secp256k1_nonce_function_default;
+ }
+
+ secp256k1_scalar_set_b32(&sec, seckey, &overflow);
+ /* Fail if the secret key is invalid. */
+ if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
+ unsigned int count = 0;
+ secp256k1_scalar_set_b32(&msg, msg32, NULL);
+ while (1) {
+ unsigned char nonce32[32];
+ ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
+ if (!ret) {
+ break;
+ }
+ secp256k1_scalar_set_b32(&non, nonce32, &overflow);
+ memset(nonce32, 0, 32);
+ if (!secp256k1_scalar_is_zero(&non) && !overflow) {
+ if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
+ break;
+ }
+ }
+ count++;
+ }
+ secp256k1_scalar_clear(&msg);
+ secp256k1_scalar_clear(&non);
+ secp256k1_scalar_clear(&sec);
+ }
+ if (ret) {
+ secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
+ } else {
+ memset(signature, 0, sizeof(*signature));
+ }
+ return ret;
+}
+
+int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) {
+ secp256k1_ge q;
+ secp256k1_scalar r, s;
+ secp256k1_scalar m;
+ int recid;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(signature != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
+ ARG_CHECK(recid >= 0 && recid < 4);
+ secp256k1_scalar_set_b32(&m, msg32, NULL);
+ if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
+ secp256k1_pubkey_save(pubkey, &q);
+ return 1;
+ } else {
+ memset(pubkey, 0, sizeof(*pubkey));
+ return 0;
+ }
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h
new file mode 100644
index 0000000000..8932d5f0af
--- /dev/null
+++ b/src/secp256k1/src/modules/recovery/tests_impl.h
@@ -0,0 +1,250 @@
+/**********************************************************************
+ * Copyright (c) 2013-2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
+#define _SECP256K1_MODULE_RECOVERY_TESTS_
+
+void test_ecdsa_recovery_end_to_end(void) {
+ unsigned char extra[32] = {0x00};
+ unsigned char privkey[32];
+ unsigned char message[32];
+ secp256k1_ecdsa_signature signature[5];
+ secp256k1_ecdsa_recoverable_signature rsignature[5];
+ unsigned char sig[74];
+ secp256k1_pubkey pubkey;
+ secp256k1_pubkey recpubkey;
+ int recid = 0;
+
+ /* Generate a random key and message. */
+ {
+ secp256k1_scalar msg, key;
+ random_scalar_order_test(&msg);
+ random_scalar_order_test(&key);
+ secp256k1_scalar_get_b32(privkey, &key);
+ secp256k1_scalar_get_b32(message, &msg);
+ }
+
+ /* Construct and verify corresponding public key. */
+ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+ /* Serialize/parse compact and verify/recover. */
+ extra[0] = 0;
+ CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);
+ extra[31] = 1;
+ CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1);
+ extra[31] = 0;
+ extra[0] = 1;
+ CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+ CHECK(memcmp(&signature[4], &signature[0], 64) == 0);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
+ memset(&rsignature[4], 0, sizeof(rsignature[4]));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
+ /* Parse compact (with recovery id) and recover. */
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
+ CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
+ CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
+ /* Serialize/destroy/parse signature and verify again. */
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
+ sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
+ /* Recover again */
+ CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
+ memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
+}
+
+/* Tests several edge cases. */
+void test_ecdsa_recovery_edge_cases(void) {
+ const unsigned char msg32[32] = {
+ 'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
+ 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
+ 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
+ 's', 's', 'a', 'g', 'e', '.', '.', '.'
+ };
+ const unsigned char sig64[64] = {
+ /* Generated by signing the above message with nonce 'This is the nonce we will use...'
+ * and secret key 0 (which is not valid), resulting in recid 0. */
+ 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
+ 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
+ 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
+ 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
+ 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
+ 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
+ 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
+ 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
+ };
+ secp256k1_pubkey pubkey;
+ /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
+ const unsigned char sigb64[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ };
+ secp256k1_pubkey pubkeyb;
+ secp256k1_ecdsa_recoverable_signature rsig;
+ secp256k1_ecdsa_signature sig;
+ int recid;
+
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0));
+ CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1));
+ CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2));
+ CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3));
+ CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
+
+ for (recid = 0; recid < 4; recid++) {
+ int i;
+ int recid2;
+ /* (4,4) encoded in DER. */
+ unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
+ unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
+ unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
+ unsigned char sigbderalt1[39] = {
+ 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
+ };
+ unsigned char sigbderalt2[39] = {
+ 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ };
+ unsigned char sigbderalt3[40] = {
+ 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
+ };
+ unsigned char sigbderalt4[40] = {
+ 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ };
+ /* (order + r,4) encoded in DER. */
+ unsigned char sigbderlong[40] = {
+ 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,
+ 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
+ 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
+ };
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1);
+ CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
+ for (recid2 = 0; recid2 < 4; recid2++) {
+ secp256k1_pubkey pubkey2b;
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);
+ CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);
+ /* Verifying with (order + r,4) should always fail. */
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ }
+ /* DER parsing tests. */
+ /* Zero length r/s. */
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
+ /* Leading zeros. */
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
+ sigbderalt3[4] = 1;
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ sigbderalt4[7] = 1;
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ /* Damage signature. */
+ sigbder[7]++;
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ sigbder[7]--;
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
+ for(i = 0; i < 8; i++) {
+ int c;
+ unsigned char orig = sigbder[i];
+ /*Try every single-byte change.*/
+ for (c = 0; c < 256; c++) {
+ if (c == orig ) {
+ continue;
+ }
+ sigbder[i] = c;
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
+ }
+ sigbder[i] = orig;
+ }
+ }
+
+ /* Test r/s equal to zero */
+ {
+ /* (1,1) encoded in DER. */
+ unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
+ unsigned char sigc64[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ };
+ secp256k1_pubkey pubkeyc;
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
+ CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1);
+ sigcder[4] = 0;
+ sigc64[31] = 0;
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
+ CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
+ sigcder[4] = 1;
+ sigcder[7] = 0;
+ sigc64[31] = 1;
+ sigc64[63] = 0;
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
+ CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
+ }
+}
+
+void run_recovery_tests(void) {
+ int i;
+ for (i = 0; i < 64*count; i++) {
+ test_ecdsa_recovery_end_to_end();
+ }
+ test_ecdsa_recovery_edge_cases();
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include
new file mode 100644
index 0000000000..b3bfa7d5cc
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include
@@ -0,0 +1,10 @@
+include_HEADERS += include/secp256k1_schnorr.h
+noinst_HEADERS += src/modules/schnorr/main_impl.h
+noinst_HEADERS += src/modules/schnorr/schnorr.h
+noinst_HEADERS += src/modules/schnorr/schnorr_impl.h
+noinst_HEADERS += src/modules/schnorr/tests_impl.h
+if USE_BENCHMARK
+noinst_PROGRAMS += bench_schnorr_verify
+bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
+bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
+endif
diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h
new file mode 100644
index 0000000000..fa176a1767
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorr/main_impl.h
@@ -0,0 +1,164 @@
+/**********************************************************************
+ * Copyright (c) 2014-2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef SECP256K1_MODULE_SCHNORR_MAIN
+#define SECP256K1_MODULE_SCHNORR_MAIN
+
+#include "include/secp256k1_schnorr.h"
+#include "modules/schnorr/schnorr_impl.h"
+
+static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
+ secp256k1_sha256_t sha;
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, r32, 32);
+ secp256k1_sha256_write(&sha, msg32, 32);
+ secp256k1_sha256_finalize(&sha, h32);
+}
+
+static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 ";
+
+int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
+ secp256k1_scalar sec, non;
+ int ret = 0;
+ int overflow = 0;
+ unsigned int count = 0;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(seckey != NULL);
+ if (noncefp == NULL) {
+ noncefp = secp256k1_nonce_function_default;
+ }
+
+ secp256k1_scalar_set_b32(&sec, seckey, NULL);
+ while (1) {
+ unsigned char nonce32[32];
+ ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count);
+ if (!ret) {
+ break;
+ }
+ secp256k1_scalar_set_b32(&non, nonce32, &overflow);
+ memset(nonce32, 0, 32);
+ if (!secp256k1_scalar_is_zero(&non) && !overflow) {
+ if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) {
+ break;
+ }
+ }
+ count++;
+ }
+ if (!ret) {
+ memset(sig64, 0, 64);
+ }
+ secp256k1_scalar_clear(&non);
+ secp256k1_scalar_clear(&sec);
+ return ret;
+}
+
+int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
+ secp256k1_ge q;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ secp256k1_pubkey_load(ctx, &q, pubkey);
+ return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32);
+}
+
+int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) {
+ secp256k1_ge q;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) {
+ secp256k1_pubkey_save(pubkey, &q);
+ return 1;
+ } else {
+ memset(pubkey, 0, sizeof(*pubkey));
+ return 0;
+ }
+}
+
+int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) {
+ int count = 0;
+ int ret = 1;
+ secp256k1_gej Qj;
+ secp256k1_ge Q;
+ secp256k1_scalar sec;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(sec32 != NULL);
+ ARG_CHECK(pubnonce != NULL);
+ ARG_CHECK(privnonce32 != NULL);
+
+ if (noncefp == NULL) {
+ noncefp = secp256k1_nonce_function_default;
+ }
+
+ do {
+ int overflow;
+ ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++);
+ if (!ret) {
+ break;
+ }
+ secp256k1_scalar_set_b32(&sec, privnonce32, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&sec)) {
+ continue;
+ }
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec);
+ secp256k1_ge_set_gej(&Q, &Qj);
+
+ secp256k1_pubkey_save(pubnonce, &Q);
+ break;
+ } while(1);
+
+ secp256k1_scalar_clear(&sec);
+ if (!ret) {
+ memset(pubnonce, 0, sizeof(*pubnonce));
+ }
+ return ret;
+}
+
+int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) {
+ int overflow = 0;
+ secp256k1_scalar sec, non;
+ secp256k1_ge pubnon;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(sec32 != NULL);
+ ARG_CHECK(secnonce32 != NULL);
+ ARG_CHECK(pubnonce_others != NULL);
+
+ secp256k1_scalar_set_b32(&sec, sec32, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&sec)) {
+ return -1;
+ }
+ secp256k1_scalar_set_b32(&non, secnonce32, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&non)) {
+ return -1;
+ }
+ secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others);
+ return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32);
+}
+
+int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) {
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(n >= 1);
+ ARG_CHECK(sig64sin != NULL);
+ return secp256k1_schnorr_sig_combine(sig64, n, sig64sin);
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/schnorr/schnorr.h b/src/secp256k1/src/modules/schnorr/schnorr.h
new file mode 100644
index 0000000000..de18147bd5
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorr/schnorr.h
@@ -0,0 +1,20 @@
+/***********************************************************************
+ * Copyright (c) 2014-2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php. *
+ ***********************************************************************/
+
+#ifndef _SECP256K1_MODULE_SCHNORR_H_
+#define _SECP256K1_MODULE_SCHNORR_H_
+
+#include "scalar.h"
+#include "group.h"
+
+typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32);
+
+static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
+static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
+static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
+static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins);
+
+#endif
diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h
new file mode 100644
index 0000000000..e13ab6db7c
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h
@@ -0,0 +1,207 @@
+/***********************************************************************
+ * Copyright (c) 2014-2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php. *
+ ***********************************************************************/
+
+#ifndef _SECP256K1_SCHNORR_IMPL_H_
+#define _SECP256K1_SCHNORR_IMPL_H_
+
+#include <string.h>
+
+#include "schnorr.h"
+#include "num.h"
+#include "field.h"
+#include "group.h"
+#include "ecmult.h"
+#include "ecmult_gen.h"
+
+/**
+ * Custom Schnorr-based signature scheme. They support multiparty signing, public key
+ * recovery and batch validation.
+ *
+ * Rationale for verifying R's y coordinate:
+ * In order to support batch validation and public key recovery, the full R point must
+ * be known to verifiers, rather than just its x coordinate. In order to not risk
+ * being more strict in batch validation than normal validation, validators must be
+ * required to reject signatures with incorrect y coordinate. This is only possible
+ * by including a (relatively slow) field inverse, or a field square root. However,
+ * batch validation offers potentially much higher benefits than this cost.
+ *
+ * Rationale for having an implicit y coordinate oddness:
+ * If we commit to having the full R point known to verifiers, there are two mechanism.
+ * Either include its oddness in the signature, or give it an implicit fixed value.
+ * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the
+ * latter, as it comes with nearly zero impact on signing or validation performance, and
+ * saves a byte in the signature.
+ *
+ * Signing:
+ * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0)
+ *
+ * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce).
+ * Compute 32-byte r, the serialization of R's x coordinate.
+ * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order.
+ * Compute scalar s = k - h * x.
+ * The signature is (r, s).
+ *
+ *
+ * Verification:
+ * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s)
+ *
+ * Signature is invalid if s >= order.
+ * Signature is invalid if r >= p.
+ * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order.
+ * Option 1 (faster for single verification):
+ * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd.
+ * Signature is valid if the serialization of R's x coordinate equals r.
+ * Option 2 (allows batch validation and pubkey recovery):
+ * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve.
+ * Signature is valid if R + h * Q + s * G == 0.
+ */
+
+static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
+ secp256k1_gej Rj;
+ secp256k1_ge Ra;
+ unsigned char h32[32];
+ secp256k1_scalar h, s;
+ int overflow;
+ secp256k1_scalar n;
+
+ if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) {
+ return 0;
+ }
+ n = *nonce;
+
+ secp256k1_ecmult_gen(ctx, &Rj, &n);
+ if (pubnonce != NULL) {
+ secp256k1_gej_add_ge(&Rj, &Rj, pubnonce);
+ }
+ secp256k1_ge_set_gej(&Ra, &Rj);
+ secp256k1_fe_normalize(&Ra.y);
+ if (secp256k1_fe_is_odd(&Ra.y)) {
+ /* R's y coordinate is odd, which is not allowed (see rationale above).
+ Force it to be even by negating the nonce. Note that this even works
+ for multiparty signing, as the R point is known to all participants,
+ which can all decide to flip the sign in unison, resulting in the
+ overall R point to be negated too. */
+ secp256k1_scalar_negate(&n, &n);
+ }
+ secp256k1_fe_normalize(&Ra.x);
+ secp256k1_fe_get_b32(sig64, &Ra.x);
+ hash(h32, sig64, msg32);
+ overflow = 0;
+ secp256k1_scalar_set_b32(&h, h32, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&h)) {
+ secp256k1_scalar_clear(&n);
+ return 0;
+ }
+ secp256k1_scalar_mul(&s, &h, key);
+ secp256k1_scalar_negate(&s, &s);
+ secp256k1_scalar_add(&s, &s, &n);
+ secp256k1_scalar_clear(&n);
+ secp256k1_scalar_get_b32(sig64 + 32, &s);
+ return 1;
+}
+
+static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
+ secp256k1_gej Qj, Rj;
+ secp256k1_ge Ra;
+ secp256k1_fe Rx;
+ secp256k1_scalar h, s;
+ unsigned char hh[32];
+ int overflow;
+
+ if (secp256k1_ge_is_infinity(pubkey)) {
+ return 0;
+ }
+ hash(hh, sig64, msg32);
+ overflow = 0;
+ secp256k1_scalar_set_b32(&h, hh, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&h)) {
+ return 0;
+ }
+ overflow = 0;
+ secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
+ if (overflow) {
+ return 0;
+ }
+ if (!secp256k1_fe_set_b32(&Rx, sig64)) {
+ return 0;
+ }
+ secp256k1_gej_set_ge(&Qj, pubkey);
+ secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s);
+ if (secp256k1_gej_is_infinity(&Rj)) {
+ return 0;
+ }
+ secp256k1_ge_set_gej_var(&Ra, &Rj);
+ secp256k1_fe_normalize_var(&Ra.y);
+ if (secp256k1_fe_is_odd(&Ra.y)) {
+ return 0;
+ }
+ return secp256k1_fe_equal_var(&Rx, &Ra.x);
+}
+
+static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
+ secp256k1_gej Qj, Rj;
+ secp256k1_ge Ra;
+ secp256k1_fe Rx;
+ secp256k1_scalar h, s;
+ unsigned char hh[32];
+ int overflow;
+
+ hash(hh, sig64, msg32);
+ overflow = 0;
+ secp256k1_scalar_set_b32(&h, hh, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&h)) {
+ return 0;
+ }
+ overflow = 0;
+ secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
+ if (overflow) {
+ return 0;
+ }
+ if (!secp256k1_fe_set_b32(&Rx, sig64)) {
+ return 0;
+ }
+ if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) {
+ return 0;
+ }
+ secp256k1_gej_set_ge(&Rj, &Ra);
+ secp256k1_scalar_inverse_var(&h, &h);
+ secp256k1_scalar_negate(&s, &s);
+ secp256k1_scalar_mul(&s, &s, &h);
+ secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s);
+ if (secp256k1_gej_is_infinity(&Qj)) {
+ return 0;
+ }
+ secp256k1_ge_set_gej(pubkey, &Qj);
+ return 1;
+}
+
+static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) {
+ secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ size_t i;
+ for (i = 0; i < n; i++) {
+ secp256k1_scalar si;
+ int overflow;
+ secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow);
+ if (overflow) {
+ return -1;
+ }
+ if (i) {
+ if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) {
+ return -1;
+ }
+ }
+ secp256k1_scalar_add(&s, &s, &si);
+ }
+ if (secp256k1_scalar_is_zero(&s)) {
+ return 0;
+ }
+ memcpy(sig64, sig64ins[0], 32);
+ secp256k1_scalar_get_b32(sig64 + 32, &s);
+ secp256k1_scalar_clear(&s);
+ return 1;
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h
new file mode 100644
index 0000000000..5bd14a03e3
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorr/tests_impl.h
@@ -0,0 +1,175 @@
+/**********************************************************************
+ * Copyright (c) 2014-2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef SECP256K1_MODULE_SCHNORR_TESTS
+#define SECP256K1_MODULE_SCHNORR_TESTS
+
+#include "include/secp256k1_schnorr.h"
+
+void test_schnorr_end_to_end(void) {
+ unsigned char privkey[32];
+ unsigned char message[32];
+ unsigned char schnorr_signature[64];
+ secp256k1_pubkey pubkey, recpubkey;
+
+ /* Generate a random key and message. */
+ {
+ secp256k1_scalar key;
+ random_scalar_order_test(&key);
+ secp256k1_scalar_get_b32(privkey, &key);
+ secp256k1_rand256_test(message);
+ }
+
+ /* Construct and verify corresponding public key. */
+ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+ /* Schnorr sign. */
+ CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1);
+ CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1);
+ CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
+ /* Destroy signature and verify again. */
+ schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
+ CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0);
+ CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 ||
+ memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
+}
+
+/** Horribly broken hash function. Do not use for anything but tests. */
+void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
+ int i;
+ for (i = 0; i < 32; i++) {
+ h32[i] = r32[i] ^ msg32[i];
+ }
+}
+
+void test_schnorr_sign_verify(void) {
+ unsigned char msg32[32];
+ unsigned char sig64[3][64];
+ secp256k1_gej pubkeyj[3];
+ secp256k1_ge pubkey[3];
+ secp256k1_scalar nonce[3], key[3];
+ int i = 0;
+ int k;
+
+ secp256k1_rand256_test(msg32);
+
+ for (k = 0; k < 3; k++) {
+ random_scalar_order_test(&key[k]);
+
+ do {
+ random_scalar_order_test(&nonce[k]);
+ if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) {
+ break;
+ }
+ } while(1);
+
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]);
+ secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]);
+ CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32));
+
+ for (i = 0; i < 4; i++) {
+ int pos = secp256k1_rand_bits(6);
+ int mod = 1 + secp256k1_rand_int(255);
+ sig64[k][pos] ^= mod;
+ CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0);
+ sig64[k][pos] ^= mod;
+ }
+ }
+}
+
+void test_schnorr_threshold(void) {
+ unsigned char msg[32];
+ unsigned char sec[5][32];
+ secp256k1_pubkey pub[5];
+ unsigned char nonce[5][32];
+ secp256k1_pubkey pubnonce[5];
+ unsigned char sig[5][64];
+ const unsigned char* sigs[5];
+ unsigned char allsig[64];
+ const secp256k1_pubkey* pubs[5];
+ secp256k1_pubkey allpub;
+ int n, i;
+ int damage;
+ int ret = 0;
+
+ damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0;
+ secp256k1_rand256_test(msg);
+ n = 2 + secp256k1_rand_int(4);
+ for (i = 0; i < n; i++) {
+ do {
+ secp256k1_rand256_test(sec[i]);
+ } while (!secp256k1_ec_seckey_verify(ctx, sec[i]));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i]));
+ CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL));
+ pubs[i] = &pub[i];
+ }
+ if (damage == 1) {
+ nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
+ } else if (damage == 2) {
+ sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
+ }
+ for (i = 0; i < n; i++) {
+ secp256k1_pubkey allpubnonce;
+ const secp256k1_pubkey *pubnonces[4];
+ int j;
+ for (j = 0; j < i; j++) {
+ pubnonces[j] = &pubnonce[j];
+ }
+ for (j = i + 1; j < n; j++) {
+ pubnonces[j - 1] = &pubnonce[j];
+ }
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1));
+ ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1;
+ sigs[i] = sig[i];
+ }
+ if (damage == 3) {
+ sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255);
+ }
+ ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2;
+ if ((ret & 1) == 0) {
+ ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4;
+ }
+ if (damage == 4) {
+ allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
+ }
+ if ((ret & 7) == 0) {
+ ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8;
+ }
+ CHECK((ret == 0) == (damage == 0));
+}
+
+void test_schnorr_recovery(void) {
+ unsigned char msg32[32];
+ unsigned char sig64[64];
+ secp256k1_ge Q;
+
+ secp256k1_rand256_test(msg32);
+ secp256k1_rand256_test(sig64);
+ secp256k1_rand256_test(sig64 + 32);
+ if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) {
+ CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1);
+ }
+}
+
+void run_schnorr_tests(void) {
+ int i;
+ for (i = 0; i < 32*count; i++) {
+ test_schnorr_end_to_end();
+ }
+ for (i = 0; i < 32 * count; i++) {
+ test_schnorr_sign_verify();
+ }
+ for (i = 0; i < 16 * count; i++) {
+ test_schnorr_recovery();
+ }
+ for (i = 0; i < 10 * count; i++) {
+ test_schnorr_threshold();
+ }
+}
+
+#endif
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index 339b6bb6ec..ebfa71eb44 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -20,48 +20,48 @@
#endif
/** Copy a number. */
-static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
+static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a);
/** Convert a number's absolute value to a binary big-endian string.
* There must be enough place. */
-static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a);
+static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a);
/** Set a number to the value of a binary big-endian string. */
-static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
+static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen);
/** Compute a modular inverse. The input must be less than the modulus. */
-static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
+static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);
/** Compare the absolute value of two numbers. */
-static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
+static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);
/** Test whether two number are equal (including sign). */
-static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b);
+static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b);
/** Add two (signed) numbers. */
-static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);
/** Subtract two (signed) numbers. */
-static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);
/** Multiply two (signed) numbers. */
-static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
even if r was negative. */
-static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
+static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m);
/** Right-shift the passed number by bits bits. */
-static void secp256k1_num_shift(secp256k1_num_t *r, int bits);
+static void secp256k1_num_shift(secp256k1_num *r, int bits);
/** Check whether a number is zero. */
-static int secp256k1_num_is_zero(const secp256k1_num_t *a);
+static int secp256k1_num_is_zero(const secp256k1_num *a);
/** Check whether a number is strictly negative. */
-static int secp256k1_num_is_neg(const secp256k1_num_t *a);
+static int secp256k1_num_is_neg(const secp256k1_num *a);
/** Change a number's sign. */
-static void secp256k1_num_negate(secp256k1_num_t *r);
+static void secp256k1_num_negate(secp256k1_num *r);
#endif
diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h
index baa1f2bf2e..7dd813088a 100644
--- a/src/secp256k1/src/num_gmp.h
+++ b/src/secp256k1/src/num_gmp.h
@@ -15,6 +15,6 @@ typedef struct {
mp_limb_t data[2*NUM_LIMBS];
int neg;
int limbs;
-} secp256k1_num_t;
+} secp256k1_num;
#endif
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index dbbc458d5d..7b6a89719a 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -15,18 +15,18 @@
#include "num.h"
#ifdef VERIFY
-static void secp256k1_num_sanity(const secp256k1_num_t *a) {
+static void secp256k1_num_sanity(const secp256k1_num *a) {
VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
}
#else
#define secp256k1_num_sanity(a) do { } while(0)
#endif
-static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
+static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) {
*r = *a;
}
-static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
+static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) {
unsigned char tmp[65];
int len = 0;
int shift = 0;
@@ -42,7 +42,7 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec
memset(tmp, 0, sizeof(tmp));
}
-static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
+static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) {
int len;
VERIFY_CHECK(alen > 0);
VERIFY_CHECK(alen <= 64);
@@ -59,7 +59,7 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un
}
}
-static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
r->limbs = a->limbs;
if (c != 0) {
@@ -68,8 +68,9 @@ static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a,
}
}
-static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
+ (void)c;
VERIFY_CHECK(c == 0);
r->limbs = a->limbs;
while (r->limbs > 1 && r->data[r->limbs-1]==0) {
@@ -77,7 +78,7 @@ static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a,
}
}
-static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
+static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) {
secp256k1_num_sanity(r);
secp256k1_num_sanity(m);
@@ -97,7 +98,7 @@ static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
}
}
-static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
+static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) {
int i;
mp_limb_t g[NUM_LIMBS+1];
mp_limb_t u[NUM_LIMBS+1];
@@ -125,6 +126,7 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t
}
sn = NUM_LIMBS+1;
gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
+ (void)gn;
VERIFY_CHECK(gn == 1);
VERIFY_CHECK(g[0] == 1);
r->neg = a->neg ^ m->neg;
@@ -142,15 +144,15 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t
memset(v, 0, sizeof(v));
}
-static int secp256k1_num_is_zero(const secp256k1_num_t *a) {
+static int secp256k1_num_is_zero(const secp256k1_num *a) {
return (a->limbs == 1 && a->data[0] == 0);
}
-static int secp256k1_num_is_neg(const secp256k1_num_t *a) {
+static int secp256k1_num_is_neg(const secp256k1_num *a) {
return (a->limbs > 1 || a->data[0] != 0) && a->neg;
}
-static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) {
if (a->limbs > b->limbs) {
return 1;
}
@@ -160,7 +162,7 @@ static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b)
return mpn_cmp(a->data, b->data, a->limbs);
}
-static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) {
if (a->limbs > b->limbs) {
return 0;
}
@@ -173,7 +175,7 @@ static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b)
return mpn_cmp(a->data, b->data, a->limbs) == 0;
}
-static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
+static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) {
if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */
r->neg = a->neg;
if (a->limbs >= b->limbs) {
@@ -192,19 +194,19 @@ static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, c
}
}
-static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
secp256k1_num_subadd(r, a, b, 0);
}
-static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
secp256k1_num_subadd(r, a, b, 1);
}
-static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
mp_limb_t tmp[2*NUM_LIMBS+1];
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
@@ -231,13 +233,13 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons
memset(tmp, 0, sizeof(tmp));
}
-static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
- int i;
+static void secp256k1_num_shift(secp256k1_num *r, int bits) {
if (bits % GMP_NUMB_BITS) {
/* Shift within limbs. */
mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
}
if (bits >= GMP_NUMB_BITS) {
+ int i;
/* Shift full limbs. */
for (i = 0; i < r->limbs; i++) {
int index = i + (bits / GMP_NUMB_BITS);
@@ -253,7 +255,7 @@ static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
}
}
-static void secp256k1_num_negate(secp256k1_num_t *r) {
+static void secp256k1_num_negate(secp256k1_num *r) {
r->neg ^= 1;
}
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index f5d09f8d47..b590ccd6dd 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -22,72 +22,83 @@
#endif
/** Clear a scalar to prevent the leak of sensitive data. */
-static void secp256k1_scalar_clear(secp256k1_scalar_t *r);
+static void secp256k1_scalar_clear(secp256k1_scalar *r);
/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */
-static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count);
+static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
/** Access bits from a scalar. Not constant time. */
-static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count);
+static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
/** Set a scalar from a big endian byte array. */
-static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow);
+static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow);
/** Set a scalar to an unsigned integer. */
-static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v);
+static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);
/** Convert a scalar to a byte array. */
-static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a);
+static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a);
/** Add two scalars together (modulo the group order). Returns whether it overflowed. */
-static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
+static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);
-/** Add a power of two to a scalar. The result is not allowed to overflow. */
-static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit);
+/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */
+static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag);
/** Multiply two scalars (modulo the group order). */
-static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
+static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);
+
+/** Shift a scalar right by some amount strictly between 0 and 16, returning
+ * the low bits that were shifted off */
+static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);
/** Compute the square of a scalar (modulo the group order). */
-static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Compute the inverse of a scalar (modulo the group order). */
-static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */
-static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Compute the complement of a scalar (modulo the group order). */
-static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Check whether a scalar equals zero. */
-static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a);
+static int secp256k1_scalar_is_zero(const secp256k1_scalar *a);
/** Check whether a scalar equals one. */
-static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a);
+static int secp256k1_scalar_is_one(const secp256k1_scalar *a);
+
+/** Check whether a scalar, considered as an nonnegative integer, is even. */
+static int secp256k1_scalar_is_even(const secp256k1_scalar *a);
/** Check whether a scalar is higher than the group order divided by 2. */
-static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a);
+static int secp256k1_scalar_is_high(const secp256k1_scalar *a);
+
+/** Conditionally negate a number, in constant time.
+ * Returns -1 if the number was negated, 1 otherwise */
+static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag);
#ifndef USE_NUM_NONE
/** Convert a scalar to a number. */
-static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a);
/** Get the order of the group as a number. */
-static void secp256k1_scalar_order_get_num(secp256k1_num_t *r);
+static void secp256k1_scalar_order_get_num(secp256k1_num *r);
#endif
/** Compare two scalars. */
-static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
+static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b);
#ifdef USE_ENDOMORPHISM
/** Find r1 and r2 such that r1+r2*2^128 = a. */
-static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a);
/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */
-static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
+static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a);
#endif
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
-static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift);
+static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
#endif
diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h
index 82899aa7b0..cff406038f 100644
--- a/src/secp256k1/src/scalar_4x64.h
+++ b/src/secp256k1/src/scalar_4x64.h
@@ -12,7 +12,7 @@
/** A scalar modulo the group order of the secp256k1 curve. */
typedef struct {
uint64_t d[4];
-} secp256k1_scalar_t;
+} secp256k1_scalar;
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index ff365292f8..aa2703dd23 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -24,26 +24,26 @@
#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL)
-SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
+SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
r->d[0] = 0;
r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
}
-SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) {
+SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
r->d[0] = v;
r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
}
-SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
}
-SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
if ((offset + count - 1) >> 6 == offset >> 6) {
@@ -54,7 +54,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256
}
}
-SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) {
+SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */
@@ -66,7 +66,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
return yes;
}
-SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) {
+SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) {
uint128_t t;
VERIFY_CHECK(overflow <= 1);
t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0;
@@ -80,7 +80,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig
return overflow;
}
-static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
uint128_t t = (uint128_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
@@ -96,9 +96,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
return overflow;
}
-static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
+static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint128_t t;
VERIFY_CHECK(bit < 256);
+ bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
@@ -113,7 +114,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
#endif
}
-static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
+static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56;
r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56;
@@ -125,18 +126,18 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char
}
}
-static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) {
+static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3];
bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2];
bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1];
bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
}
-SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) {
+SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0;
}
-static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0);
uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1;
r->d[0] = t & nonzero; t >>= 64;
@@ -148,11 +149,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala
r->d[3] = t & nonzero;
}
-SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) {
+SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0;
}
-static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
+static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
no |= (a->d[3] < SECP256K1_N_H_3);
@@ -164,6 +165,22 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
return yes;
}
+static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
+ /* If we are flag = 0, mask = 00...00 and this is a no-op;
+ * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
+ uint64_t mask = !flag - 1;
+ uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
+ uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
+ r->d[0] = t & nonzero; t >>= 64;
+ t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
+ r->d[1] = t & nonzero; t >>= 64;
+ t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);
+ r->d[2] = t & nonzero; t >>= 64;
+ t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);
+ r->d[3] = t & nonzero;
+ return 2 * (mask == 0) - 1;
+}
+
/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */
/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
@@ -250,7 +267,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
VERIFY_CHECK(c2 == 0); \
}
-static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) {
+static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) {
#ifdef USE_ASM_X86_64
/* Reduce 512 bits into 385. */
uint64_t m0, m1, m2, m3, m4, m5, m6;
@@ -559,7 +576,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
-static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) {
#ifdef USE_ASM_X86_64
const uint64_t *pb = b->d;
__asm__ __volatile__(
@@ -721,12 +738,12 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a,
extract(l[5]);
muladd_fast(a->d[3], b->d[3]);
extract_fast(l[6]);
- VERIFY_CHECK(c1 <= 0);
+ VERIFY_CHECK(c1 == 0);
l[7] = c0;
#endif
}
-static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) {
#ifdef USE_ASM_X86_64
__asm__ __volatile__(
/* Preload */
@@ -871,19 +888,32 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a)
#undef extract
#undef extract_fast
-static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
uint64_t l[8];
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
}
-static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
+ int ret;
+ VERIFY_CHECK(n > 0);
+ VERIFY_CHECK(n < 16);
+ ret = r->d[0] & ((1 << n) - 1);
+ r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n));
+ r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n));
+ r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n));
+ r->d[3] = (r->d[3] >> n);
+ return ret;
+}
+
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint64_t l[8];
secp256k1_scalar_sqr_512(l, a);
secp256k1_scalar_reduce_512(r, l);
}
-static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
+#ifdef USE_ENDOMORPHISM
+static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
r1->d[0] = a->d[0];
r1->d[1] = a->d[1];
r1->d[2] = 0;
@@ -893,12 +923,13 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_
r2->d[2] = 0;
r2->d[3] = 0;
}
+#endif
-SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0;
}
-SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
+SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) {
uint64_t l[8];
unsigned int shiftlimbs;
unsigned int shiftlow;
@@ -912,9 +943,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *
r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0;
- if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) {
- secp256k1_scalar_add_bit(r, 0);
- }
+ secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);
}
#endif
diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h
index f17017e24e..1319664f65 100644
--- a/src/secp256k1/src/scalar_8x32.h
+++ b/src/secp256k1/src/scalar_8x32.h
@@ -12,7 +12,7 @@
/** A scalar modulo the group order of the secp256k1 curve. */
typedef struct {
uint32_t d[8];
-} secp256k1_scalar_t;
+} secp256k1_scalar;
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index 22b31d4112..aae4f35c08 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -34,7 +34,7 @@
#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL)
#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL)
-SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
+SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
r->d[0] = 0;
r->d[1] = 0;
r->d[2] = 0;
@@ -45,7 +45,7 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
r->d[7] = 0;
}
-SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) {
+SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
r->d[0] = v;
r->d[1] = 0;
r->d[2] = 0;
@@ -56,12 +56,12 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, uns
r->d[7] = 0;
}
-SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
}
-SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
if ((offset + count - 1) >> 5 == offset >> 5) {
@@ -72,7 +72,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256
}
}
-SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) {
+SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */
@@ -90,7 +90,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
return yes;
}
-SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) {
+SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) {
uint64_t t;
VERIFY_CHECK(overflow <= 1);
t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0;
@@ -112,7 +112,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3
return overflow;
}
-static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
uint64_t t = (uint64_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
@@ -136,9 +136,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
return overflow;
}
-static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
+static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint64_t t;
VERIFY_CHECK(bit < 256);
+ bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
@@ -161,7 +162,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
#endif
}
-static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
+static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;
r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;
@@ -177,7 +178,7 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char
}
}
-static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) {
+static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7];
bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6];
bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5];
@@ -188,11 +189,11 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_
bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
}
-SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) {
+SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
}
-static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0);
uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1;
r->d[0] = t & nonzero; t >>= 32;
@@ -212,11 +213,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala
r->d[7] = t & nonzero;
}
-SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) {
+SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
}
-static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
+static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
no |= (a->d[7] < SECP256K1_N_H_7);
@@ -234,6 +235,31 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
return yes;
}
+static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
+ /* If we are flag = 0, mask = 00...00 and this is a no-op;
+ * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
+ uint32_t mask = !flag - 1;
+ uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
+ uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
+ r->d[0] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
+ r->d[1] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);
+ r->d[2] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);
+ r->d[3] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask);
+ r->d[4] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask);
+ r->d[5] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask);
+ r->d[6] = t & nonzero; t >>= 32;
+ t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask);
+ r->d[7] = t & nonzero;
+ return 2 * (mask == 0) - 1;
+}
+
+
/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */
/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
@@ -320,7 +346,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
VERIFY_CHECK(c2 == 0); \
}
-static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) {
+static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) {
uint64_t c;
uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15];
uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12;
@@ -462,7 +488,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
-static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
@@ -550,7 +576,7 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, c
l[15] = c0;
}
-static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
@@ -618,20 +644,36 @@ static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) {
#undef extract
#undef extract_fast
-static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
uint32_t l[16];
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
}
-static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
+static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
+ int ret;
+ VERIFY_CHECK(n > 0);
+ VERIFY_CHECK(n < 16);
+ ret = r->d[0] & ((1 << n) - 1);
+ r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n));
+ r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n));
+ r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n));
+ r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n));
+ r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n));
+ r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n));
+ r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n));
+ r->d[7] = (r->d[7] >> n);
+ return ret;
+}
+
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint32_t l[16];
secp256k1_scalar_sqr_512(l, a);
secp256k1_scalar_reduce_512(r, l);
}
#ifdef USE_ENDOMORPHISM
-static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
r1->d[0] = a->d[0];
r1->d[1] = a->d[1];
r1->d[2] = a->d[2];
@@ -651,11 +693,11 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_
}
#endif
-SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
}
-SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
+SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) {
uint32_t l[16];
unsigned int shiftlimbs;
unsigned int shiftlow;
@@ -673,9 +715,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *
r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0;
- if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) {
- secp256k1_scalar_add_bit(r, 0);
- }
+ secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
}
#endif
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 33824983e4..88ea97de86 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -25,14 +25,14 @@
#endif
#ifndef USE_NUM_NONE
-static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) {
unsigned char c[32];
secp256k1_scalar_get_b32(c, a);
secp256k1_num_set_bin(r, c, 32);
}
/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */
-static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) {
+static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
static const unsigned char order[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
@@ -43,11 +43,11 @@ static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) {
}
#endif
-static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
- secp256k1_scalar_t *t;
+static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
+ secp256k1_scalar *t;
int i;
/* First compute x ^ (2^N - 1) for some values of N. */
- secp256k1_scalar_t x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127;
+ secp256k1_scalar x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127;
secp256k1_scalar_sqr(&x2, x);
secp256k1_scalar_mul(&x2, &x2, x);
@@ -234,18 +234,27 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal
secp256k1_scalar_mul(r, t, &x6); /* 111111 */
}
-static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
+SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
+ /* d[0] is present and is the lowest word for all representations */
+ return !(a->d[0] & 1);
+}
+
+static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
#if defined(USE_SCALAR_INV_BUILTIN)
secp256k1_scalar_inverse(r, x);
#elif defined(USE_SCALAR_INV_NUM)
unsigned char b[32];
- secp256k1_num_t n, m;
- secp256k1_scalar_get_b32(b, x);
+ secp256k1_num n, m;
+ secp256k1_scalar t = *x;
+ secp256k1_scalar_get_b32(b, &t);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_scalar_order_get_num(&m);
secp256k1_num_mod_inverse(&n, &n, &m);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_scalar_set_b32(r, b, NULL);
+ /* Verify that the inverse was computed correctly, without GMP code. */
+ secp256k1_scalar_mul(&t, &t, r);
+ CHECK(secp256k1_scalar_is_one(&t));
#else
#error "Please select scalar inverse implementation"
#endif
@@ -290,30 +299,31 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_
* The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order).
*/
-static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
- secp256k1_scalar_t c1, c2;
- static const secp256k1_scalar_t minus_lambda = SECP256K1_SCALAR_CONST(
+static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
+ secp256k1_scalar c1, c2;
+ static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST(
0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL,
0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL
);
- static const secp256k1_scalar_t minus_b1 = SECP256K1_SCALAR_CONST(
+ static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL,
0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL
);
- static const secp256k1_scalar_t minus_b2 = SECP256K1_SCALAR_CONST(
+ static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL
);
- static const secp256k1_scalar_t g1 = SECP256K1_SCALAR_CONST(
+ static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL,
0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL
);
- static const secp256k1_scalar_t g2 = SECP256K1_SCALAR_CONST(
+ static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL,
0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL
);
VERIFY_CHECK(r1 != a);
VERIFY_CHECK(r2 != a);
+ /* these _var calls are constant time since the shift amount is constant */
secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272);
secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272);
secp256k1_scalar_mul(&c1, &c1, &minus_b1);
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index d6192dc4ed..62d192baeb 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -14,150 +14,348 @@
#include "scalar_impl.h"
#include "group_impl.h"
#include "ecmult_impl.h"
+#include "ecmult_const_impl.h"
#include "ecmult_gen_impl.h"
#include "ecdsa_impl.h"
#include "eckey_impl.h"
#include "hash_impl.h"
+#define ARG_CHECK(cond) do { \
+ if (EXPECT(!(cond), 0)) { \
+ secp256k1_callback_call(&ctx->illegal_callback, #cond); \
+ return 0; \
+ } \
+} while(0)
+
+static void default_illegal_callback_fn(const char* str, void* data) {
+ (void)data;
+ fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
+ abort();
+}
+
+static const secp256k1_callback default_illegal_callback = {
+ default_illegal_callback_fn,
+ NULL
+};
+
+static void default_error_callback_fn(const char* str, void* data) {
+ (void)data;
+ fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
+ abort();
+}
+
+static const secp256k1_callback default_error_callback = {
+ default_error_callback_fn,
+ NULL
+};
+
+
struct secp256k1_context_struct {
- secp256k1_ecmult_context_t ecmult_ctx;
- secp256k1_ecmult_gen_context_t ecmult_gen_ctx;
+ secp256k1_ecmult_context ecmult_ctx;
+ secp256k1_ecmult_gen_context ecmult_gen_ctx;
+ secp256k1_callback illegal_callback;
+ secp256k1_callback error_callback;
};
-secp256k1_context_t* secp256k1_context_create(int flags) {
- secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t));
+secp256k1_context* secp256k1_context_create(unsigned int flags) {
+ secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
+ ret->illegal_callback = default_illegal_callback;
+ ret->error_callback = default_error_callback;
+
+ if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
+ secp256k1_callback_call(&ret->illegal_callback,
+ "Invalid flags");
+ free(ret);
+ return NULL;
+ }
secp256k1_ecmult_context_init(&ret->ecmult_ctx);
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
- if (flags & SECP256K1_CONTEXT_SIGN) {
- secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx);
+ if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
+ secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback);
}
- if (flags & SECP256K1_CONTEXT_VERIFY) {
- secp256k1_ecmult_context_build(&ret->ecmult_ctx);
+ if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
+ secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback);
}
return ret;
}
-secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) {
- secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t));
- secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx);
- secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx);
+secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
+ secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context));
+ ret->illegal_callback = ctx->illegal_callback;
+ ret->error_callback = ctx->error_callback;
+ secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback);
+ secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback);
return ret;
}
-void secp256k1_context_destroy(secp256k1_context_t* ctx) {
- secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
- secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
+void secp256k1_context_destroy(secp256k1_context* ctx) {
+ if (ctx != NULL) {
+ secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
+ secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
- free(ctx);
+ free(ctx);
+ }
}
-int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) {
- secp256k1_ge_t q;
- secp256k1_ecdsa_sig_t s;
- secp256k1_scalar_t m;
- int ret = -3;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
- DEBUG_CHECK(msg32 != NULL);
- DEBUG_CHECK(sig != NULL);
- DEBUG_CHECK(pubkey != NULL);
+void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
+ if (fun == NULL) {
+ fun = default_illegal_callback_fn;
+ }
+ ctx->illegal_callback.fn = fun;
+ ctx->illegal_callback.data = data;
+}
- secp256k1_scalar_set_b32(&m, msg32, NULL);
+void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
+ if (fun == NULL) {
+ fun = default_error_callback_fn;
+ }
+ ctx->error_callback.fn = fun;
+ ctx->error_callback.data = data;
+}
- if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) {
- if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
- if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) {
- /* success is 1, all other values are fail */
- ret = 1;
- } else {
- ret = 0;
- }
- } else {
- ret = -2;
- }
+static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
+ if (sizeof(secp256k1_ge_storage) == 64) {
+ /* When the secp256k1_ge_storage type is exactly 64 byte, use its
+ * representation inside secp256k1_pubkey, as conversion is very fast.
+ * Note that secp256k1_pubkey_save must use the same representation. */
+ secp256k1_ge_storage s;
+ memcpy(&s, &pubkey->data[0], 64);
+ secp256k1_ge_from_storage(ge, &s);
+ } else {
+ /* Otherwise, fall back to 32-byte big endian for X and Y. */
+ secp256k1_fe x, y;
+ secp256k1_fe_set_b32(&x, pubkey->data);
+ secp256k1_fe_set_b32(&y, pubkey->data + 32);
+ secp256k1_ge_set_xy(ge, &x, &y);
+ }
+ ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
+ return 1;
+}
+
+static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
+ if (sizeof(secp256k1_ge_storage) == 64) {
+ secp256k1_ge_storage s;
+ secp256k1_ge_to_storage(&s, ge);
+ memcpy(&pubkey->data[0], &s, 64);
} else {
- ret = -1;
+ VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
+ secp256k1_fe_normalize_var(&ge->x);
+ secp256k1_fe_normalize_var(&ge->y);
+ secp256k1_fe_get_b32(pubkey->data, &ge->x);
+ secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);
}
+}
+
+int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
+ secp256k1_ge Q;
+
+ (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ memset(pubkey, 0, sizeof(*pubkey));
+ ARG_CHECK(input != NULL);
+ if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) {
+ return 0;
+ }
+ secp256k1_pubkey_save(pubkey, &Q);
+ secp256k1_ge_clear(&Q);
+ return 1;
+}
+
+int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) {
+ secp256k1_ge Q;
+ size_t len;
+ int ret = 0;
+ (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(outputlen != NULL);
+ ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
+ len = *outputlen;
+ *outputlen = 0;
+ ARG_CHECK(output != NULL);
+ memset(output, 0, len);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);
+ if (secp256k1_pubkey_load(ctx, &Q, pubkey)) {
+ ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION);
+ if (ret) {
+ *outputlen = len;
+ }
+ }
return ret;
}
-static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
- secp256k1_rfc6979_hmac_sha256_t rng;
- unsigned int i;
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0);
- for (i = 0; i <= counter; i++) {
- secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
- }
- secp256k1_rfc6979_hmac_sha256_finalize(&rng);
- return 1;
+static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) {
+ (void)ctx;
+ if (sizeof(secp256k1_scalar) == 32) {
+ /* When the secp256k1_scalar type is exactly 32 byte, use its
+ * representation inside secp256k1_ecdsa_signature, as conversion is very fast.
+ * Note that secp256k1_ecdsa_signature_save must use the same representation. */
+ memcpy(r, &sig->data[0], 32);
+ memcpy(s, &sig->data[32], 32);
+ } else {
+ secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
+ secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
+ }
}
-const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
-const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979;
+static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) {
+ if (sizeof(secp256k1_scalar) == 32) {
+ memcpy(&sig->data[0], r, 32);
+ memcpy(&sig->data[32], s, 32);
+ } else {
+ secp256k1_scalar_get_b32(&sig->data[0], r);
+ secp256k1_scalar_get_b32(&sig->data[32], s);
+ }
+}
-int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
- secp256k1_ecdsa_sig_t sig;
- secp256k1_scalar_t sec, non, msg;
- int ret = 0;
+int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
+ secp256k1_scalar r, s;
+
+ (void)ctx;
+ ARG_CHECK(sig != NULL);
+ ARG_CHECK(input != NULL);
+
+ if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) {
+ secp256k1_ecdsa_signature_save(sig, &r, &s);
+ return 1;
+ } else {
+ memset(sig, 0, sizeof(*sig));
+ return 0;
+ }
+}
+
+int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) {
+ secp256k1_scalar r, s;
+ int ret = 1;
int overflow = 0;
- unsigned int count = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- DEBUG_CHECK(msg32 != NULL);
- DEBUG_CHECK(signature != NULL);
- DEBUG_CHECK(signaturelen != NULL);
- DEBUG_CHECK(seckey != NULL);
- if (noncefp == NULL) {
- noncefp = secp256k1_nonce_function_default;
+
+ (void)ctx;
+ ARG_CHECK(sig != NULL);
+ ARG_CHECK(input64 != NULL);
+
+ secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
+ ret &= !overflow;
+ secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
+ ret &= !overflow;
+ if (ret) {
+ secp256k1_ecdsa_signature_save(sig, &r, &s);
+ } else {
+ memset(sig, 0, sizeof(*sig));
}
+ return ret;
+}
- secp256k1_scalar_set_b32(&sec, seckey, &overflow);
- /* Fail if the secret key is invalid. */
- if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
- secp256k1_scalar_set_b32(&msg, msg32, NULL);
- while (1) {
- unsigned char nonce32[32];
- ret = noncefp(nonce32, msg32, seckey, count, noncedata);
- if (!ret) {
- break;
- }
- secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- memset(nonce32, 0, 32);
- if (!secp256k1_scalar_is_zero(&non) && !overflow) {
- if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) {
- break;
- }
- }
- count++;
- }
+int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
+ secp256k1_scalar r, s;
+
+ (void)ctx;
+ ARG_CHECK(output != NULL);
+ ARG_CHECK(outputlen != NULL);
+ ARG_CHECK(sig != NULL);
+
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
+ return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s);
+}
+
+int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
+ secp256k1_scalar r, s;
+
+ (void)ctx;
+ ARG_CHECK(output64 != NULL);
+ ARG_CHECK(sig != NULL);
+
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
+ secp256k1_scalar_get_b32(&output64[0], &r);
+ secp256k1_scalar_get_b32(&output64[32], &s);
+ return 1;
+}
+
+int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) {
+ secp256k1_scalar r, s;
+ int ret = 0;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(sigin != NULL);
+
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin);
+ ret = secp256k1_scalar_is_high(&s);
+ if (sigout != NULL) {
if (ret) {
- ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
+ secp256k1_scalar_negate(&s, &s);
}
- secp256k1_scalar_clear(&msg);
- secp256k1_scalar_clear(&non);
- secp256k1_scalar_clear(&sec);
- }
- if (!ret) {
- *signaturelen = 0;
+ secp256k1_ecdsa_signature_save(sigout, &r, &s);
}
+
return ret;
}
-int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) {
- secp256k1_ecdsa_sig_t sig;
- secp256k1_scalar_t sec, non, msg;
+int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
+ secp256k1_ge q;
+ secp256k1_scalar r, s;
+ secp256k1_scalar m;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(sig != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ secp256k1_scalar_set_b32(&m, msg32, NULL);
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
+ return (!secp256k1_scalar_is_high(&s) &&
+ secp256k1_pubkey_load(ctx, &q, pubkey) &&
+ secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m));
+}
+
+static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
+ unsigned char keydata[112];
+ int keylen = 64;
+ secp256k1_rfc6979_hmac_sha256_t rng;
+ unsigned int i;
+ /* We feed a byte array to the PRNG as input, consisting of:
+ * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
+ * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
+ * - optionally 16 extra bytes with the algorithm name.
+ * Because the arguments have distinct fixed lengths it is not possible for
+ * different argument mixtures to emulate each other and result in the same
+ * nonces.
+ */
+ memcpy(keydata, key32, 32);
+ memcpy(keydata + 32, msg32, 32);
+ if (data != NULL) {
+ memcpy(keydata + 64, data, 32);
+ keylen = 96;
+ }
+ if (algo16 != NULL) {
+ memcpy(keydata + keylen, algo16, 16);
+ keylen += 16;
+ }
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen);
+ memset(keydata, 0, sizeof(keydata));
+ for (i = 0; i <= counter; i++) {
+ secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
+ }
+ secp256k1_rfc6979_hmac_sha256_finalize(&rng);
+ return 1;
+}
+
+const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
+const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
+
+int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
+ secp256k1_scalar r, s;
+ secp256k1_scalar sec, non, msg;
int ret = 0;
int overflow = 0;
- unsigned int count = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- DEBUG_CHECK(msg32 != NULL);
- DEBUG_CHECK(sig64 != NULL);
- DEBUG_CHECK(seckey != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(signature != NULL);
+ ARG_CHECK(seckey != NULL);
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default;
}
@@ -165,139 +363,87 @@ int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
+ unsigned int count = 0;
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
unsigned char nonce32[32];
- ret = noncefp(nonce32, msg32, seckey, count, noncedata);
+ ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
if (!ret) {
break;
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
memset(nonce32, 0, 32);
- if (!secp256k1_scalar_is_zero(&non) && !overflow) {
- if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) {
+ if (!overflow && !secp256k1_scalar_is_zero(&non)) {
+ if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
break;
}
}
count++;
}
- if (ret) {
- secp256k1_scalar_get_b32(sig64, &sig.r);
- secp256k1_scalar_get_b32(sig64 + 32, &sig.s);
- }
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
}
- if (!ret) {
- memset(sig64, 0, 64);
- }
- return ret;
-}
-
-int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) {
- secp256k1_ge_t q;
- secp256k1_ecdsa_sig_t sig;
- secp256k1_scalar_t m;
- int ret = 0;
- int overflow = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
- DEBUG_CHECK(msg32 != NULL);
- DEBUG_CHECK(sig64 != NULL);
- DEBUG_CHECK(pubkey != NULL);
- DEBUG_CHECK(pubkeylen != NULL);
- DEBUG_CHECK(recid >= 0 && recid <= 3);
-
- secp256k1_scalar_set_b32(&sig.r, sig64, &overflow);
- if (!overflow) {
- secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow);
- if (!overflow) {
- secp256k1_scalar_set_b32(&m, msg32, NULL);
-
- if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) {
- ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
- }
- }
+ if (ret) {
+ secp256k1_ecdsa_signature_save(signature, &r, &s);
+ } else {
+ memset(signature, 0, sizeof(*signature));
}
return ret;
}
-int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) {
- secp256k1_scalar_t sec;
+int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) {
+ secp256k1_scalar sec;
int ret;
int overflow;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(seckey != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(seckey != NULL);
(void)ctx;
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
- ret = !secp256k1_scalar_is_zero(&sec) && !overflow;
+ ret = !overflow && !secp256k1_scalar_is_zero(&sec);
secp256k1_scalar_clear(&sec);
return ret;
}
-int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) {
- secp256k1_ge_t q;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(pubkey != NULL);
- (void)ctx;
-
- return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen);
-}
-
-int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
- secp256k1_gej_t pj;
- secp256k1_ge_t p;
- secp256k1_scalar_t sec;
+int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
+ secp256k1_gej pj;
+ secp256k1_ge p;
+ secp256k1_scalar sec;
int overflow;
int ret = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- DEBUG_CHECK(pubkey != NULL);
- DEBUG_CHECK(pubkeylen != NULL);
- DEBUG_CHECK(seckey != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ memset(pubkey, 0, sizeof(*pubkey));
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(seckey != NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
- if (!overflow) {
+ ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec));
+ if (ret) {
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
- secp256k1_scalar_clear(&sec);
secp256k1_ge_set_gej(&p, &pj);
- ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
- }
- if (!ret) {
- *pubkeylen = 0;
- }
- return ret;
-}
-
-int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) {
- secp256k1_ge_t p;
- int ret = 0;
- DEBUG_CHECK(pubkey != NULL);
- DEBUG_CHECK(pubkeylen != NULL);
- (void)ctx;
-
- if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) {
- ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0);
+ secp256k1_pubkey_save(pubkey, &p);
}
+ secp256k1_scalar_clear(&sec);
return ret;
}
-int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) {
- secp256k1_scalar_t term;
- secp256k1_scalar_t sec;
+int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+ secp256k1_scalar term;
+ secp256k1_scalar sec;
int ret = 0;
int overflow = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(seckey != NULL);
- DEBUG_CHECK(tweak != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(seckey != NULL);
+ ARG_CHECK(tweak != NULL);
(void)ctx;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
- ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow;
+ ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term);
+ memset(seckey, 0, 32);
if (ret) {
secp256k1_scalar_get_b32(seckey, &sec);
}
@@ -307,45 +453,44 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char
return ret;
}
-int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
- secp256k1_ge_t p;
- secp256k1_scalar_t term;
+int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
+ secp256k1_ge p;
+ secp256k1_scalar term;
int ret = 0;
int overflow = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
- DEBUG_CHECK(pubkey != NULL);
- DEBUG_CHECK(tweak != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(tweak != NULL);
secp256k1_scalar_set_b32(&term, tweak, &overflow);
- if (!overflow) {
- ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
- if (ret) {
- ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term);
- }
- if (ret) {
- int oldlen = pubkeylen;
- ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
- VERIFY_CHECK(pubkeylen == oldlen);
+ ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
+ memset(pubkey, 0, sizeof(*pubkey));
+ if (ret) {
+ if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) {
+ secp256k1_pubkey_save(pubkey, &p);
+ } else {
+ ret = 0;
}
}
return ret;
}
-int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) {
- secp256k1_scalar_t factor;
- secp256k1_scalar_t sec;
+int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+ secp256k1_scalar factor;
+ secp256k1_scalar sec;
int ret = 0;
int overflow = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(seckey != NULL);
- DEBUG_CHECK(tweak != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(seckey != NULL);
+ ARG_CHECK(tweak != NULL);
(void)ctx;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
- ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow;
+ ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
+ memset(seckey, 0, 32);
if (ret) {
secp256k1_scalar_get_b32(seckey, &sec);
}
@@ -355,65 +500,69 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char
return ret;
}
-int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
- secp256k1_ge_t p;
- secp256k1_scalar_t factor;
+int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
+ secp256k1_ge p;
+ secp256k1_scalar factor;
int ret = 0;
int overflow = 0;
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
- DEBUG_CHECK(pubkey != NULL);
- DEBUG_CHECK(tweak != NULL);
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(tweak != NULL);
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
- if (!overflow) {
- ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
- if (ret) {
- ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor);
- }
- if (ret) {
- int oldlen = pubkeylen;
- ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
- VERIFY_CHECK(pubkeylen == oldlen);
+ ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
+ memset(pubkey, 0, sizeof(*pubkey));
+ if (ret) {
+ if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) {
+ secp256k1_pubkey_save(pubkey, &p);
+ } else {
+ ret = 0;
}
}
return ret;
}
-int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) {
- secp256k1_scalar_t key;
- int ret = 0;
- DEBUG_CHECK(seckey != NULL);
- DEBUG_CHECK(privkey != NULL);
- DEBUG_CHECK(privkeylen != NULL);
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
-
- secp256k1_scalar_set_b32(&key, seckey, NULL);
- ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed);
- secp256k1_scalar_clear(&key);
- return ret;
+int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
+ return 1;
}
-int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) {
- secp256k1_scalar_t key;
- int ret = 0;
- DEBUG_CHECK(seckey != NULL);
- DEBUG_CHECK(privkey != NULL);
- (void)ctx;
+int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) {
+ size_t i;
+ secp256k1_gej Qj;
+ secp256k1_ge Q;
- ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen);
- if (ret) {
- secp256k1_scalar_get_b32(seckey, &key);
- }
- secp256k1_scalar_clear(&key);
- return ret;
-}
+ ARG_CHECK(pubnonce != NULL);
+ memset(pubnonce, 0, sizeof(*pubnonce));
+ ARG_CHECK(n >= 1);
+ ARG_CHECK(pubnonces != NULL);
-int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) {
- DEBUG_CHECK(ctx != NULL);
- DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
+ secp256k1_gej_set_infinity(&Qj);
+
+ for (i = 0; i < n; i++) {
+ secp256k1_pubkey_load(ctx, &Q, pubnonces[i]);
+ secp256k1_gej_add_ge(&Qj, &Qj, &Q);
+ }
+ if (secp256k1_gej_is_infinity(&Qj)) {
+ return 0;
+ }
+ secp256k1_ge_set_gej(&Q, &Qj);
+ secp256k1_pubkey_save(pubnonce, &Q);
return 1;
}
+
+#ifdef ENABLE_MODULE_ECDH
+# include "modules/ecdh/main_impl.h"
+#endif
+
+#ifdef ENABLE_MODULE_SCHNORR
+# include "modules/schnorr/main_impl.h"
+#endif
+
+#ifdef ENABLE_MODULE_RECOVERY
+# include "modules/recovery/main_impl.h"
+#endif
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index 041bb92c47..f8efa93c7c 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -16,13 +16,23 @@
/** Seed the pseudorandom number generator for testing. */
SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16);
-/** Generate a pseudorandom 32-bit number. */
+/** Generate a pseudorandom number in the range [0..2**32-1]. */
static uint32_t secp256k1_rand32(void);
+/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or
+ * more. */
+static uint32_t secp256k1_rand_bits(int bits);
+
+/** Generate a pseudorandom number in the range [0..range-1]. */
+static uint32_t secp256k1_rand_int(uint32_t range);
+
/** Generate a pseudorandom 32-byte array. */
static void secp256k1_rand256(unsigned char *b32);
/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */
static void secp256k1_rand256_test(unsigned char *b32);
+/** Generate pseudorandom bytes with long sequences of zero and one bits. */
+static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);
+
#endif
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index 21c69f1c51..15c7b9f12d 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -1,5 +1,5 @@
/**********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
+ * Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
@@ -16,9 +16,11 @@
static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng;
static uint32_t secp256k1_test_rng_precomputed[8];
static int secp256k1_test_rng_precomputed_used = 8;
+static uint64_t secp256k1_test_rng_integer;
+static int secp256k1_test_rng_integer_bits_left = 0;
SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) {
- secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, (const unsigned char*)"TestRNG", 7, seed16, 16, NULL, 0);
+ secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16);
}
SECP256K1_INLINE static uint32_t secp256k1_rand32(void) {
@@ -29,32 +31,80 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) {
return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++];
}
+static uint32_t secp256k1_rand_bits(int bits) {
+ uint32_t ret;
+ if (secp256k1_test_rng_integer_bits_left < bits) {
+ secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left);
+ secp256k1_test_rng_integer_bits_left += 32;
+ }
+ ret = secp256k1_test_rng_integer;
+ secp256k1_test_rng_integer >>= bits;
+ secp256k1_test_rng_integer_bits_left -= bits;
+ ret &= ((~((uint32_t)0)) >> (32 - bits));
+ return ret;
+}
+
+static uint32_t secp256k1_rand_int(uint32_t range) {
+ /* We want a uniform integer between 0 and range-1, inclusive.
+ * B is the smallest number such that range <= 2**B.
+ * two mechanisms implemented here:
+ * - generate B bits numbers until one below range is found, and return it
+ * - find the largest multiple M of range that is <= 2**(B+A), generate B+A
+ * bits numbers until one below M is found, and return it modulo range
+ * The second mechanism consumes A more bits of entropy in every iteration,
+ * but may need fewer iterations due to M being closer to 2**(B+A) then
+ * range is to 2**B. The array below (indexed by B) contains a 0 when the
+ * first mechanism is to be used, and the number A otherwise.
+ */
+ static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0};
+ uint32_t trange, mult;
+ int bits = 0;
+ if (range <= 1) {
+ return 0;
+ }
+ trange = range - 1;
+ while (trange > 0) {
+ trange >>= 1;
+ bits++;
+ }
+ if (addbits[bits]) {
+ bits = bits + addbits[bits];
+ mult = ((~((uint32_t)0)) >> (32 - bits)) / range;
+ trange = range * mult;
+ } else {
+ trange = range;
+ mult = 1;
+ }
+ while(1) {
+ uint32_t x = secp256k1_rand_bits(bits);
+ if (x < trange) {
+ return (mult == 1) ? x : (x % range);
+ }
+ }
+}
+
static void secp256k1_rand256(unsigned char *b32) {
secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32);
}
-static void secp256k1_rand256_test(unsigned char *b32) {
- int bits=0;
- uint64_t ent = 0;
- int entleft = 0;
- memset(b32, 0, 32);
- while (bits < 256) {
+static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) {
+ size_t bits = 0;
+ memset(bytes, 0, len);
+ while (bits < len * 8) {
int now;
uint32_t val;
- if (entleft < 12) {
- ent |= ((uint64_t)secp256k1_rand32()) << entleft;
- entleft += 32;
- }
- now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31;
- val = 1 & (ent >> 11);
- ent >>= 12;
- entleft -= 12;
- while (now > 0 && bits < 256) {
- b32[bits / 8] |= val << (bits % 8);
+ now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31;
+ val = secp256k1_rand_bits(1);
+ while (now > 0 && bits < len * 8) {
+ bytes[bits / 8] |= val << (bits % 8);
now--;
bits++;
}
}
}
+static void secp256k1_rand256_test(unsigned char *b32) {
+ secp256k1_rand_bytes_test(b32, 32);
+}
+
#endif
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index d0e05057f2..687a5f2fdd 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -14,6 +14,7 @@
#include <time.h>
#include "secp256k1.c"
+#include "include/secp256k1.h"
#include "testrand_impl.h"
#ifdef ENABLE_OPENSSL_TESTS
@@ -23,10 +24,40 @@
#include "openssl/obj_mac.h"
#endif
+#include "contrib/lax_der_parsing.c"
+#include "contrib/lax_der_privatekey_parsing.c"
+
+#if !defined(VG_CHECK)
+# if defined(VALGRIND)
+# include <valgrind/memcheck.h>
+# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
+# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
+# else
+# define VG_UNDEF(x,y)
+# define VG_CHECK(x,y)
+# endif
+#endif
+
static int count = 64;
-static secp256k1_context_t *ctx = NULL;
+static secp256k1_context *ctx = NULL;
+
+static void counting_illegal_callback_fn(const char* str, void* data) {
+ /* Dummy callback function that just counts. */
+ int32_t *p;
+ (void)str;
+ p = data;
+ (*p)++;
+}
-void random_field_element_test(secp256k1_fe_t *fe) {
+static void uncounting_illegal_callback_fn(const char* str, void* data) {
+ /* Dummy callback function that just counts (backwards). */
+ int32_t *p;
+ (void)str;
+ p = data;
+ (*p)--;
+}
+
+void random_field_element_test(secp256k1_fe *fe) {
do {
unsigned char b32[32];
secp256k1_rand256_test(b32);
@@ -36,9 +67,9 @@ void random_field_element_test(secp256k1_fe_t *fe) {
} while(1);
}
-void random_field_element_magnitude(secp256k1_fe_t *fe) {
- secp256k1_fe_t zero;
- int n = secp256k1_rand32() % 9;
+void random_field_element_magnitude(secp256k1_fe *fe) {
+ secp256k1_fe zero;
+ int n = secp256k1_rand_int(9);
secp256k1_fe_normalize(fe);
if (n == 0) {
return;
@@ -47,23 +78,22 @@ void random_field_element_magnitude(secp256k1_fe_t *fe) {
secp256k1_fe_negate(&zero, &zero, 0);
secp256k1_fe_mul_int(&zero, n - 1);
secp256k1_fe_add(fe, &zero);
-#ifdef VERIFY
- CHECK(fe->magnitude == n);
-#endif
+ VERIFY_CHECK(fe->magnitude == n);
}
-void random_group_element_test(secp256k1_ge_t *ge) {
- secp256k1_fe_t fe;
+void random_group_element_test(secp256k1_ge *ge) {
+ secp256k1_fe fe;
do {
random_field_element_test(&fe);
- if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) {
+ if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) {
+ secp256k1_fe_normalize(&ge->y);
break;
}
} while(1);
}
-void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) {
- secp256k1_fe_t z2, z3;
+void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) {
+ secp256k1_fe z2, z3;
do {
random_field_element_test(&gej->z);
if (!secp256k1_fe_is_zero(&gej->z)) {
@@ -77,7 +107,7 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge
gej->infinity = ge->infinity;
}
-void random_scalar_order_test(secp256k1_scalar_t *num) {
+void random_scalar_order_test(secp256k1_scalar *num) {
do {
unsigned char b32[32];
int overflow = 0;
@@ -90,7 +120,7 @@ void random_scalar_order_test(secp256k1_scalar_t *num) {
} while(1);
}
-void random_scalar_order(secp256k1_scalar_t *num) {
+void random_scalar_order(secp256k1_scalar *num) {
do {
unsigned char b32[32];
int overflow = 0;
@@ -104,19 +134,31 @@ void random_scalar_order(secp256k1_scalar_t *num) {
}
void run_context_tests(void) {
- secp256k1_context_t *none = secp256k1_context_create(0);
- secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
- secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
- secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
-
- secp256k1_gej_t pubj;
- secp256k1_ge_t pub;
- secp256k1_scalar_t msg, key, nonce;
- secp256k1_ecdsa_sig_t sig;
+ secp256k1_pubkey pubkey;
+ secp256k1_ecdsa_signature sig;
+ unsigned char ctmp[32];
+ int32_t ecount;
+ int32_t ecount2;
+ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
+ secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ secp256k1_gej pubj;
+ secp256k1_ge pub;
+ secp256k1_scalar msg, key, nonce;
+ secp256k1_scalar sigr, sigs;
+
+ ecount = 0;
+ ecount2 = 10;
+ secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);
+ secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);
+ CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
/*** clone and destroy all of them to make sure cloning was complete ***/
{
- secp256k1_context_t *ctx_tmp;
+ secp256k1_context *ctx_tmp;
ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp);
@@ -124,30 +166,74 @@ void run_context_tests(void) {
ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp);
}
+ /* Verify that the error callback makes it across the clone. */
+ CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+ /* And that it resets back to default. */
+ secp256k1_context_set_error_callback(sign, NULL, NULL);
+ CHECK(vrfy->error_callback.fn == sign->error_callback.fn);
+
/*** attempt to use them ***/
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj);
+ /* Verify context-type checking illegal-argument errors. */
+ memset(ctmp, 1, 32);
+ CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0);
+ CHECK(ecount == 1);
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0);
+ CHECK(ecount == 2);
+ VG_UNDEF(&sig, sizeof(sig));
+ CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1);
+ VG_CHECK(&sig, sizeof(sig));
+ CHECK(ecount2 == 10);
+ CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0);
+ CHECK(ecount2 == 11);
+ CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0);
+ CHECK(ecount2 == 12);
+ CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);
+ CHECK(ecount2 == 13);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_context_randomize(sign, NULL) == 1);
+ CHECK(ecount2 == 13);
+ secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
+ secp256k1_context_set_illegal_callback(sign, NULL, NULL);
+
+ /* This shouldn't leak memory, due to already-set tests. */
+ secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL);
+ secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL);
+
/* obtain a working nonce */
do {
random_scalar_order_test(&nonce);
- } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL));
+ } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try signing */
- CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL));
- CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL));
+ CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
+ CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try verifying */
- CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg));
- CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg));
+ CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg));
+ CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg));
/* cleanup */
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(both);
+ /* Defined as no-op. */
+ secp256k1_context_destroy(NULL);
}
/***** HASH TESTS *****/
@@ -178,7 +264,7 @@ void run_sha256_tests(void) {
secp256k1_sha256_finalize(&hasher, out);
CHECK(memcmp(out, outputs[i], 32) == 0);
if (strlen(inputs[i]) > 0) {
- int split = secp256k1_rand32() % strlen(inputs[i]);
+ int split = secp256k1_rand_int(strlen(inputs[i]));
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
@@ -222,7 +308,7 @@ void run_hmac_sha256_tests(void) {
secp256k1_hmac_sha256_finalize(&hasher, out);
CHECK(memcmp(out, outputs[i], 32) == 0);
if (strlen(inputs[i]) > 0) {
- int split = secp256k1_rand32() % strlen(inputs[i]);
+ int split = secp256k1_rand_int(strlen(inputs[i]));
secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
@@ -233,16 +319,14 @@ void run_hmac_sha256_tests(void) {
}
void run_rfc6979_hmac_sha256_tests(void) {
- static const unsigned char key1[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00};
- static const unsigned char msg1[32] = {0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a};
+ static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0};
static const unsigned char out1[3][32] = {
{0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb},
{0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a},
{0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e}
};
- static const unsigned char key2[32] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- static const unsigned char msg2[32] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
+ static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
static const unsigned char out2[3][32] = {
{0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95},
{0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9},
@@ -251,24 +335,23 @@ void run_rfc6979_hmac_sha256_tests(void) {
secp256k1_rfc6979_hmac_sha256_t rng;
unsigned char out[32];
- unsigned char zero[1] = {0};
int i;
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64);
for (i = 0; i < 3; i++) {
secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
CHECK(memcmp(out, out1[i], 32) == 0);
}
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, zero, 1);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65);
for (i = 0; i < 3; i++) {
secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
CHECK(memcmp(out, out1[i], 32) != 0);
}
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 32, msg2, 32, zero, 0);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64);
for (i = 0; i < 3; i++) {
secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
CHECK(memcmp(out, out2[i], 32) == 0);
@@ -276,30 +359,102 @@ void run_rfc6979_hmac_sha256_tests(void) {
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
}
+/***** RANDOM TESTS *****/
+
+void test_rand_bits(int rand32, int bits) {
+ /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to
+ * get a false negative chance below once in a billion */
+ static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316};
+ /* We try multiplying the results with various odd numbers, which shouldn't
+ * influence the uniform distribution modulo a power of 2. */
+ static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011};
+ /* We only select up to 6 bits from the output to analyse */
+ unsigned int usebits = bits > 6 ? 6 : bits;
+ unsigned int maxshift = bits - usebits;
+ /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit
+ number, track all observed outcomes, one per bit in a uint64_t. */
+ uint64_t x[6][27] = {{0}};
+ unsigned int i, shift, m;
+ /* Multiply the output of all rand calls with the odd number m, which
+ should not change the uniformity of its distribution. */
+ for (i = 0; i < rounds[usebits]; i++) {
+ uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits));
+ CHECK((((uint64_t)r) >> bits) == 0);
+ for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) {
+ uint32_t rm = r * mults[m];
+ for (shift = 0; shift <= maxshift; shift++) {
+ x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1)));
+ }
+ }
+ }
+ for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) {
+ for (shift = 0; shift <= maxshift; shift++) {
+ /* Test that the lower usebits bits of x[shift] are 1 */
+ CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0);
+ }
+ }
+}
+
+/* Subrange must be a whole divisor of range, and at most 64 */
+void test_rand_int(uint32_t range, uint32_t subrange) {
+ /* (1-1/subrange)^rounds < 1/10^9 */
+ int rounds = (subrange * 2073) / 100;
+ int i;
+ uint64_t x = 0;
+ CHECK((range % subrange) == 0);
+ for (i = 0; i < rounds; i++) {
+ uint32_t r = secp256k1_rand_int(range);
+ CHECK(r < range);
+ r = r % subrange;
+ x |= (((uint64_t)1) << r);
+ }
+ /* Test that the lower subrange bits of x are 1. */
+ CHECK(((~x) << (64 - subrange)) == 0);
+}
+
+void run_rand_bits(void) {
+ size_t b;
+ test_rand_bits(1, 32);
+ for (b = 1; b <= 32; b++) {
+ test_rand_bits(0, b);
+ }
+}
+
+void run_rand_int(void) {
+ static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432};
+ static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64};
+ unsigned int m, s;
+ for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) {
+ for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) {
+ test_rand_int(ms[m] * ss[s], ss[s]);
+ }
+ }
+}
+
/***** NUM TESTS *****/
#ifndef USE_NUM_NONE
-void random_num_negate(secp256k1_num_t *num) {
- if (secp256k1_rand32() & 1) {
+void random_num_negate(secp256k1_num *num) {
+ if (secp256k1_rand_bits(1)) {
secp256k1_num_negate(num);
}
}
-void random_num_order_test(secp256k1_num_t *num) {
- secp256k1_scalar_t sc;
+void random_num_order_test(secp256k1_num *num) {
+ secp256k1_scalar sc;
random_scalar_order_test(&sc);
secp256k1_scalar_get_num(num, &sc);
}
-void random_num_order(secp256k1_num_t *num) {
- secp256k1_scalar_t sc;
+void random_num_order(secp256k1_num *num) {
+ secp256k1_scalar sc;
random_scalar_order(&sc);
secp256k1_scalar_get_num(num, &sc);
}
void test_num_negate(void) {
- secp256k1_num_t n1;
- secp256k1_num_t n2;
+ secp256k1_num n1;
+ secp256k1_num n2;
random_num_order_test(&n1); /* n1 = R */
random_num_negate(&n1);
secp256k1_num_copy(&n2, &n1); /* n2 = R */
@@ -318,16 +473,15 @@ void test_num_negate(void) {
}
void test_num_add_sub(void) {
- secp256k1_num_t n1;
- secp256k1_num_t n2;
- secp256k1_num_t n1p2, n2p1, n1m2, n2m1;
- int r = secp256k1_rand32();
+ secp256k1_num n1;
+ secp256k1_num n2;
+ secp256k1_num n1p2, n2p1, n1m2, n2m1;
random_num_order_test(&n1); /* n1 = R1 */
- if (r & 1) {
+ if (secp256k1_rand_bits(1)) {
random_num_negate(&n1);
}
random_num_order_test(&n2); /* n2 = R2 */
- if (r & 2) {
+ if (secp256k1_rand_bits(1)) {
random_num_negate(&n2);
}
secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */
@@ -358,12 +512,12 @@ void run_num_smalltests(void) {
/***** SCALAR TESTS *****/
void scalar_test(void) {
- secp256k1_scalar_t s;
- secp256k1_scalar_t s1;
- secp256k1_scalar_t s2;
+ secp256k1_scalar s;
+ secp256k1_scalar s1;
+ secp256k1_scalar s2;
#ifndef USE_NUM_NONE
- secp256k1_num_t snum, s1num, s2num;
- secp256k1_num_t order, half_order;
+ secp256k1_num snum, s1num, s2num;
+ secp256k1_num order, half_order;
#endif
unsigned char c[32];
@@ -390,10 +544,10 @@ void scalar_test(void) {
{
int i;
/* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */
- secp256k1_scalar_t n;
+ secp256k1_scalar n;
secp256k1_scalar_set_int(&n, 0);
for (i = 0; i < 256; i += 4) {
- secp256k1_scalar_t t;
+ secp256k1_scalar t;
int j;
secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));
for (j = 0; j < 4; j++) {
@@ -406,13 +560,13 @@ void scalar_test(void) {
{
/* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */
- secp256k1_scalar_t n;
+ secp256k1_scalar n;
int i = 0;
secp256k1_scalar_set_int(&n, 0);
while (i < 256) {
- secp256k1_scalar_t t;
+ secp256k1_scalar t;
int j;
- int now = (secp256k1_rand32() % 15) + 1;
+ int now = secp256k1_rand_int(15) + 1;
if (now + i > 256) {
now = 256 - i;
}
@@ -429,9 +583,9 @@ void scalar_test(void) {
#ifndef USE_NUM_NONE
{
/* Test that adding the scalars together is equal to adding their numbers together modulo the order. */
- secp256k1_num_t rnum;
- secp256k1_num_t r2num;
- secp256k1_scalar_t r;
+ secp256k1_num rnum;
+ secp256k1_num r2num;
+ secp256k1_scalar r;
secp256k1_num_add(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &order);
secp256k1_scalar_add(&r, &s, &s2);
@@ -440,10 +594,10 @@ void scalar_test(void) {
}
{
- /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */
- secp256k1_scalar_t r;
- secp256k1_num_t r2num;
- secp256k1_num_t rnum;
+ /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */
+ secp256k1_scalar r;
+ secp256k1_num r2num;
+ secp256k1_num rnum;
secp256k1_num_mul(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &order);
secp256k1_scalar_mul(&r, &s, &s2);
@@ -457,9 +611,9 @@ void scalar_test(void) {
}
{
- secp256k1_scalar_t neg;
- secp256k1_num_t negnum;
- secp256k1_num_t negnum2;
+ secp256k1_scalar neg;
+ secp256k1_num negnum;
+ secp256k1_num negnum2;
/* Check that comparison with zero matches comparison with zero on the number. */
CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s));
/* Check that comparison with the half order is equal to testing for high scalar. */
@@ -484,12 +638,12 @@ void scalar_test(void) {
{
/* Test secp256k1_scalar_mul_shift_var. */
- secp256k1_scalar_t r;
- secp256k1_num_t one;
- secp256k1_num_t rnum;
- secp256k1_num_t rnum2;
+ secp256k1_scalar r;
+ secp256k1_num one;
+ secp256k1_num rnum;
+ secp256k1_num rnum2;
unsigned char cone[1] = {0x01};
- unsigned int shift = 256 + (secp256k1_rand32() % 257);
+ unsigned int shift = 256 + secp256k1_rand_int(257);
secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift);
secp256k1_num_mul(&rnum, &s1num, &s2num);
secp256k1_num_shift(&rnum, shift - 1);
@@ -499,15 +653,29 @@ void scalar_test(void) {
secp256k1_scalar_get_num(&rnum2, &r);
CHECK(secp256k1_num_eq(&rnum, &rnum2));
}
+
+ {
+ /* test secp256k1_scalar_shr_int */
+ secp256k1_scalar r;
+ int i;
+ random_scalar_order_test(&r);
+ for (i = 0; i < 100; ++i) {
+ int low;
+ int shift = 1 + secp256k1_rand_int(15);
+ int expected = r.d[0] % (1 << shift);
+ low = secp256k1_scalar_shr_int(&r, shift);
+ CHECK(expected == low);
+ }
+ }
#endif
{
/* Test that scalar inverses are equal to the inverse of their number modulo the order. */
if (!secp256k1_scalar_is_zero(&s)) {
- secp256k1_scalar_t inv;
+ secp256k1_scalar inv;
#ifndef USE_NUM_NONE
- secp256k1_num_t invnum;
- secp256k1_num_t invnum2;
+ secp256k1_num invnum;
+ secp256k1_num invnum2;
#endif
secp256k1_scalar_inverse(&inv, &s);
#ifndef USE_NUM_NONE
@@ -526,18 +694,18 @@ void scalar_test(void) {
{
/* Test commutativity of add. */
- secp256k1_scalar_t r1, r2;
+ secp256k1_scalar r1, r2;
secp256k1_scalar_add(&r1, &s1, &s2);
secp256k1_scalar_add(&r2, &s2, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2));
}
{
- secp256k1_scalar_t r1, r2;
- secp256k1_scalar_t b;
+ secp256k1_scalar r1, r2;
+ secp256k1_scalar b;
int i;
/* Test add_bit. */
- int bit = secp256k1_rand32() % 256;
+ int bit = secp256k1_rand_bits(8);
secp256k1_scalar_set_int(&b, 1);
CHECK(secp256k1_scalar_is_one(&b));
for (i = 0; i < bit; i++) {
@@ -547,14 +715,17 @@ void scalar_test(void) {
r2 = s1;
if (!secp256k1_scalar_add(&r1, &r1, &b)) {
/* No overflow happened. */
- secp256k1_scalar_add_bit(&r2, bit);
+ secp256k1_scalar_cadd_bit(&r2, bit, 1);
+ CHECK(secp256k1_scalar_eq(&r1, &r2));
+ /* cadd is a noop when flag is zero */
+ secp256k1_scalar_cadd_bit(&r2, bit, 0);
CHECK(secp256k1_scalar_eq(&r1, &r2));
}
}
{
/* Test commutativity of mul. */
- secp256k1_scalar_t r1, r2;
+ secp256k1_scalar r1, r2;
secp256k1_scalar_mul(&r1, &s1, &s2);
secp256k1_scalar_mul(&r2, &s2, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2));
@@ -562,7 +733,7 @@ void scalar_test(void) {
{
/* Test associativity of add. */
- secp256k1_scalar_t r1, r2;
+ secp256k1_scalar r1, r2;
secp256k1_scalar_add(&r1, &s1, &s2);
secp256k1_scalar_add(&r1, &r1, &s);
secp256k1_scalar_add(&r2, &s2, &s);
@@ -572,7 +743,7 @@ void scalar_test(void) {
{
/* Test associativity of mul. */
- secp256k1_scalar_t r1, r2;
+ secp256k1_scalar r1, r2;
secp256k1_scalar_mul(&r1, &s1, &s2);
secp256k1_scalar_mul(&r1, &r1, &s);
secp256k1_scalar_mul(&r2, &s2, &s);
@@ -582,7 +753,7 @@ void scalar_test(void) {
{
/* Test distributitivity of mul over add. */
- secp256k1_scalar_t r1, r2, t;
+ secp256k1_scalar r1, r2, t;
secp256k1_scalar_add(&r1, &s1, &s2);
secp256k1_scalar_mul(&r1, &r1, &s);
secp256k1_scalar_mul(&r2, &s1, &s);
@@ -593,7 +764,7 @@ void scalar_test(void) {
{
/* Test square. */
- secp256k1_scalar_t r1, r2;
+ secp256k1_scalar r1, r2;
secp256k1_scalar_sqr(&r1, &s1);
secp256k1_scalar_mul(&r2, &s1, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2));
@@ -601,7 +772,7 @@ void scalar_test(void) {
{
/* Test multiplicative identity. */
- secp256k1_scalar_t r1, v1;
+ secp256k1_scalar r1, v1;
secp256k1_scalar_set_int(&v1,1);
secp256k1_scalar_mul(&r1, &s1, &v1);
CHECK(secp256k1_scalar_eq(&r1, &s1));
@@ -609,7 +780,7 @@ void scalar_test(void) {
{
/* Test additive identity. */
- secp256k1_scalar_t r1, v0;
+ secp256k1_scalar r1, v0;
secp256k1_scalar_set_int(&v0,0);
secp256k1_scalar_add(&r1, &s1, &v0);
CHECK(secp256k1_scalar_eq(&r1, &s1));
@@ -617,7 +788,7 @@ void scalar_test(void) {
{
/* Test zero product property. */
- secp256k1_scalar_t r1, v0;
+ secp256k1_scalar r1, v0;
secp256k1_scalar_set_int(&v0,0);
secp256k1_scalar_mul(&r1, &s1, &v0);
CHECK(secp256k1_scalar_eq(&r1, &v0));
@@ -633,7 +804,7 @@ void run_scalar_tests(void) {
{
/* (-1)+1 should be zero. */
- secp256k1_scalar_t s, o;
+ secp256k1_scalar s, o;
secp256k1_scalar_set_int(&s, 1);
CHECK(secp256k1_scalar_is_one(&s));
secp256k1_scalar_negate(&o, &s);
@@ -646,8 +817,8 @@ void run_scalar_tests(void) {
#ifndef USE_NUM_NONE
{
/* A scalar with value of the curve order should be 0. */
- secp256k1_num_t order;
- secp256k1_scalar_t zero;
+ secp256k1_num order;
+ secp256k1_scalar zero;
unsigned char bin[32];
int overflow = 0;
secp256k1_scalar_order_get_num(&order);
@@ -657,11 +828,589 @@ void run_scalar_tests(void) {
CHECK(secp256k1_scalar_is_zero(&zero));
}
#endif
+
+ {
+ /* Does check_overflow check catch all ones? */
+ static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST(
+ 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+ 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
+ );
+ CHECK(secp256k1_scalar_check_overflow(&overflowed));
+ }
+
+ {
+ /* Static test vectors.
+ * These were reduced from ~10^12 random vectors based on comparison-decision
+ * and edge-case coverage on 32-bit and 64-bit implementations.
+ * The responses were generated with Sage 5.9.
+ */
+ secp256k1_scalar x;
+ secp256k1_scalar y;
+ secp256k1_scalar z;
+ secp256k1_scalar zz;
+ secp256k1_scalar one;
+ secp256k1_scalar r1;
+ secp256k1_scalar r2;
+#if defined(USE_SCALAR_INV_NUM)
+ secp256k1_scalar zzv;
+#endif
+ int overflow;
+ unsigned char chal[32][2][32] = {
+ {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}},
+ {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}},
+ {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00},
+ {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}},
+ {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+ 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0,
+ 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
+ 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,
+ 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f,
+ 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}},
+ {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f,
+ 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},
+ {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff,
+ 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
+ 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0},
+ {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff,
+ 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f},
+ {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff,
+ 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff},
+ {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}},
+ {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff,
+ 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}},
+ {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00},
+ {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}},
+ {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00,
+ 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}},
+ {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+ 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00},
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},
+ {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80,
+ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}},
+ {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff,
+ 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+ 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0,
+ 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+ 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}},
+ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+ 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+ 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
+ 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}},
+ {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00},
+ {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+ 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f,
+ 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}},
+ {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},
+ {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f,
+ 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}},
+ {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83,
+ 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0},
+ {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
+ 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}
+ };
+ unsigned char res[32][2][32] = {
+ {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9,
+ 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1,
+ 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6,
+ 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35},
+ {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d,
+ 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c,
+ 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49,
+ 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}},
+ {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22,
+ 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c,
+ 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f,
+ 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8},
+ {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77,
+ 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4,
+ 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59,
+ 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}},
+ {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef,
+ 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab,
+ 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55,
+ 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c},
+ {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96,
+ 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f,
+ 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12,
+ 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}},
+ {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c,
+ 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf,
+ 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9,
+ 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48},
+ {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42,
+ 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5,
+ 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c,
+ 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}},
+ {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb,
+ 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74,
+ 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6,
+ 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63},
+ {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3,
+ 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99,
+ 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58,
+ 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}},
+ {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b,
+ 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7,
+ 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f,
+ 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0},
+ {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d,
+ 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d,
+ 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9,
+ 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}},
+ {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7,
+ 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70,
+ 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06,
+ 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e},
+ {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9,
+ 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79,
+ 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e,
+ 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}},
+ {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb,
+ 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5,
+ 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a,
+ 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe},
+ {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48,
+ 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e,
+ 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc,
+ 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}},
+ {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b,
+ 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0,
+ 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53,
+ 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8},
+ {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c,
+ 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01,
+ 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f,
+ 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}},
+ {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7,
+ 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c,
+ 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92,
+ 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30},
+ {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62,
+ 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e,
+ 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb,
+ 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}},
+ {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25,
+ 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d,
+ 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0,
+ 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13},
+ {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60,
+ 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00,
+ 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4,
+ 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}},
+ {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31,
+ 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4,
+ 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88,
+ 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa},
+ {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57,
+ 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38,
+ 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51,
+ 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}},
+ {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c,
+ 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f,
+ 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2,
+ 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4},
+ {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01,
+ 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4,
+ 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86,
+ 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}},
+ {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5,
+ 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51,
+ 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3,
+ 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62},
+ {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c,
+ 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91,
+ 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c,
+ 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}},
+ {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e,
+ 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56,
+ 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58,
+ 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4},
+ {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41,
+ 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7,
+ 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92,
+ 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}},
+ {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec,
+ 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19,
+ 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3,
+ 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4},
+ {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87,
+ 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a,
+ 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92,
+ 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}},
+ {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64,
+ 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3,
+ 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f,
+ 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33},
+ {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c,
+ 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d,
+ 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea,
+ 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}},
+ {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7,
+ 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a,
+ 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae,
+ 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe},
+ {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc,
+ 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39,
+ 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14,
+ 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}},
+ {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23,
+ 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d,
+ 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2,
+ 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16},
+ {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c,
+ 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84,
+ 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0,
+ 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}},
+ {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb,
+ 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94,
+ 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b,
+ 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e},
+ {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54,
+ 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00,
+ 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb,
+ 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
+ {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1,
+ 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0,
+ 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59,
+ 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92},
+ {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1,
+ 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0,
+ 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59,
+ 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}},
+ {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0,
+ 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b,
+ 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94,
+ 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8},
+ {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26,
+ 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d,
+ 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a,
+ 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,
+ 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd},
+ {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1,
+ 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0,
+ 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59,
+ 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+ 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
+ {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39,
+ 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea,
+ 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf,
+ 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae},
+ {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b,
+ 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb,
+ 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6,
+ 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}},
+ {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a,
+ 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f,
+ 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9,
+ 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56},
+ {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93,
+ 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07,
+ 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71,
+ 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}},
+ {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87,
+ 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9,
+ 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55,
+ 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73},
+ {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d,
+ 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86,
+ 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb,
+ 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}},
+ {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2,
+ 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7,
+ 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41,
+ 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7},
+ {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06,
+ 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04,
+ 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08,
+ 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}},
+ {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2,
+ 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b,
+ 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40,
+ 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68},
+ {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e,
+ 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a,
+ 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b,
+ 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}},
+ {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67,
+ 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f,
+ 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a,
+ 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51},
+ {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2,
+ 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38,
+ 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34,
+ 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}
+ };
+ secp256k1_scalar_set_int(&one, 1);
+ for (i = 0; i < 32; i++) {
+ secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
+ CHECK(!overflow);
+ secp256k1_scalar_set_b32(&y, chal[i][1], &overflow);
+ CHECK(!overflow);
+ secp256k1_scalar_set_b32(&r1, res[i][0], &overflow);
+ CHECK(!overflow);
+ secp256k1_scalar_set_b32(&r2, res[i][1], &overflow);
+ CHECK(!overflow);
+ secp256k1_scalar_mul(&z, &x, &y);
+ CHECK(!secp256k1_scalar_check_overflow(&z));
+ CHECK(secp256k1_scalar_eq(&r1, &z));
+ if (!secp256k1_scalar_is_zero(&y)) {
+ secp256k1_scalar_inverse(&zz, &y);
+ CHECK(!secp256k1_scalar_check_overflow(&zz));
+#if defined(USE_SCALAR_INV_NUM)
+ secp256k1_scalar_inverse_var(&zzv, &y);
+ CHECK(secp256k1_scalar_eq(&zzv, &zz));
+#endif
+ secp256k1_scalar_mul(&z, &z, &zz);
+ CHECK(!secp256k1_scalar_check_overflow(&z));
+ CHECK(secp256k1_scalar_eq(&x, &z));
+ secp256k1_scalar_mul(&zz, &zz, &y);
+ CHECK(!secp256k1_scalar_check_overflow(&zz));
+ CHECK(secp256k1_scalar_eq(&one, &zz));
+ }
+ secp256k1_scalar_mul(&z, &x, &x);
+ CHECK(!secp256k1_scalar_check_overflow(&z));
+ secp256k1_scalar_sqr(&zz, &x);
+ CHECK(!secp256k1_scalar_check_overflow(&zz));
+ CHECK(secp256k1_scalar_eq(&zz, &z));
+ CHECK(secp256k1_scalar_eq(&r2, &zz));
+ }
+ }
}
/***** FIELD TESTS *****/
-void random_fe(secp256k1_fe_t *x) {
+void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_rand256(bin);
@@ -671,7 +1420,17 @@ void random_fe(secp256k1_fe_t *x) {
} while(1);
}
-void random_fe_non_zero(secp256k1_fe_t *nz) {
+void random_fe_test(secp256k1_fe *x) {
+ unsigned char bin[32];
+ do {
+ secp256k1_rand256_test(bin);
+ if (secp256k1_fe_set_b32(x, bin)) {
+ return;
+ }
+ } while(1);
+}
+
+void random_fe_non_zero(secp256k1_fe *nz) {
int tries = 10;
while (--tries >= 0) {
random_fe(nz);
@@ -684,25 +1443,25 @@ void random_fe_non_zero(secp256k1_fe_t *nz) {
CHECK(tries >= 0);
}
-void random_fe_non_square(secp256k1_fe_t *ns) {
- secp256k1_fe_t r;
+void random_fe_non_square(secp256k1_fe *ns) {
+ secp256k1_fe r;
random_fe_non_zero(ns);
if (secp256k1_fe_sqrt_var(&r, ns)) {
secp256k1_fe_negate(ns, ns, 1);
}
}
-int check_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
- secp256k1_fe_t an = *a;
- secp256k1_fe_t bn = *b;
+int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe an = *a;
+ secp256k1_fe bn = *b;
secp256k1_fe_normalize_weak(&an);
secp256k1_fe_normalize_var(&bn);
return secp256k1_fe_equal_var(&an, &bn);
}
-int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) {
- secp256k1_fe_t x;
- secp256k1_fe_t one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) {
+ secp256k1_fe x;
+ secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
secp256k1_fe_mul(&x, a, ai);
return check_fe_equal(&x, &one);
}
@@ -714,17 +1473,17 @@ void run_field_convert(void) {
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40
};
- static const secp256k1_fe_storage_t fes = SECP256K1_FE_STORAGE_CONST(
+ static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST(
0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL,
0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL
);
- static const secp256k1_fe_t fe = SECP256K1_FE_CONST(
+ static const secp256k1_fe fe = SECP256K1_FE_CONST(
0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL,
0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL
);
- secp256k1_fe_t fe2;
+ secp256k1_fe fe2;
unsigned char b322[32];
- secp256k1_fe_storage_t fes2;
+ secp256k1_fe_storage fes2;
/* Check conversions to fe. */
CHECK(secp256k1_fe_set_b32(&fe2, b32));
CHECK(secp256k1_fe_equal_var(&fe, &fe2));
@@ -737,15 +1496,24 @@ void run_field_convert(void) {
CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0);
}
+int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe t = *b;
+#ifdef VERIFY
+ t.magnitude = a->magnitude;
+ t.normalized = a->normalized;
+#endif
+ return memcmp(a, &t, sizeof(secp256k1_fe));
+}
+
void run_field_misc(void) {
- secp256k1_fe_t x;
- secp256k1_fe_t y;
- secp256k1_fe_t z;
- secp256k1_fe_t q;
- secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
- int i;
+ secp256k1_fe x;
+ secp256k1_fe y;
+ secp256k1_fe z;
+ secp256k1_fe q;
+ secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
+ int i, j;
for (i = 0; i < 5*count; i++) {
- secp256k1_fe_storage_t xs, ys, zs;
+ secp256k1_fe_storage xs, ys, zs;
random_fe(&x);
random_fe_non_zero(&y);
/* Test the fe equality and comparison operations. */
@@ -756,14 +1524,27 @@ void run_field_misc(void) {
/* Test fe conditional move; z is not normalized here. */
q = x;
secp256k1_fe_cmov(&x, &z, 0);
+ VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude);
secp256k1_fe_cmov(&x, &x, 1);
- CHECK(memcmp(&x, &z, sizeof(x)) != 0);
- CHECK(memcmp(&x, &q, sizeof(x)) == 0);
+ CHECK(fe_memcmp(&x, &z) != 0);
+ CHECK(fe_memcmp(&x, &q) == 0);
secp256k1_fe_cmov(&q, &z, 1);
- CHECK(memcmp(&q, &z, sizeof(q)) == 0);
- /* Test storage conversion and conditional moves. */
- secp256k1_fe_normalize(&z);
+ VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude);
+ CHECK(fe_memcmp(&q, &z) == 0);
+ secp256k1_fe_normalize_var(&x);
+ secp256k1_fe_normalize_var(&z);
CHECK(!secp256k1_fe_equal_var(&x, &z));
+ secp256k1_fe_normalize_var(&q);
+ secp256k1_fe_cmov(&q, &z, (i&1));
+ VERIFY_CHECK(q.normalized && q.magnitude == 1);
+ for (j = 0; j < 6; j++) {
+ secp256k1_fe_negate(&z, &z, j+1);
+ secp256k1_fe_normalize_var(&q);
+ secp256k1_fe_cmov(&q, &z, (j&1));
+ VERIFY_CHECK(!q.normalized && q.magnitude == (j+2));
+ }
+ secp256k1_fe_normalize_var(&z);
+ /* Test storage conversion and conditional moves. */
secp256k1_fe_to_storage(&xs, &x);
secp256k1_fe_to_storage(&ys, &y);
secp256k1_fe_to_storage(&zs, &z);
@@ -797,7 +1578,7 @@ void run_field_misc(void) {
}
void run_field_inv(void) {
- secp256k1_fe_t x, xi, xii;
+ secp256k1_fe x, xi, xii;
int i;
for (i = 0; i < 10*count; i++) {
random_fe_non_zero(&x);
@@ -809,7 +1590,7 @@ void run_field_inv(void) {
}
void run_field_inv_var(void) {
- secp256k1_fe_t x, xi, xii;
+ secp256k1_fe x, xi, xii;
int i;
for (i = 0; i < 10*count; i++) {
random_fe_non_zero(&x);
@@ -821,13 +1602,13 @@ void run_field_inv_var(void) {
}
void run_field_inv_all_var(void) {
- secp256k1_fe_t x[16], xi[16], xii[16];
+ secp256k1_fe x[16], xi[16], xii[16];
int i;
/* Check it's safe to call for 0 elements */
secp256k1_fe_inv_all_var(0, xi, x);
for (i = 0; i < count; i++) {
size_t j;
- size_t len = (secp256k1_rand32() & 15) + 1;
+ size_t len = secp256k1_rand_int(15) + 1;
for (j = 0; j < len; j++) {
random_fe_non_zero(&x[j]);
}
@@ -843,7 +1624,7 @@ void run_field_inv_all_var(void) {
}
void run_sqr(void) {
- secp256k1_fe_t x, s;
+ secp256k1_fe x, s;
{
int i;
@@ -858,8 +1639,8 @@ void run_sqr(void) {
}
}
-void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) {
- secp256k1_fe_t r1, r2;
+void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
+ secp256k1_fe r1, r2;
int v = secp256k1_fe_sqrt_var(&r1, a);
CHECK((v == 0) == (k == NULL));
@@ -873,7 +1654,7 @@ void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) {
}
void run_sqrt(void) {
- secp256k1_fe_t ns, x, s, t;
+ secp256k1_fe ns, x, s, t;
int i;
/* Check sqrt(0) is 0 */
@@ -908,19 +1689,19 @@ void run_sqrt(void) {
/***** GROUP TESTS *****/
-void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) {
+void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(a->infinity == b->infinity);
if (a->infinity) {
return;
}
CHECK(secp256k1_fe_equal_var(&a->x, &b->x));
- CHECK(secp256k1_fe_equal_var(&b->y, &b->y));
+ CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
}
/* This compares jacobian points including their Z, not just their geometric meaning. */
-int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
- secp256k1_gej_t a2;
- secp256k1_gej_t b2;
+int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {
+ secp256k1_gej a2;
+ secp256k1_gej b2;
int ret = 1;
ret &= a->infinity == b->infinity;
if (ret && !a->infinity) {
@@ -939,9 +1720,9 @@ int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
return ret;
}
-void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) {
- secp256k1_fe_t z2s;
- secp256k1_fe_t u1, u2, s1, s2;
+void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
+ secp256k1_fe z2s;
+ secp256k1_fe u1, u2, s1, s2;
CHECK(a->infinity == b->infinity);
if (a->infinity) {
return;
@@ -958,21 +1739,39 @@ void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) {
void test_ge(void) {
int i, i1;
+#ifdef USE_ENDOMORPHISM
+ int runs = 6;
+#else
int runs = 4;
+#endif
/* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4).
* The second in each pair of identical points uses a random Z coordinate in the Jacobian form.
* All magnitudes are randomized.
- * All 17*17 combinations of points are added to eachother, using all applicable methods.
+ * All 17*17 combinations of points are added to each other, using all applicable methods.
+ *
+ * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well.
*/
- secp256k1_ge_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs));
- secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs));
+ secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs));
+ secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs));
+ secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
+ secp256k1_fe zf;
+ secp256k1_fe zfi2, zfi3;
+
secp256k1_gej_set_infinity(&gej[0]);
secp256k1_ge_clear(&ge[0]);
secp256k1_ge_set_gej_var(&ge[0], &gej[0]);
for (i = 0; i < runs; i++) {
int j;
- secp256k1_ge_t g;
+ secp256k1_ge g;
random_group_element_test(&g);
+#ifdef USE_ENDOMORPHISM
+ if (i >= runs - 2) {
+ secp256k1_ge_mul_lambda(&g, &ge[1]);
+ }
+ if (i >= runs - 1) {
+ secp256k1_ge_mul_lambda(&g, &g);
+ }
+#endif
ge[1 + 4 * i] = g;
ge[2 + 4 * i] = g;
secp256k1_ge_neg(&ge[3 + 4 * i], &g);
@@ -990,18 +1789,65 @@ void test_ge(void) {
}
}
+ /* Compute z inverses. */
+ {
+ secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
+ for (i = 0; i < 4 * runs + 1; i++) {
+ if (i == 0) {
+ /* The point at infinity does not have a meaningful z inverse. Any should do. */
+ do {
+ random_field_element_test(&zs[i]);
+ } while(secp256k1_fe_is_zero(&zs[i]));
+ } else {
+ zs[i] = gej[i].z;
+ }
+ }
+ secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs);
+ free(zs);
+ }
+
+ /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */
+ do {
+ random_field_element_test(&zf);
+ } while(secp256k1_fe_is_zero(&zf));
+ random_field_element_magnitude(&zf);
+ secp256k1_fe_inv_var(&zfi3, &zf);
+ secp256k1_fe_sqr(&zfi2, &zfi3);
+ secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);
+
for (i1 = 0; i1 < 1 + 4 * runs; i1++) {
int i2;
for (i2 = 0; i2 < 1 + 4 * runs; i2++) {
/* Compute reference result using gej + gej (var). */
- secp256k1_gej_t refj, resj;
- secp256k1_ge_t ref;
- secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2]);
+ secp256k1_gej refj, resj;
+ secp256k1_ge ref;
+ secp256k1_fe zr;
+ secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr);
+ /* Check Z ratio. */
+ if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) {
+ secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z);
+ CHECK(secp256k1_fe_equal_var(&zrz, &refj.z));
+ }
secp256k1_ge_set_gej_var(&ref, &refj);
- /* Test gej + ge (var). */
- secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2]);
+ /* Test gej + ge with Z ratio result (var). */
+ secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr);
ge_equals_gej(&ref, &resj);
+ if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) {
+ secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z);
+ CHECK(secp256k1_fe_equal_var(&zrz, &resj.z));
+ }
+
+ /* Test gej + ge (var, with additional Z factor). */
+ {
+ secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */
+ secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2);
+ secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3);
+ random_field_element_magnitude(&ge2_zfi.x);
+ random_field_element_magnitude(&ge2_zfi.y);
+ secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf);
+ ge_equals_gej(&ref, &resj);
+ }
/* Test gej + ge (const). */
if (i2 != 0) {
@@ -1012,10 +1858,15 @@ void test_ge(void) {
/* Test doubling (var). */
if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) {
- /* Normal doubling. */
- secp256k1_gej_double_var(&resj, &gej[i1]);
+ secp256k1_fe zr2;
+ /* Normal doubling with Z ratio result. */
+ secp256k1_gej_double_var(&resj, &gej[i1], &zr2);
ge_equals_gej(&ref, &resj);
- secp256k1_gej_double_var(&resj, &gej[i2]);
+ /* Check Z ratio. */
+ secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z);
+ CHECK(secp256k1_fe_equal_var(&zr2, &resj.z));
+ /* Normal doubling. */
+ secp256k1_gej_double_var(&resj, &gej[i2], NULL);
ge_equals_gej(&ref, &resj);
}
@@ -1040,41 +1891,121 @@ void test_ge(void) {
/* Test adding all points together in random order equals infinity. */
{
- secp256k1_gej_t sum = SECP256K1_GEJ_CONST_INFINITY;
- secp256k1_gej_t *gej_shuffled = (secp256k1_gej_t *)malloc((4 * runs + 1) * sizeof(secp256k1_gej_t));
+ secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY;
+ secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej));
for (i = 0; i < 4 * runs + 1; i++) {
gej_shuffled[i] = gej[i];
}
for (i = 0; i < 4 * runs + 1; i++) {
- int swap = i + secp256k1_rand32() % (4 * runs + 1 - i);
+ int swap = i + secp256k1_rand_int(4 * runs + 1 - i);
if (swap != i) {
- secp256k1_gej_t t = gej_shuffled[i];
+ secp256k1_gej t = gej_shuffled[i];
gej_shuffled[i] = gej_shuffled[swap];
gej_shuffled[swap] = t;
}
}
for (i = 0; i < 4 * runs + 1; i++) {
- secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i]);
+ secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL);
}
CHECK(secp256k1_gej_is_infinity(&sum));
free(gej_shuffled);
}
- /* Test batch gej -> ge conversion. */
+ /* Test batch gej -> ge conversion with and without known z ratios. */
{
- secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t));
- secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej);
+ secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe));
+ secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
+ secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
for (i = 0; i < 4 * runs + 1; i++) {
- secp256k1_fe_t s;
+ /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */
+ if (i < 4 * runs) {
+ secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z);
+ }
+ }
+ secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr);
+ secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback);
+ for (i = 0; i < 4 * runs + 1; i++) {
+ secp256k1_fe s;
random_fe_non_zero(&s);
secp256k1_gej_rescale(&gej[i], &s);
+ ge_equals_gej(&ge_set_table[i], &gej[i]);
ge_equals_gej(&ge_set_all[i], &gej[i]);
}
+ free(ge_set_table);
free(ge_set_all);
+ free(zr);
}
free(ge);
free(gej);
+ free(zinv);
+}
+
+void test_add_neg_y_diff_x(void) {
+ /* The point of this test is to check that we can add two points
+ * whose y-coordinates are negatives of each other but whose x
+ * coordinates differ. If the x-coordinates were the same, these
+ * points would be negatives of each other and their sum is
+ * infinity. This is cool because it "covers up" any degeneracy
+ * in the addition algorithm that would cause the xy coordinates
+ * of the sum to be wrong (since infinity has no xy coordinates).
+ * HOWEVER, if the x-coordinates are different, infinity is the
+ * wrong answer, and such degeneracies are exposed. This is the
+ * root of https://github.com/bitcoin/secp256k1/issues/257 which
+ * this test is a regression test for.
+ *
+ * These points were generated in sage as
+ * # secp256k1 params
+ * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
+ * C = EllipticCurve ([F (0), F (7)])
+ * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
+ * N = FiniteField(G.order())
+ *
+ * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F)
+ * x = polygen(N)
+ * lam = (1 - x^3).roots()[1][0]
+ *
+ * # random "bad pair"
+ * P = C.random_element()
+ * Q = -int(lam) * P
+ * print " P: %x %x" % P.xy()
+ * print " Q: %x %x" % Q.xy()
+ * print "P + Q: %x %x" % (P + Q).xy()
+ */
+ secp256k1_gej aj = SECP256K1_GEJ_CONST(
+ 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30,
+ 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb,
+ 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8,
+ 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d
+ );
+ secp256k1_gej bj = SECP256K1_GEJ_CONST(
+ 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86,
+ 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7,
+ 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57,
+ 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2
+ );
+ secp256k1_gej sumj = SECP256K1_GEJ_CONST(
+ 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027,
+ 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a,
+ 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08,
+ 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe
+ );
+ secp256k1_ge b;
+ secp256k1_gej resj;
+ secp256k1_ge res;
+ secp256k1_ge_set_gej(&b, &bj);
+
+ secp256k1_gej_add_var(&resj, &aj, &bj, NULL);
+ secp256k1_ge_set_gej(&res, &resj);
+ ge_equals_gej(&res, &sumj);
+
+ secp256k1_gej_add_ge(&resj, &aj, &b);
+ secp256k1_ge_set_gej(&res, &resj);
+ ge_equals_gej(&res, &sumj);
+
+ secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL);
+ secp256k1_ge_set_gej(&res, &resj);
+ ge_equals_gej(&res, &sumj);
}
void run_ge(void) {
@@ -1082,36 +2013,125 @@ void run_ge(void) {
for (i = 0; i < count * 32; i++) {
test_ge();
}
+ test_add_neg_y_diff_x();
+}
+
+void test_ec_combine(void) {
+ secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ secp256k1_pubkey data[6];
+ const secp256k1_pubkey* d[6];
+ secp256k1_pubkey sd;
+ secp256k1_pubkey sd2;
+ secp256k1_gej Qj;
+ secp256k1_ge Q;
+ int i;
+ for (i = 1; i <= 6; i++) {
+ secp256k1_scalar s;
+ random_scalar_order_test(&s);
+ secp256k1_scalar_add(&sum, &sum, &s);
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s);
+ secp256k1_ge_set_gej(&Q, &Qj);
+ secp256k1_pubkey_save(&data[i - 1], &Q);
+ d[i - 1] = &data[i - 1];
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum);
+ secp256k1_ge_set_gej(&Q, &Qj);
+ secp256k1_pubkey_save(&sd, &Q);
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1);
+ CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0);
+ }
+}
+
+void run_ec_combine(void) {
+ int i;
+ for (i = 0; i < count * 8; i++) {
+ test_ec_combine();
+ }
+}
+
+void test_group_decompress(const secp256k1_fe* x) {
+ /* The input itself, normalized. */
+ secp256k1_fe fex = *x;
+ secp256k1_fe tmp;
+ /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */
+ secp256k1_ge ge_quad, ge_even, ge_odd;
+ /* Return values of the above calls. */
+ int res_quad, res_even, res_odd;
+
+ secp256k1_fe_normalize_var(&fex);
+
+ res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex);
+ res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);
+ res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);
+
+ CHECK(res_quad == res_even);
+ CHECK(res_quad == res_odd);
+
+ if (res_quad) {
+ secp256k1_fe_normalize_var(&ge_quad.x);
+ secp256k1_fe_normalize_var(&ge_odd.x);
+ secp256k1_fe_normalize_var(&ge_even.x);
+ secp256k1_fe_normalize_var(&ge_quad.y);
+ secp256k1_fe_normalize_var(&ge_odd.y);
+ secp256k1_fe_normalize_var(&ge_even.y);
+
+ /* No infinity allowed. */
+ CHECK(!ge_quad.infinity);
+ CHECK(!ge_even.infinity);
+ CHECK(!ge_odd.infinity);
+
+ /* Check that the x coordinates check out. */
+ CHECK(secp256k1_fe_equal_var(&ge_quad.x, x));
+ CHECK(secp256k1_fe_equal_var(&ge_even.x, x));
+ CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));
+
+ /* Check that the Y coordinate result in ge_quad is a square. */
+ CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y));
+ secp256k1_fe_sqr(&tmp, &tmp);
+ CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y));
+
+ /* Check odd/even Y in ge_odd, ge_even. */
+ CHECK(secp256k1_fe_is_odd(&ge_odd.y));
+ CHECK(!secp256k1_fe_is_odd(&ge_even.y));
+ }
+}
+
+void run_group_decompress(void) {
+ int i;
+ for (i = 0; i < count * 4; i++) {
+ secp256k1_fe fe;
+ random_fe_test(&fe);
+ test_group_decompress(&fe);
+ }
}
/***** ECMULT TESTS *****/
void run_ecmult_chain(void) {
/* random starting point A (on the curve) */
- secp256k1_gej_t a = SECP256K1_GEJ_CONST(
+ secp256k1_gej a = SECP256K1_GEJ_CONST(
0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3,
0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004,
0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f,
0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f
);
/* two random initial factors xn and gn */
- secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST(
+ secp256k1_scalar xn = SECP256K1_SCALAR_CONST(
0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c,
0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407
);
- secp256k1_scalar_t gn = SECP256K1_SCALAR_CONST(
+ secp256k1_scalar gn = SECP256K1_SCALAR_CONST(
0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9,
0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de
);
/* two small multipliers to be applied to xn and gn in every iteration: */
- static const secp256k1_scalar_t xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337);
- static const secp256k1_scalar_t gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113);
+ static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337);
+ static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113);
/* accumulators with the resulting coefficients to A and G */
- secp256k1_scalar_t ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
- secp256k1_scalar_t ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+ secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
/* actual points */
- secp256k1_gej_t x = a;
- secp256k1_gej_t x2;
+ secp256k1_gej x;
+ secp256k1_gej x2;
int i;
/* the point being computed */
@@ -1131,7 +2151,7 @@ void run_ecmult_chain(void) {
/* verify */
if (i == 19999) {
/* expected result after 19999 iterations */
- secp256k1_gej_t rp = SECP256K1_GEJ_CONST(
+ secp256k1_gej rp = SECP256K1_GEJ_CONST(
0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE,
0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830,
0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D,
@@ -1139,30 +2159,32 @@ void run_ecmult_chain(void) {
);
secp256k1_gej_neg(&rp, &rp);
- secp256k1_gej_add_var(&rp, &rp, &x);
+ secp256k1_gej_add_var(&rp, &rp, &x, NULL);
CHECK(secp256k1_gej_is_infinity(&rp));
}
}
/* redo the computation, but directly with the resulting ae and ge coefficients: */
secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge);
secp256k1_gej_neg(&x2, &x2);
- secp256k1_gej_add_var(&x2, &x2, &x);
+ secp256k1_gej_add_var(&x2, &x2, &x, NULL);
CHECK(secp256k1_gej_is_infinity(&x2));
}
-void test_point_times_order(const secp256k1_gej_t *point) {
+void test_point_times_order(const secp256k1_gej *point) {
/* X * (point + G) + (order-X) * (pointer + G) = 0 */
- secp256k1_scalar_t x;
- secp256k1_scalar_t nx;
- secp256k1_gej_t res1, res2;
- secp256k1_ge_t res3;
+ secp256k1_scalar x;
+ secp256k1_scalar nx;
+ secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+ secp256k1_gej res1, res2;
+ secp256k1_ge res3;
unsigned char pub[65];
- int psize = 65;
+ size_t psize = 65;
random_scalar_order_test(&x);
secp256k1_scalar_negate(&nx, &x);
secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */
secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */
- secp256k1_gej_add_var(&res1, &res1, &res2);
+ secp256k1_gej_add_var(&res1, &res1, &res2, NULL);
CHECK(secp256k1_gej_is_infinity(&res1));
CHECK(secp256k1_gej_is_valid_var(&res1) == 0);
secp256k1_ge_set_gej(&res3, &res1);
@@ -1171,19 +2193,29 @@ void test_point_times_order(const secp256k1_gej_t *point) {
CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0);
psize = 65;
CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0);
+ /* check zero/one edge cases */
+ secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero);
+ secp256k1_ge_set_gej(&res3, &res1);
+ CHECK(secp256k1_ge_is_infinity(&res3));
+ secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero);
+ secp256k1_ge_set_gej(&res3, &res1);
+ ge_equals_gej(&res3, point);
+ secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one);
+ secp256k1_ge_set_gej(&res3, &res1);
+ ge_equals_ge(&res3, &secp256k1_ge_const_g);
}
void run_point_times_order(void) {
int i;
- secp256k1_fe_t x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2);
- static const secp256k1_fe_t xr = SECP256K1_FE_CONST(
+ secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2);
+ static const secp256k1_fe xr = SECP256K1_FE_CONST(
0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C,
0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45
);
for (i = 0; i < 500; i++) {
- secp256k1_ge_t p;
+ secp256k1_ge p;
if (secp256k1_ge_set_xo_var(&p, &x, 1)) {
- secp256k1_gej_t j;
+ secp256k1_gej j;
CHECK(secp256k1_ge_is_valid_var(&p));
secp256k1_gej_set_ge(&j, &p);
CHECK(secp256k1_gej_is_valid_var(&j));
@@ -1195,15 +2227,118 @@ void run_point_times_order(void) {
CHECK(secp256k1_fe_equal_var(&x, &xr));
}
-void test_wnaf(const secp256k1_scalar_t *number, int w) {
- secp256k1_scalar_t x, two, t;
+void ecmult_const_random_mult(void) {
+ /* random starting point A (on the curve) */
+ secp256k1_ge a = SECP256K1_GE_CONST(
+ 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b,
+ 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a,
+ 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c,
+ 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d
+ );
+ /* random initial factor xn */
+ secp256k1_scalar xn = SECP256K1_SCALAR_CONST(
+ 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327,
+ 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b
+ );
+ /* expected xn * A (from sage) */
+ secp256k1_ge expected_b = SECP256K1_GE_CONST(
+ 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd,
+ 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786,
+ 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f,
+ 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
+ );
+ secp256k1_gej b;
+ secp256k1_ecmult_const(&b, &a, &xn);
+
+ CHECK(secp256k1_ge_is_valid_var(&a));
+ ge_equals_gej(&expected_b, &b);
+}
+
+void ecmult_const_commutativity(void) {
+ secp256k1_scalar a;
+ secp256k1_scalar b;
+ secp256k1_gej res1;
+ secp256k1_gej res2;
+ secp256k1_ge mid1;
+ secp256k1_ge mid2;
+ random_scalar_order_test(&a);
+ random_scalar_order_test(&b);
+
+ secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
+ secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
+ secp256k1_ge_set_gej(&mid1, &res1);
+ secp256k1_ge_set_gej(&mid2, &res2);
+ secp256k1_ecmult_const(&res1, &mid1, &b);
+ secp256k1_ecmult_const(&res2, &mid2, &a);
+ secp256k1_ge_set_gej(&mid1, &res1);
+ secp256k1_ge_set_gej(&mid2, &res2);
+ ge_equals_ge(&mid1, &mid2);
+}
+
+void ecmult_const_mult_zero_one(void) {
+ secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+ secp256k1_scalar negone;
+ secp256k1_gej res1;
+ secp256k1_ge res2;
+ secp256k1_ge point;
+ secp256k1_scalar_negate(&negone, &one);
+
+ random_group_element_test(&point);
+ secp256k1_ecmult_const(&res1, &point, &zero);
+ secp256k1_ge_set_gej(&res2, &res1);
+ CHECK(secp256k1_ge_is_infinity(&res2));
+ secp256k1_ecmult_const(&res1, &point, &one);
+ secp256k1_ge_set_gej(&res2, &res1);
+ ge_equals_ge(&res2, &point);
+ secp256k1_ecmult_const(&res1, &point, &negone);
+ secp256k1_gej_neg(&res1, &res1);
+ secp256k1_ge_set_gej(&res2, &res1);
+ ge_equals_ge(&res2, &point);
+}
+
+void ecmult_const_chain_multiply(void) {
+ /* Check known result (randomly generated test problem from sage) */
+ const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST(
+ 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d,
+ 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b
+ );
+ const secp256k1_gej expected_point = SECP256K1_GEJ_CONST(
+ 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd,
+ 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f,
+ 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196,
+ 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435
+ );
+ secp256k1_gej point;
+ secp256k1_ge res;
+ int i;
+
+ secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g);
+ for (i = 0; i < 100; ++i) {
+ secp256k1_ge tmp;
+ secp256k1_ge_set_gej(&tmp, &point);
+ secp256k1_ecmult_const(&point, &tmp, &scalar);
+ }
+ secp256k1_ge_set_gej(&res, &point);
+ ge_equals_gej(&res, &expected_point);
+}
+
+void run_ecmult_const_tests(void) {
+ ecmult_const_mult_zero_one();
+ ecmult_const_random_mult();
+ ecmult_const_commutativity();
+ ecmult_const_chain_multiply();
+}
+
+void test_wnaf(const secp256k1_scalar *number, int w) {
+ secp256k1_scalar x, two, t;
int wnaf[256];
int zeroes = -1;
int i;
int bits;
secp256k1_scalar_set_int(&x, 0);
secp256k1_scalar_set_int(&two, 2);
- bits = secp256k1_ecmult_wnaf(wnaf, number, w);
+ bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w);
CHECK(bits <= 256);
for (i = bits-1; i >= 0; i--) {
int v = wnaf[i];
@@ -1229,20 +2364,95 @@ void test_wnaf(const secp256k1_scalar_t *number, int w) {
CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */
}
+void test_constant_wnaf_negate(const secp256k1_scalar *number) {
+ secp256k1_scalar neg1 = *number;
+ secp256k1_scalar neg2 = *number;
+ int sign1 = 1;
+ int sign2 = 1;
+
+ if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) {
+ secp256k1_scalar_negate(&neg1, &neg1);
+ sign1 = -1;
+ }
+ sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2));
+ CHECK(sign1 == sign2);
+ CHECK(secp256k1_scalar_eq(&neg1, &neg2));
+}
+
+void test_constant_wnaf(const secp256k1_scalar *number, int w) {
+ secp256k1_scalar x, shift;
+ int wnaf[256] = {0};
+ int i;
+#ifdef USE_ENDOMORPHISM
+ int skew;
+#endif
+ secp256k1_scalar num = *number;
+
+ secp256k1_scalar_set_int(&x, 0);
+ secp256k1_scalar_set_int(&shift, 1 << w);
+ /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */
+#ifdef USE_ENDOMORPHISM
+ for (i = 0; i < 16; ++i) {
+ secp256k1_scalar_shr_int(&num, 8);
+ }
+ skew = secp256k1_wnaf_const(wnaf, num, w);
+#else
+ secp256k1_wnaf_const(wnaf, num, w);
+#endif
+
+ for (i = WNAF_SIZE(w); i >= 0; --i) {
+ secp256k1_scalar t;
+ int v = wnaf[i];
+ CHECK(v != 0); /* check nonzero */
+ CHECK(v & 1); /* check parity */
+ CHECK(v > -(1 << w)); /* check range above */
+ CHECK(v < (1 << w)); /* check range below */
+
+ secp256k1_scalar_mul(&x, &x, &shift);
+ if (v >= 0) {
+ secp256k1_scalar_set_int(&t, v);
+ } else {
+ secp256k1_scalar_set_int(&t, -v);
+ secp256k1_scalar_negate(&t, &t);
+ }
+ secp256k1_scalar_add(&x, &x, &t);
+ }
+#ifdef USE_ENDOMORPHISM
+ /* Skew num because when encoding 128-bit numbers as odd we use an offset */
+ secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
+#endif
+ CHECK(secp256k1_scalar_eq(&x, &num));
+}
+
void run_wnaf(void) {
int i;
- secp256k1_scalar_t n;
+ secp256k1_scalar n = {{0}};
+
+ /* Sanity check: 1 and 2 are the smallest odd and even numbers and should
+ * have easier-to-diagnose failure modes */
+ n.d[0] = 1;
+ test_constant_wnaf(&n, 4);
+ n.d[0] = 2;
+ test_constant_wnaf(&n, 4);
+ /* Random tests */
for (i = 0; i < count; i++) {
random_scalar_order(&n);
test_wnaf(&n, 4+(i%10));
+ test_constant_wnaf_negate(&n);
+ test_constant_wnaf(&n, 4 + (i % 10));
}
+ secp256k1_scalar_set_int(&n, 0);
+ CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1);
+ CHECK(secp256k1_scalar_is_zero(&n));
+ CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1);
+ CHECK(secp256k1_scalar_is_zero(&n));
}
void test_ecmult_constants(void) {
/* Test ecmult_gen() for [0..36) and [order-36..0). */
- secp256k1_scalar_t x;
- secp256k1_gej_t r;
- secp256k1_ge_t ng;
+ secp256k1_scalar x;
+ secp256k1_gej r;
+ secp256k1_ge ng;
int i;
int j;
secp256k1_ge_neg(&ng, &secp256k1_ge_const_g);
@@ -1276,14 +2486,14 @@ void run_ecmult_constants(void) {
}
void test_ecmult_gen_blind(void) {
- /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */
- secp256k1_scalar_t key;
- secp256k1_scalar_t b;
+ /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */
+ secp256k1_scalar key;
+ secp256k1_scalar b;
unsigned char seed32[32];
- secp256k1_gej_t pgej;
- secp256k1_gej_t pgej2;
- secp256k1_gej_t i;
- secp256k1_ge_t pge;
+ secp256k1_gej pgej;
+ secp256k1_gej pgej2;
+ secp256k1_gej i;
+ secp256k1_ge pge;
random_scalar_order_test(&key);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key);
secp256k1_rand256(seed32);
@@ -1300,8 +2510,8 @@ void test_ecmult_gen_blind(void) {
void test_ecmult_gen_blind_reset(void) {
/* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */
- secp256k1_scalar_t b;
- secp256k1_gej_t initial;
+ secp256k1_scalar b;
+ secp256k1_gej initial;
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);
b = ctx->ecmult_gen_ctx.blind;
initial = ctx->ecmult_gen_ctx.initial;
@@ -1318,35 +2528,702 @@ void run_ecmult_gen_blind(void) {
}
}
+#ifdef USE_ENDOMORPHISM
+/***** ENDOMORPHISH TESTS *****/
+void test_scalar_split(void) {
+ secp256k1_scalar full;
+ secp256k1_scalar s1, slam;
+ const unsigned char zero[32] = {0};
+ unsigned char tmp[32];
+
+ random_scalar_order_test(&full);
+ secp256k1_scalar_split_lambda(&s1, &slam, &full);
+
+ /* check that both are <= 128 bits in size */
+ if (secp256k1_scalar_is_high(&s1)) {
+ secp256k1_scalar_negate(&s1, &s1);
+ }
+ if (secp256k1_scalar_is_high(&slam)) {
+ secp256k1_scalar_negate(&slam, &slam);
+ }
+
+ secp256k1_scalar_get_b32(tmp, &s1);
+ CHECK(memcmp(zero, tmp, 16) == 0);
+ secp256k1_scalar_get_b32(tmp, &slam);
+ CHECK(memcmp(zero, tmp, 16) == 0);
+}
+
+void run_endomorphism_tests(void) {
+ test_scalar_split();
+}
+#endif
+
+void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) {
+ unsigned char pubkeyc[65];
+ secp256k1_pubkey pubkey;
+ secp256k1_ge ge;
+ size_t pubkeyclen;
+ int32_t ecount;
+ ecount = 0;
+ secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) {
+ /* Smaller sizes are tested exhaustively elsewhere. */
+ int32_t i;
+ memcpy(&pubkeyc[1], input, 64);
+ VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen);
+ for (i = 0; i < 256; i++) {
+ /* Try all type bytes. */
+ int xpass;
+ int ypass;
+ int ysign;
+ pubkeyc[0] = i;
+ /* What sign does this point have? */
+ ysign = (input[63] & 1) + 2;
+ /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */
+ xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2);
+ /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */
+ ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) &&
+ ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65));
+ if (xpass || ypass) {
+ /* These cases must parse. */
+ unsigned char pubkeyo[65];
+ size_t outl;
+ memset(&pubkey, 0, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ ecount = 0;
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ outl = 65;
+ VG_UNDEF(pubkeyo, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+ VG_CHECK(pubkeyo, outl);
+ CHECK(outl == 33);
+ CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0);
+ CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0]));
+ if (ypass) {
+ /* This test isn't always done because we decode with alternative signs, so the y won't match. */
+ CHECK(pubkeyo[0] == ysign);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1);
+ memset(&pubkey, 0, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ secp256k1_pubkey_save(&pubkey, &ge);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ outl = 65;
+ VG_UNDEF(pubkeyo, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
+ VG_CHECK(pubkeyo, outl);
+ CHECK(outl == 65);
+ CHECK(pubkeyo[0] == 4);
+ CHECK(memcmp(&pubkeyo[1], input, 64) == 0);
+ }
+ CHECK(ecount == 0);
+ } else {
+ /* These cases must fail to parse. */
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ }
+ }
+ }
+ secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+}
+
+void run_ec_pubkey_parse_test(void) {
+#define SECP256K1_EC_PARSE_TEST_NVALID (12)
+ const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = {
+ {
+ /* Point with leading and trailing zeros in x and y serialization. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83,
+ 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00
+ },
+ {
+ /* Point with x equal to a 3rd root of unity.*/
+ 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9,
+ 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee,
+ 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14,
+ 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee,
+ },
+ {
+ /* Point with largest x. (1/2) */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c,
+ 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e,
+ 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d,
+ },
+ {
+ /* Point with largest x. (2/2) */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c,
+ 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1,
+ 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2,
+ },
+ {
+ /* Point with smallest x. (1/2) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14,
+ 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee,
+ },
+ {
+ /* Point with smallest x. (2/2) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb,
+ 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41,
+ },
+ {
+ /* Point with largest y. (1/3) */
+ 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6,
+ 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,
+ },
+ {
+ /* Point with largest y. (2/3) */
+ 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c,
+ 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,
+ },
+ {
+ /* Point with largest y. (3/3) */
+ 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc,
+ 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,
+ },
+ {
+ /* Point with smallest y. (1/3) */
+ 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6,
+ 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ },
+ {
+ /* Point with smallest y. (2/3) */
+ 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c,
+ 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ },
+ {
+ /* Point with smallest y. (3/3) */
+ 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc,
+ 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+ }
+ };
+#define SECP256K1_EC_PARSE_TEST_NXVALID (4)
+ const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = {
+ {
+ /* Valid if y overflow ignored (y = 1 mod p). (1/3) */
+ 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6,
+ 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,
+ },
+ {
+ /* Valid if y overflow ignored (y = 1 mod p). (2/3) */
+ 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c,
+ 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,
+ },
+ {
+ /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/
+ 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc,
+ 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,
+ },
+ {
+ /* x on curve, y is from y^2 = x^3 + 8. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
+ }
+ };
+#define SECP256K1_EC_PARSE_TEST_NINVALID (7)
+ const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = {
+ {
+ /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */
+ 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c,
+ 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ },
+ {
+ /* Valid if x overflow ignored (x = 1 mod p). */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,
+ 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14,
+ 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee,
+ },
+ {
+ /* Valid if x overflow ignored (x = 1 mod p). */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,
+ 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb,
+ 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41,
+ },
+ {
+ /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,
+ 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f,
+ 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28,
+ },
+ {
+ /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,
+ 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0,
+ 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07,
+ },
+ {
+ /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d,
+ 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc,
+ },
+ {
+ /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2,
+ 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53
+ }
+ };
+ const unsigned char pubkeyc[66] = {
+ /* Serialization of G. */
+ 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B,
+ 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17,
+ 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08,
+ 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4,
+ 0xB8, 0x00
+ };
+ unsigned char sout[65];
+ unsigned char shortkey[2];
+ secp256k1_ge ge;
+ secp256k1_pubkey pubkey;
+ size_t len;
+ int32_t i;
+ int32_t ecount;
+ int32_t ecount2;
+ ecount = 0;
+ /* Nothing should be reading this far into pubkeyc. */
+ VG_UNDEF(&pubkeyc[65], 1);
+ secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ /* Zero length claimed, fail, zeroize, no illegal arg error. */
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(shortkey, 2);
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ /* Length one claimed, fail, zeroize, no illegal arg error. */
+ for (i = 0; i < 256 ; i++) {
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ shortkey[0] = i;
+ VG_UNDEF(&shortkey[1], 1);
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ }
+ /* Length two claimed, fail, zeroize, no illegal arg error. */
+ for (i = 0; i < 65536 ; i++) {
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ shortkey[0] = i & 255;
+ shortkey[1] = i >> 8;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ }
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */
+ CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0);
+ CHECK(ecount == 2);
+ /* NULL input string. Illegal arg and zeroize output. */
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 1);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 2);
+ /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */
+ memset(&pubkey, 0xfe, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);
+ CHECK(ecount == 1);
+ /* Valid parse. */
+ memset(&pubkey, 0, sizeof(pubkey));
+ ecount = 0;
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(ecount == 0);
+ VG_UNDEF(&ge, sizeof(ge));
+ CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1);
+ VG_CHECK(&ge.x, sizeof(ge.x));
+ VG_CHECK(&ge.y, sizeof(ge.y));
+ VG_CHECK(&ge.infinity, sizeof(ge.infinity));
+ ge_equals_ge(&secp256k1_ge_const_g, &ge);
+ CHECK(ecount == 0);
+ /* secp256k1_ec_pubkey_serialize illegal args. */
+ ecount = 0;
+ len = 65;
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
+ CHECK(ecount == 1);
+ CHECK(len == 0);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
+ CHECK(ecount == 2);
+ len = 65;
+ VG_UNDEF(sout, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0);
+ VG_CHECK(sout, 65);
+ CHECK(ecount == 3);
+ CHECK(len == 0);
+ len = 65;
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0);
+ CHECK(ecount == 4);
+ CHECK(len == 0);
+ len = 65;
+ VG_UNDEF(sout, 65);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
+ VG_CHECK(sout, 65);
+ CHECK(ecount == 4);
+ CHECK(len == 65);
+ /* Multiple illegal args. Should still set arg error only once. */
+ ecount = 0;
+ ecount2 = 11;
+ CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0);
+ CHECK(ecount == 1);
+ /* Does the illegal arg callback actually change the behavior? */
+ secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2);
+ CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0);
+ CHECK(ecount == 1);
+ CHECK(ecount2 == 10);
+ secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+ /* Try a bunch of prefabbed points with all possible encodings. */
+ for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) {
+ ec_pubkey_parse_pointtest(valid[i], 1, 1);
+ }
+ for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) {
+ ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0);
+ }
+ for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) {
+ ec_pubkey_parse_pointtest(invalid[i], 0, 0);
+ }
+}
+
+void run_eckey_edge_case_test(void) {
+ const unsigned char orderc[32] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+ 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
+ };
+ const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00};
+ unsigned char ctmp[33];
+ unsigned char ctmp2[33];
+ secp256k1_pubkey pubkey;
+ secp256k1_pubkey pubkey2;
+ secp256k1_pubkey pubkey_one;
+ secp256k1_pubkey pubkey_negone;
+ const secp256k1_pubkey *pubkeys[3];
+ size_t len;
+ int32_t ecount;
+ /* Group order is too large, reject. */
+ CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0);
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ /* Maximum value is too large, reject. */
+ memset(ctmp, 255, 32);
+ CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+ memset(&pubkey, 1, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ /* Zero is too small, reject. */
+ memset(ctmp, 0, 32);
+ CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+ memset(&pubkey, 1, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ /* One must be accepted. */
+ ctmp[31] = 0x01;
+ CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+ memset(&pubkey, 0, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+ pubkey_one = pubkey;
+ /* Group order + 1 is too large, reject. */
+ memcpy(ctmp, orderc, 32);
+ ctmp[31] = 0x42;
+ CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+ memset(&pubkey, 1, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ /* -1 must be accepted. */
+ ctmp[31] = 0x40;
+ CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+ memset(&pubkey, 0, sizeof(pubkey));
+ VG_UNDEF(&pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
+ VG_CHECK(&pubkey, sizeof(pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+ pubkey_negone = pubkey;
+ /* Tweak of zero leaves the value changed. */
+ memset(ctmp2, 0, 32);
+ CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1);
+ CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);
+ memcpy(&pubkey2, &pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+ CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
+ /* Multiply tweak of zero zeroizes the output. */
+ CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0);
+ CHECK(memcmp(zeros, ctmp, 32) == 0);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);
+ CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+ memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+ /* Overflowing key tweak zeroizes. */
+ memcpy(ctmp, orderc, 32);
+ ctmp[31] = 0x40;
+ CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0);
+ CHECK(memcmp(zeros, ctmp, 32) == 0);
+ memcpy(ctmp, orderc, 32);
+ ctmp[31] = 0x40;
+ CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0);
+ CHECK(memcmp(zeros, ctmp, 32) == 0);
+ memcpy(ctmp, orderc, 32);
+ ctmp[31] = 0x40;
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);
+ CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+ memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);
+ CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+ memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+ /* Private key tweaks results in a key of zero. */
+ ctmp2[31] = 1;
+ CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0);
+ CHECK(memcmp(zeros, ctmp2, 32) == 0);
+ ctmp2[31] = 1;
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
+ CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+ memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+ /* Tweak computation wraps and results in a key of 1. */
+ ctmp2[31] = 2;
+ CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1);
+ CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1);
+ ctmp2[31] = 2;
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+ ctmp2[31] = 1;
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1);
+ CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
+ /* Tweak mul * 2 = 1+1. */
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
+ ctmp2[31] = 2;
+ CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1);
+ CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
+ /* Test argument errors. */
+ ecount = 0;
+ secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ CHECK(ecount == 0);
+ /* Zeroize pubkey on parse error. */
+ memset(&pubkey, 0, 32);
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
+ CHECK(ecount == 1);
+ CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
+ memcpy(&pubkey, &pubkey2, sizeof(pubkey));
+ memset(&pubkey2, 0, 32);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0);
+ CHECK(ecount == 2);
+ CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0);
+ /* Plain argument errors. */
+ ecount = 0;
+ CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);
+ CHECK(ecount == 0);
+ CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0);
+ CHECK(ecount == 1);
+ ecount = 0;
+ memset(ctmp2, 0, 32);
+ ctmp2[31] = 4;
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0);
+ CHECK(ecount == 2);
+ ecount = 0;
+ memset(ctmp2, 0, 32);
+ ctmp2[31] = 4;
+ CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0);
+ CHECK(ecount == 2);
+ ecount = 0;
+ memset(ctmp2, 0, 32);
+ CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0);
+ CHECK(ecount == 2);
+ ecount = 0;
+ memset(ctmp2, 0, 32);
+ ctmp2[31] = 1;
+ CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0);
+ CHECK(ecount == 2);
+ ecount = 0;
+ CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0);
+ CHECK(ecount == 1);
+ memset(&pubkey, 1, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ /* secp256k1_ec_pubkey_combine tests. */
+ ecount = 0;
+ pubkeys[0] = &pubkey_one;
+ VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *));
+ VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *));
+ VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *));
+ memset(&pubkey, 255, sizeof(secp256k1_pubkey));
+ VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0);
+ VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0);
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ CHECK(ecount == 2);
+ memset(&pubkey, 255, sizeof(secp256k1_pubkey));
+ VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0);
+ VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ CHECK(ecount == 3);
+ pubkeys[0] = &pubkey_negone;
+ memset(&pubkey, 255, sizeof(secp256k1_pubkey));
+ VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1);
+ VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+ CHECK(ecount == 3);
+ len = 33;
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(memcmp(ctmp, ctmp2, 33) == 0);
+ /* Result is infinity. */
+ pubkeys[0] = &pubkey_one;
+ pubkeys[1] = &pubkey_negone;
+ memset(&pubkey, 255, sizeof(secp256k1_pubkey));
+ VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0);
+ VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
+ CHECK(ecount == 3);
+ /* Passes through infinity but comes out one. */
+ pubkeys[2] = &pubkey_one;
+ memset(&pubkey, 255, sizeof(secp256k1_pubkey));
+ VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1);
+ VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+ CHECK(ecount == 3);
+ len = 33;
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1);
+ CHECK(memcmp(ctmp, ctmp2, 33) == 0);
+ /* Adds to two. */
+ pubkeys[1] = &pubkey_one;
+ memset(&pubkey, 255, sizeof(secp256k1_pubkey));
+ VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1);
+ VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));
+ CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
+ CHECK(ecount == 3);
+ secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
+}
-void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) {
- secp256k1_scalar_t nonce;
+void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
+ secp256k1_scalar nonce;
do {
random_scalar_order_test(&nonce);
- } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid));
+ } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid));
}
void test_ecdsa_sign_verify(void) {
- secp256k1_gej_t pubj;
- secp256k1_ge_t pub;
- secp256k1_scalar_t one;
- secp256k1_scalar_t msg, key;
- secp256k1_ecdsa_sig_t sig;
+ secp256k1_gej pubj;
+ secp256k1_ge pub;
+ secp256k1_scalar one;
+ secp256k1_scalar msg, key;
+ secp256k1_scalar sigr, sigs;
int recid;
int getrec;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj);
- getrec = secp256k1_rand32()&1;
- random_sign(&sig, &key, &msg, getrec?&recid:NULL);
+ getrec = secp256k1_rand_bits(1);
+ random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL);
if (getrec) {
CHECK(recid >= 0 && recid < 4);
}
- CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));
secp256k1_scalar_set_int(&one, 1);
secp256k1_scalar_add(&msg, &msg, &one);
- CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg));
+ CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));
}
void run_ecdsa_sign_verify(void) {
@@ -1357,22 +3234,23 @@ void run_ecdsa_sign_verify(void) {
}
/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */
-static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
+static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
(void)msg32;
(void)key32;
+ (void)algo16;
memcpy(nonce32, data, 32);
return (counter == 0);
}
-static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
+static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
/* Dummy nonce generator that has a fatal error on the first counter value. */
if (counter == 0) {
return 0;
}
- return nonce_function_rfc6979(nonce32, msg32, key32, counter - 1, data);
+ return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1);
}
-static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
+static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
/* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */
if (counter < 3) {
memset(nonce32, counter==0 ? 0 : 255, 32);
@@ -1394,17 +3272,17 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
}
return 1;
}
- /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */
+ /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */
/* If someone does fine a case where it retries for secp256k1, we'd like to know. */
if (counter > 5) {
return 0;
}
- return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data);
+ return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5);
}
-int is_empty_compact_signature(const unsigned char *sig64) {
- static const unsigned char res[64] = {0};
- return memcmp(sig64, res, 64) == 0;
+int is_empty_signature(const secp256k1_ecdsa_signature *sig) {
+ static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0};
+ return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0;
}
void test_ecdsa_end_to_end(void) {
@@ -1412,26 +3290,19 @@ void test_ecdsa_end_to_end(void) {
unsigned char privkey[32];
unsigned char message[32];
unsigned char privkey2[32];
- unsigned char csignature[64];
- unsigned char signature[72];
- unsigned char signature2[72];
- unsigned char signature3[72];
- unsigned char signature4[72];
- unsigned char pubkey[65];
- unsigned char recpubkey[65];
+ secp256k1_ecdsa_signature signature[6];
+ secp256k1_scalar r, s;
+ unsigned char sig[74];
+ size_t siglen = 74;
+ unsigned char pubkeyc[65];
+ size_t pubkeyclen = 65;
+ secp256k1_pubkey pubkey;
unsigned char seckey[300];
- int signaturelen = 72;
- int signaturelen2 = 72;
- int signaturelen3 = 72;
- int signaturelen4 = 72;
- int recid = 0;
- int recpubkeylen = 0;
- int pubkeylen = 65;
- int seckeylen = 300;
+ size_t seckeylen = 300;
/* Generate a random key and message. */
{
- secp256k1_scalar_t msg, key;
+ secp256k1_scalar msg, key;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(privkey, &key);
@@ -1440,117 +3311,120 @@ void test_ecdsa_end_to_end(void) {
/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1);
- if (secp256k1_rand32() & 1) {
- CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen));
- }
- CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen));
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+ /* Verify exporting and importing public key. */
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED));
+ memset(&pubkey, 0, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
/* Verify private key import and export. */
- CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1);
- CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1);
+ CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
+ CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
CHECK(memcmp(privkey, privkey2, 32) == 0);
/* Optionally tweak the keys using addition. */
- if (secp256k1_rand32() % 3 == 0) {
+ if (secp256k1_rand_int(3) == 0) {
int ret1;
int ret2;
unsigned char rnd[32];
- unsigned char pubkey2[65];
- int pubkeylen2 = 65;
+ secp256k1_pubkey pubkey2;
secp256k1_rand256_test(rnd);
ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd);
- ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd);
+ ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd);
CHECK(ret1 == ret2);
if (ret1 == 0) {
return;
}
- CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1);
- CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
+ CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
}
/* Optionally tweak the keys using multiplication. */
- if (secp256k1_rand32() % 3 == 0) {
+ if (secp256k1_rand_int(3) == 0) {
int ret1;
int ret2;
unsigned char rnd[32];
- unsigned char pubkey2[65];
- int pubkeylen2 = 65;
+ secp256k1_pubkey pubkey2;
secp256k1_rand256_test(rnd);
ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd);
- ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd);
+ ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd);
CHECK(ret1 == ret2);
if (ret1 == 0) {
return;
}
- CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1);
- CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
+ CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
}
/* Sign. */
- CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1);
- CHECK(signaturelen > 0);
- CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1);
- CHECK(signaturelen2 > 0);
+ CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1);
extra[31] = 1;
- CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1);
- CHECK(signaturelen3 > 0);
+ CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1);
extra[31] = 0;
extra[0] = 1;
- CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1);
- CHECK(signaturelen3 > 0);
- CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0));
- CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0));
- CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0));
- CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0));
- CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0));
- CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0));
+ CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1);
+ CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0);
+ CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0);
+ CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0);
+ CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0);
+ CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0);
+ CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0);
+ CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0);
/* Verify. */
- CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1);
- /* Destroy signature and verify again. */
- signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255);
- CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1);
-
- /* Compact sign. */
- CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1);
- CHECK(!is_empty_compact_signature(csignature));
- /* Recover. */
- CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1);
- CHECK(recpubkeylen == pubkeylen);
- CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0);
- /* Destroy signature and verify again. */
- csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
- CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 ||
- memcmp(pubkey, recpubkey, pubkeylen) != 0);
- CHECK(recpubkeylen == pubkeylen);
-
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1);
+ /* Test lower-S form, malleate, verify and fail, test again, malleate again */
+ CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0]));
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]);
+ secp256k1_scalar_negate(&s, &s);
+ secp256k1_ecdsa_signature_save(&signature[5], &r, &s);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0);
+ CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
+ CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));
+ CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
+ CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);
+ secp256k1_scalar_negate(&s, &s);
+ secp256k1_ecdsa_signature_save(&signature[5], &r, &s);
+ CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);
+ CHECK(memcmp(&signature[5], &signature[0], 64) == 0);
+
+ /* Serialize/parse DER and verify again */
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
+ memset(&signature[0], 0, sizeof(signature[0]));
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);
+ /* Serialize/destroy/parse DER and verify again. */
+ siglen = 74;
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
+ sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 ||
+ secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0);
}
void test_random_pubkeys(void) {
- secp256k1_ge_t elem;
- secp256k1_ge_t elem2;
+ secp256k1_ge elem;
+ secp256k1_ge elem2;
unsigned char in[65];
/* Generate some randomly sized pubkeys. */
- uint32_t r = secp256k1_rand32();
- int len = (r & 3) == 0 ? 65 : 33;
- r>>=2;
- if ((r & 3) == 0) {
- len = (r & 252) >> 3;
+ size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33;
+ if (secp256k1_rand_bits(2) == 0) {
+ len = secp256k1_rand_bits(6);
}
- r>>=8;
if (len == 65) {
- in[0] = (r & 2) ? 4 : (r & 1? 6 : 7);
+ in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7);
} else {
- in[0] = (r & 1) ? 2 : 3;
+ in[0] = secp256k1_rand_bits(1) ? 2 : 3;
}
- r>>=2;
- if ((r & 7) == 0) {
- in[0] = (r & 2040) >> 3;
+ if (secp256k1_rand_bits(3) == 0) {
+ in[0] = secp256k1_rand_bits(8);
}
- r>>=11;
if (len > 1) {
secp256k1_rand256(&in[1]);
}
@@ -1561,7 +3435,7 @@ void test_random_pubkeys(void) {
unsigned char out[65];
unsigned char firstb;
int res;
- int size = len;
+ size_t size = len;
firstb = in[0];
/* If the pubkey can be parsed, it should round-trip... */
CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33));
@@ -1577,7 +3451,7 @@ void test_random_pubkeys(void) {
CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size));
ge_equals_ge(&elem,&elem2);
/* Check that the X9.62 hybrid type is checked. */
- in[0] = (r & 1) ? 6 : 7;
+ in[0] = secp256k1_rand_bits(1) ? 6 : 7;
res = secp256k1_eckey_pubkey_parse(&elem2, in, size);
if (firstb == 2 || firstb == 3) {
if (in[0] == firstb + 4) {
@@ -1608,185 +3482,505 @@ void run_ecdsa_end_to_end(void) {
}
}
+int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
+ static const unsigned char zeroes[32] = {0};
+ static const unsigned char max_scalar[32] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
+ 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40
+ };
+
+ int ret = 0;
+
+ secp256k1_ecdsa_signature sig_der;
+ unsigned char roundtrip_der[2048];
+ unsigned char compact_der[64];
+ size_t len_der = 2048;
+ int parsed_der = 0, valid_der = 0, roundtrips_der = 0;
+
+ secp256k1_ecdsa_signature sig_der_lax;
+ unsigned char roundtrip_der_lax[2048];
+ unsigned char compact_der_lax[64];
+ size_t len_der_lax = 2048;
+ int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0;
+
+#ifdef ENABLE_OPENSSL_TESTS
+ ECDSA_SIG *sig_openssl;
+ const unsigned char *sigptr;
+ unsigned char roundtrip_openssl[2048];
+ int len_openssl = 2048;
+ int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0;
+#endif
+
+ parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen);
+ if (parsed_der) {
+ ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0;
+ valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0);
+ }
+ if (valid_der) {
+ ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1;
+ roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0;
+ }
+
+ parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen);
+ if (parsed_der_lax) {
+ ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10;
+ valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0);
+ }
+ if (valid_der_lax) {
+ ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11;
+ roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0;
+ }
+
+ if (certainly_der) {
+ ret |= (!parsed_der) << 2;
+ }
+ if (certainly_not_der) {
+ ret |= (parsed_der) << 17;
+ }
+ if (valid_der) {
+ ret |= (!roundtrips_der) << 3;
+ }
+
+ if (valid_der) {
+ ret |= (!roundtrips_der_lax) << 12;
+ ret |= (len_der != len_der_lax) << 13;
+ ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14;
+ }
+ ret |= (roundtrips_der != roundtrips_der_lax) << 15;
+ if (parsed_der) {
+ ret |= (!parsed_der_lax) << 16;
+ }
+
+#ifdef ENABLE_OPENSSL_TESTS
+ sig_openssl = ECDSA_SIG_new();
+ sigptr = sig;
+ parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL);
+ if (parsed_openssl) {
+ valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256;
+ if (valid_openssl) {
+ unsigned char tmp[32] = {0};
+ BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r));
+ valid_openssl = memcmp(tmp, max_scalar, 32) < 0;
+ }
+ if (valid_openssl) {
+ unsigned char tmp[32] = {0};
+ BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s));
+ valid_openssl = memcmp(tmp, max_scalar, 32) < 0;
+ }
+ }
+ len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL);
+ if (len_openssl <= 2048) {
+ unsigned char *ptr = roundtrip_openssl;
+ CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl);
+ roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0);
+ } else {
+ len_openssl = 0;
+ }
+ ECDSA_SIG_free(sig_openssl);
+
+ ret |= (parsed_der && !parsed_openssl) << 4;
+ ret |= (valid_der && !valid_openssl) << 5;
+ ret |= (roundtrips_openssl && !parsed_der) << 6;
+ ret |= (roundtrips_der != roundtrips_openssl) << 7;
+ if (roundtrips_openssl) {
+ ret |= (len_der != (size_t)len_openssl) << 8;
+ ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9;
+ }
+#endif
+ return ret;
+}
+
+static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) {
+ size_t i;
+ for (i = 0; i < ptrlen; i++) {
+ int shift = ptrlen - 1 - i;
+ if (shift >= 4) {
+ ptr[i] = 0;
+ } else {
+ ptr[i] = (val >> shift) & 0xFF;
+ }
+ }
+}
+
+static void damage_array(unsigned char *sig, size_t *len) {
+ int pos;
+ int action = secp256k1_rand_bits(3);
+ if (action < 1) {
+ /* Delete a byte. */
+ pos = secp256k1_rand_int(*len);
+ memmove(sig + pos, sig + pos + 1, *len - pos - 1);
+ (*len)--;
+ return;
+ } else if (action < 2) {
+ /* Insert a byte. */
+ pos = secp256k1_rand_int(1 + *len);
+ memmove(sig + pos + 1, sig + pos, *len - pos);
+ sig[pos] = secp256k1_rand_bits(8);
+ (*len)++;
+ return;
+ } else if (action < 4) {
+ /* Modify a byte. */
+ sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255);
+ return;
+ } else { /* action < 8 */
+ /* Modify a bit. */
+ sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3);
+ return;
+ }
+}
+
+static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) {
+ int der;
+ int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2];
+ size_t tlen, elen, glen;
+ int indet;
+ int n;
+
+ *len = 0;
+ der = secp256k1_rand_bits(2) == 0;
+ *certainly_der = der;
+ *certainly_not_der = 0;
+ indet = der ? 0 : secp256k1_rand_int(10) == 0;
+
+ for (n = 0; n < 2; n++) {
+ /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */
+ nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0);
+ /* The length of the number in bytes (the first byte of which will always be nonzero) */
+ nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8;
+ CHECK(nlen[n] <= 232);
+ /* The top bit of the number. */
+ nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1));
+ /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */
+ nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127));
+ /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */
+ nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8);
+ if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) {
+ *certainly_not_der = 1;
+ }
+ CHECK(nlen[n] + nzlen[n] <= 300);
+ /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */
+ nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2);
+ if (!der) {
+ /* nlenlen[n] max 127 bytes */
+ int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256;
+ nlenlen[n] += add;
+ if (add != 0) {
+ *certainly_not_der = 1;
+ }
+ }
+ CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427);
+ }
+
+ /* The total length of the data to go, so far */
+ tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1];
+ CHECK(tlen <= 856);
+
+ /* The length of the garbage inside the tuple. */
+ elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8;
+ if (elen != 0) {
+ *certainly_not_der = 1;
+ }
+ tlen += elen;
+ CHECK(tlen <= 980);
+
+ /* The length of the garbage after the end of the tuple. */
+ glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8;
+ if (glen != 0) {
+ *certainly_not_der = 1;
+ }
+ CHECK(tlen + glen <= 990);
+
+ /* Write the tuple header. */
+ sig[(*len)++] = 0x30;
+ if (indet) {
+ /* Indeterminate length */
+ sig[(*len)++] = 0x80;
+ *certainly_not_der = 1;
+ } else {
+ int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2);
+ if (!der) {
+ int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256;
+ tlenlen += add;
+ if (add != 0) {
+ *certainly_not_der = 1;
+ }
+ }
+ if (tlenlen == 0) {
+ /* Short length notation */
+ sig[(*len)++] = tlen;
+ } else {
+ /* Long length notation */
+ sig[(*len)++] = 128 + tlenlen;
+ assign_big_endian(sig + *len, tlenlen, tlen);
+ *len += tlenlen;
+ }
+ tlen += tlenlen;
+ }
+ tlen += 2;
+ CHECK(tlen + glen <= 1119);
+
+ for (n = 0; n < 2; n++) {
+ /* Write the integer header. */
+ sig[(*len)++] = 0x02;
+ if (nlenlen[n] == 0) {
+ /* Short length notation */
+ sig[(*len)++] = nlen[n] + nzlen[n];
+ } else {
+ /* Long length notation. */
+ sig[(*len)++] = 128 + nlenlen[n];
+ assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]);
+ *len += nlenlen[n];
+ }
+ /* Write zero padding */
+ while (nzlen[n] > 0) {
+ sig[(*len)++] = 0x00;
+ nzlen[n]--;
+ }
+ if (nlen[n] == 32 && !nlow[n]) {
+ /* Special extra 16 0xFF bytes in "high" 32-byte numbers */
+ int i;
+ for (i = 0; i < 16; i++) {
+ sig[(*len)++] = 0xFF;
+ }
+ nlen[n] -= 16;
+ }
+ /* Write first byte of number */
+ if (nlen[n] > 0) {
+ sig[(*len)++] = nhbyte[n];
+ nlen[n]--;
+ }
+ /* Generate remaining random bytes of number */
+ secp256k1_rand_bytes_test(sig + *len, nlen[n]);
+ *len += nlen[n];
+ nlen[n] = 0;
+ }
+
+ /* Generate random garbage inside tuple. */
+ secp256k1_rand_bytes_test(sig + *len, elen);
+ *len += elen;
+
+ /* Generate end-of-contents bytes. */
+ if (indet) {
+ sig[(*len)++] = 0;
+ sig[(*len)++] = 0;
+ tlen += 2;
+ }
+ CHECK(tlen + glen <= 1121);
+
+ /* Generate random garbage outside tuple. */
+ secp256k1_rand_bytes_test(sig + *len, glen);
+ *len += glen;
+ tlen += glen;
+ CHECK(tlen <= 1121);
+ CHECK(tlen == *len);
+}
+
+void run_ecdsa_der_parse(void) {
+ int i,j;
+ for (i = 0; i < 200 * count; i++) {
+ unsigned char buffer[2048];
+ size_t buflen = 0;
+ int certainly_der = 0;
+ int certainly_not_der = 0;
+ random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der);
+ for (j = 0; j < 16; j++) {
+ int ret = 0;
+ if (j > 0) {
+ damage_array(buffer, &buflen);
+ /* We don't know anything anymore about the DERness of the result */
+ certainly_der = 0;
+ certainly_not_der = 0;
+ }
+ ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der);
+ if (ret != 0) {
+ size_t k;
+ fprintf(stderr, "Failure %x on ", ret);
+ for (k = 0; k < buflen; k++) {
+ fprintf(stderr, "%02x ", buffer[k]);
+ }
+ fprintf(stderr, "\n");
+ }
+ CHECK(ret == 0);
+ }
+ }
+}
+
/* Tests several edge cases. */
void test_ecdsa_edge_cases(void) {
- const unsigned char msg32[32] = {
- 'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
- 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
- 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
- 's', 's', 'a', 'g', 'e', '.', '.', '.'
- };
- const unsigned char sig64[64] = {
- /* Generated by signing the above message with nonce 'This is the nonce we will use...'
- * and secret key 0 (which is not valid), resulting in recid 0. */
- 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
- 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
- 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
- 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
- 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
- 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
- 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
- 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
- };
- unsigned char pubkey[65];
int t;
- int pubkeylen = 65;
- /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
- const unsigned char sigb64[64] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
- };
- unsigned char pubkeyb[33];
- int pubkeyblen = 33;
- int recid;
+ secp256k1_ecdsa_signature sig;
- CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0));
- CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1));
- CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2));
- CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3));
+ /* Test the case where ECDSA recomputes a point that is infinity. */
+ {
+ secp256k1_gej keyj;
+ secp256k1_ge key;
+ secp256k1_scalar msg;
+ secp256k1_scalar sr, ss;
+ secp256k1_scalar_set_int(&ss, 1);
+ secp256k1_scalar_negate(&ss, &ss);
+ secp256k1_scalar_inverse(&ss, &ss);
+ secp256k1_scalar_set_int(&sr, 1);
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr);
+ secp256k1_ge_set_gej(&key, &keyj);
+ msg = ss;
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+ }
- for (recid = 0; recid < 4; recid++) {
- int i;
- int recid2;
- /* (4,4) encoded in DER. */
- unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
- unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
- unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
- unsigned char sigbderalt1[39] = {
- 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
- };
- unsigned char sigbderalt2[39] = {
- 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ /* Verify signature with r of zero fails. */
+ {
+ const unsigned char pubkey_mods_zero[33] = {
+ 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0,
+ 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41,
+ 0x41
};
- unsigned char sigbderalt3[40] = {
- 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00,
+ secp256k1_ge key;
+ secp256k1_scalar msg;
+ secp256k1_scalar sr, ss;
+ secp256k1_scalar_set_int(&ss, 1);
+ secp256k1_scalar_set_int(&msg, 0);
+ secp256k1_scalar_set_int(&sr, 0);
+ CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+ }
+
+ /* Verify signature with s of zero fails. */
+ {
+ const unsigned char pubkey[33] = {
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
+ 0x01
};
- unsigned char sigbderalt4[40] = {
- 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00,
+ secp256k1_ge key;
+ secp256k1_scalar msg;
+ secp256k1_scalar sr, ss;
+ secp256k1_scalar_set_int(&ss, 0);
+ secp256k1_scalar_set_int(&msg, 0);
+ secp256k1_scalar_set_int(&sr, 1);
+ CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+ }
+
+ /* Verify signature with message 0 passes. */
+ {
+ const unsigned char pubkey[33] = {
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x02
};
- /* (order + r,4) encoded in DER. */
- unsigned char sigbderlong[40] = {
- 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,
- 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
- 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
+ const unsigned char pubkey2[33] = {
+ 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0,
+ 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41,
+ 0x43
};
- CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid));
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1);
- for (recid2 = 0; recid2 < 4; recid2++) {
- unsigned char pubkey2b[33];
- int pubkey2blen = 33;
- CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2));
- /* Verifying with (order + r,4) should always fail. */
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1);
- }
- /* DER parsing tests. */
- /* Zero length r/s. */
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2);
- /* Leading zeros. */
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1);
- sigbderalt3[4] = 1;
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2);
- sigbderalt4[7] = 1;
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2);
- /* Damage signature. */
- sigbder[7]++;
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0);
- sigbder[7]--;
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2);
- for(i = 0; i < 8; i++) {
- int c;
- unsigned char orig = sigbder[i];
- /*Try every single-byte change.*/
- for (c = 0; c < 256; c++) {
- if (c == orig ) {
- continue;
- }
- sigbder[i] = c;
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) ==
- (i==4 || i==7) ? 0 : -2 );
- }
- sigbder[i] = orig;
- }
+ secp256k1_ge key;
+ secp256k1_ge key2;
+ secp256k1_scalar msg;
+ secp256k1_scalar sr, ss;
+ secp256k1_scalar_set_int(&ss, 2);
+ secp256k1_scalar_set_int(&msg, 0);
+ secp256k1_scalar_set_int(&sr, 2);
+ CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+ CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+ secp256k1_scalar_negate(&ss, &ss);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+ secp256k1_scalar_set_int(&ss, 1);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0);
}
- /* Test the case where ECDSA recomputes a point that is infinity. */
+ /* Verify signature with message 1 passes. */
{
- secp256k1_gej_t keyj;
- secp256k1_ge_t key;
- secp256k1_scalar_t msg;
- secp256k1_ecdsa_sig_t sig;
- secp256k1_scalar_set_int(&sig.s, 1);
- secp256k1_scalar_negate(&sig.s, &sig.s);
- secp256k1_scalar_inverse(&sig.s, &sig.s);
- secp256k1_scalar_set_int(&sig.r, 1);
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r);
- secp256k1_ge_set_gej(&key, &keyj);
- msg = sig.s;
- CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0);
+ const unsigned char pubkey[33] = {
+ 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22,
+ 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05,
+ 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c,
+ 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76,
+ 0x25
+ };
+ const unsigned char pubkey2[33] = {
+ 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40,
+ 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae,
+ 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f,
+ 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10,
+ 0x62
+ };
+ const unsigned char csr[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,
+ 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb
+ };
+ secp256k1_ge key;
+ secp256k1_ge key2;
+ secp256k1_scalar msg;
+ secp256k1_scalar sr, ss;
+ secp256k1_scalar_set_int(&ss, 1);
+ secp256k1_scalar_set_int(&msg, 1);
+ secp256k1_scalar_set_b32(&sr, csr, NULL);
+ CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+ CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+ secp256k1_scalar_negate(&ss, &ss);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);
+ secp256k1_scalar_set_int(&ss, 2);
+ secp256k1_scalar_inverse_var(&ss, &ss);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0);
}
- /* Test r/s equal to zero */
+ /* Verify signature with message -1 passes. */
{
- /* (1,1) encoded in DER. */
- unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
- unsigned char sigc64[64] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ const unsigned char pubkey[33] = {
+ 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0,
+ 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52,
+ 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27,
+ 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20,
+ 0xf1
+ };
+ const unsigned char csr[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,
+ 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee
};
- unsigned char pubkeyc[65];
- int pubkeyclen = 65;
- CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1);
- sigcder[4] = 0;
- sigc64[31] = 0;
- CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
- sigcder[4] = 1;
- sigcder[7] = 0;
- sigc64[31] = 1;
- sigc64[63] = 0;
- CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
- CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
- }
-
- /*Signature where s would be zero.*/
+ secp256k1_ge key;
+ secp256k1_scalar msg;
+ secp256k1_scalar sr, ss;
+ secp256k1_scalar_set_int(&ss, 1);
+ secp256k1_scalar_set_int(&msg, 1);
+ secp256k1_scalar_negate(&msg, &msg);
+ secp256k1_scalar_set_b32(&sr, csr, NULL);
+ CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+ secp256k1_scalar_negate(&ss, &ss);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);
+ secp256k1_scalar_set_int(&ss, 3);
+ secp256k1_scalar_inverse_var(&ss, &ss);
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
+ }
+
+ /* Signature where s would be zero. */
{
- const unsigned char nonce[32] = {
+ secp256k1_pubkey pubkey;
+ size_t siglen;
+ int32_t ecount;
+ unsigned char signature[72];
+ static const unsigned char nonce[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1810,21 +4004,72 @@ void test_ecdsa_edge_cases(void) {
0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
};
- unsigned char sig[72];
- int siglen = 72;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0);
- CHECK(siglen == 0);
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0);
- CHECK(siglen == 0);
+ ecount = 0;
+ secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0);
msg[31] = 0xaa;
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1);
+ CHECK(ecount == 0);
+ CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1);
+ CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);
+ CHECK(ecount == 7);
+ /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */
+ CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0);
+ CHECK(ecount == 8);
siglen = 72;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1);
- CHECK(siglen > 0);
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1);
- CHECK(siglen > 0);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0);
+ CHECK(ecount == 9);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0);
+ CHECK(ecount == 10);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0);
+ CHECK(ecount == 11);
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
+ CHECK(ecount == 11);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0);
+ CHECK(ecount == 12);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0);
+ CHECK(ecount == 13);
+ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1);
+ CHECK(ecount == 13);
siglen = 10;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1);
- CHECK(siglen == 0);
+ /* Too little room for a signature does not fail via ARGCHECK. */
+ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);
+ CHECK(ecount == 13);
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1);
+ CHECK(ecount == 5);
+ memset(signature, 255, 64);
+ CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0);
+ CHECK(ecount == 5);
+ secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
}
/* Nonce function corner cases. */
@@ -1833,65 +4078,43 @@ void test_ecdsa_edge_cases(void) {
int i;
unsigned char key[32];
unsigned char msg[32];
- unsigned char sig[72];
- unsigned char sig2[72];
- secp256k1_ecdsa_sig_t s[512];
- int siglen = 72;
- int siglen2 = 72;
- int recid2;
+ secp256k1_ecdsa_signature sig2;
+ secp256k1_scalar sr[512], ss;
const unsigned char *extra;
extra = t == 0 ? NULL : zero;
memset(msg, 0, 32);
msg[31] = 1;
/* High key results in signature failure. */
memset(key, 0xFF, 32);
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0);
- CHECK(siglen == 0);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);
+ CHECK(is_empty_signature(&sig));
/* Zero key results in signature failure. */
memset(key, 0, 32);
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0);
- CHECK(siglen == 0);
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);
+ CHECK(is_empty_signature(&sig));
/* Nonce function failure results in signature failure. */
key[31] = 1;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0);
- CHECK(siglen == 0);
- CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0);
- CHECK(is_empty_compact_signature(sig));
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0);
+ CHECK(is_empty_signature(&sig));
/* The retry loop successfully makes its way to the first good value. */
- siglen = 72;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1);
- CHECK(siglen > 0);
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1);
- CHECK(siglen > 0);
- CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
- CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1);
- CHECK(!is_empty_compact_signature(sig));
- CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1);
- CHECK(!is_empty_compact_signature(sig2));
- CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
- /* The default nonce function is determinstic. */
- siglen = 72;
- siglen2 = 72;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1);
- CHECK(siglen > 0);
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1);
- CHECK(siglen2 > 0);
- CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
- CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1);
- CHECK(!is_empty_compact_signature(sig));
- CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1);
- CHECK(!is_empty_compact_signature(sig));
- CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1);
+ CHECK(!is_empty_signature(&sig));
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1);
+ CHECK(!is_empty_signature(&sig2));
+ CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
+ /* The default nonce function is deterministic. */
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
+ CHECK(!is_empty_signature(&sig2));
+ CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function changes output with different messages. */
for(i = 0; i < 256; i++) {
int j;
- siglen2 = 72;
msg[0] = i;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1);
- CHECK(!is_empty_compact_signature(sig));
- CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2));
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
+ CHECK(!is_empty_signature(&sig2));
+ secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
- CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r));
+ CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
}
msg[0] = 0;
@@ -1899,17 +4122,45 @@ void test_ecdsa_edge_cases(void) {
/* The default nonce function changes output with different keys. */
for(i = 256; i < 512; i++) {
int j;
- siglen2 = 72;
key[0] = i - 256;
- CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1);
- CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2));
+ CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);
+ CHECK(!is_empty_signature(&sig2));
+ secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
- CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r));
+ CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
}
key[0] = 0;
}
+ {
+ /* Check that optional nonce arguments do not have equivalent effect. */
+ const unsigned char zeros[32] = {0};
+ unsigned char nonce[32];
+ unsigned char nonce2[32];
+ unsigned char nonce3[32];
+ unsigned char nonce4[32];
+ VG_UNDEF(nonce,32);
+ VG_UNDEF(nonce2,32);
+ VG_UNDEF(nonce3,32);
+ VG_UNDEF(nonce4,32);
+ CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1);
+ VG_CHECK(nonce,32);
+ CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1);
+ VG_CHECK(nonce2,32);
+ CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1);
+ VG_CHECK(nonce3,32);
+ CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1);
+ VG_CHECK(nonce4,32);
+ CHECK(memcmp(nonce, nonce2, 32) != 0);
+ CHECK(memcmp(nonce, nonce3, 32) != 0);
+ CHECK(memcmp(nonce, nonce4, 32) != 0);
+ CHECK(memcmp(nonce2, nonce3, 32) != 0);
+ CHECK(memcmp(nonce2, nonce4, 32) != 0);
+ CHECK(memcmp(nonce3, nonce4, 32) != 0);
+ }
+
+
/* Privkey export where pubkey is the point at infinity. */
{
unsigned char privkey[300];
@@ -1919,9 +4170,10 @@ void test_ecdsa_edge_cases(void) {
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
};
- int outlen = 300;
- CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0));
- CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1));
+ size_t outlen = 300;
+ CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));
+ outlen = 300;
+ CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));
}
}
@@ -1930,46 +4182,48 @@ void run_ecdsa_edge_cases(void) {
}
#ifdef ENABLE_OPENSSL_TESTS
-EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) {
+EC_KEY *get_openssl_key(const unsigned char *key32) {
unsigned char privkey[300];
- int privkeylen;
+ size_t privkeylen;
const unsigned char* pbegin = privkey;
- int compr = secp256k1_rand32() & 1;
+ int compr = secp256k1_rand_bits(1);
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
- CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr));
+ CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr));
CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
CHECK(EC_KEY_check_key(ec_key));
return ec_key;
}
void test_ecdsa_openssl(void) {
- secp256k1_gej_t qj;
- secp256k1_ge_t q;
- secp256k1_ecdsa_sig_t sig;
- secp256k1_scalar_t one;
- secp256k1_scalar_t msg2;
- secp256k1_scalar_t key, msg;
+ secp256k1_gej qj;
+ secp256k1_ge q;
+ secp256k1_scalar sigr, sigs;
+ secp256k1_scalar one;
+ secp256k1_scalar msg2;
+ secp256k1_scalar key, msg;
EC_KEY *ec_key;
unsigned int sigsize = 80;
- int secp_sigsize = 80;
+ size_t secp_sigsize = 80;
unsigned char message[32];
unsigned char signature[80];
+ unsigned char key32[32];
secp256k1_rand256_test(message);
secp256k1_scalar_set_b32(&msg, message, NULL);
random_scalar_order_test(&key);
+ secp256k1_scalar_get_b32(key32, &key);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key);
secp256k1_ge_set_gej(&q, &qj);
- ec_key = get_openssl_key(&key);
- CHECK(ec_key);
+ ec_key = get_openssl_key(key32);
+ CHECK(ec_key != NULL);
CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
- CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
- CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg));
+ CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize));
+ CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg));
secp256k1_scalar_set_int(&one, 1);
secp256k1_scalar_add(&msg2, &msg, &one);
- CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2));
+ CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2));
- random_sign(&sig, &key, &msg, NULL);
- CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig));
+ random_sign(&sigr, &sigs, &key, &msg, NULL);
+ CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs));
CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1);
EC_KEY_free(ec_key);
@@ -1983,6 +4237,18 @@ void run_ecdsa_openssl(void) {
}
#endif
+#ifdef ENABLE_MODULE_ECDH
+# include "modules/ecdh/tests_impl.h"
+#endif
+
+#ifdef ENABLE_MODULE_SCHNORR
+# include "modules/schnorr/tests_impl.h"
+#endif
+
+#ifdef ENABLE_MODULE_RECOVERY
+# include "modules/recovery/tests_impl.h"
+#endif
+
int main(int argc, char **argv) {
unsigned char seed16[16] = {0};
unsigned char run32[32] = {0};
@@ -2007,7 +4273,7 @@ int main(int argc, char **argv) {
}
} else {
FILE *frand = fopen("/dev/urandom", "r");
- if (!frand || !fread(&seed16, sizeof(seed16), 1, frand)) {
+ if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) {
uint64_t t = time(NULL) * (uint64_t)1337;
seed16[0] ^= t;
seed16[1] ^= t >> 8;
@@ -2028,12 +4294,14 @@ int main(int argc, char **argv) {
/* initialize */
run_context_tests();
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
-
- if (secp256k1_rand32() & 1) {
+ if (secp256k1_rand_bits(1)) {
secp256k1_rand256(run32);
- CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL));
+ CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL));
}
+ run_rand_bits();
+ run_rand_int();
+
run_sha256_tests();
run_hmac_sha256_tests();
run_rfc6979_hmac_sha256_tests();
@@ -2057,6 +4325,7 @@ int main(int argc, char **argv) {
/* group tests */
run_ge();
+ run_group_decompress();
/* ecmult tests */
run_wnaf();
@@ -2064,9 +4333,28 @@ int main(int argc, char **argv) {
run_ecmult_chain();
run_ecmult_constants();
run_ecmult_gen_blind();
+ run_ecmult_const_tests();
+ run_ec_combine();
+
+ /* endomorphism tests */
+#ifdef USE_ENDOMORPHISM
+ run_endomorphism_tests();
+#endif
+
+ /* EC point parser test */
+ run_ec_pubkey_parse_test();
+
+ /* EC key edge cases */
+ run_eckey_edge_case_test();
+
+#ifdef ENABLE_MODULE_ECDH
+ /* ecdh tests */
+ run_ecdh_tests();
+#endif
/* ecdsa tests */
run_random_pubkeys();
+ run_ecdsa_der_parse();
run_ecdsa_sign_verify();
run_ecdsa_end_to_end();
run_ecdsa_edge_cases();
@@ -2074,10 +4362,22 @@ int main(int argc, char **argv) {
run_ecdsa_openssl();
#endif
+#ifdef ENABLE_MODULE_SCHNORR
+ /* Schnorr tests */
+ run_schnorr_tests();
+#endif
+
+#ifdef ENABLE_MODULE_RECOVERY
+ /* ECDSA pubkey recovery tests */
+ run_recovery_tests();
+#endif
+
secp256k1_rand256(run32);
printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);
/* shutdown */
secp256k1_context_destroy(ctx);
+
+ printf("no problems found\n");
return 0;
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index ae98639f7c..4eef4ded47 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -15,6 +15,15 @@
#include <stdint.h>
#include <stdio.h>
+typedef struct {
+ void (*fn)(const char *text, void* data);
+ const void* data;
+} secp256k1_callback;
+
+static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) {
+ cb->fn(text, (void*)cb->data);
+}
+
#ifdef DETERMINISTIC
#define TEST_FAILURE(msg) do { \
fprintf(stderr, "%s\n", msg); \
@@ -47,23 +56,20 @@
} while(0)
#endif
-/* Like assert(), but safe to use on expressions with side effects. */
-#ifndef NDEBUG
-#define DEBUG_CHECK CHECK
-#else
-#define DEBUG_CHECK(cond) do { (void)(cond); } while(0)
-#endif
-
-/* Like DEBUG_CHECK(), but when VERIFY is defined instead of NDEBUG not defined. */
+/* Like assert(), but when VERIFY is defined, and side-effect safe. */
#ifdef VERIFY
#define VERIFY_CHECK CHECK
+#define VERIFY_SETUP(stmt) do { stmt; } while(0)
#else
#define VERIFY_CHECK(cond) do { (void)(cond); } while(0)
+#define VERIFY_SETUP(stmt)
#endif
-static SECP256K1_INLINE void *checked_malloc(size_t size) {
+static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
void *ret = malloc(size);
- CHECK(ret != NULL);
+ if (ret == NULL) {
+ secp256k1_callback_call(cb, "Out of memory");
+ }
return ret;
}
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 0cf906a259..afb3b282f6 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -377,8 +377,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx7.vout.resize(2);
tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[0].nValue = 10 * COIN;
- tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
- tx7.vout[0].nValue = 10 * COIN;
+ tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[1].nValue = 10 * COIN;
pool.addUnchecked(tx4.GetHash(), CTxMemPoolEntry(tx4, 7000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx4)));
pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5)));
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
new file mode 100644
index 0000000000..08644f2968
--- /dev/null
+++ b/src/torcontrol.cpp
@@ -0,0 +1,685 @@
+#include "torcontrol.h"
+#include "utilstrencodings.h"
+#include "net.h"
+#include "util.h"
+#include "crypto/hmac_sha256.h"
+
+#include <vector>
+#include <deque>
+#include <set>
+#include <stdlib.h>
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/signals2/signal.hpp>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+#include <event2/bufferevent.h>
+#include <event2/buffer.h>
+#include <event2/util.h>
+#include <event2/event.h>
+#include <event2/thread.h>
+
+/** Default control port */
+const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051";
+/** Tor cookie size (from control-spec.txt) */
+static const int TOR_COOKIE_SIZE = 32;
+/** Size of client/server nonce for SAFECOOKIE */
+static const int TOR_NONCE_SIZE = 32;
+/** For computing serverHash in SAFECOOKIE */
+static const std::string TOR_SAFE_SERVERKEY = "Tor safe cookie authentication server-to-controller hash";
+/** For computing clientHash in SAFECOOKIE */
+static const std::string TOR_SAFE_CLIENTKEY = "Tor safe cookie authentication controller-to-server hash";
+/** Exponential backoff configuration - initial timeout in seconds */
+static const float RECONNECT_TIMEOUT_START = 1.0;
+/** Exponential backoff configuration - growth factor */
+static const float RECONNECT_TIMEOUT_EXP = 1.5;
+/** Maximum length for lines received on TorControlConnection.
+ * tor-control-spec.txt mentions that there is explicitly no limit defined to line length,
+ * this is belt-and-suspenders sanity limit to prevent memory exhaustion.
+ */
+static const int MAX_LINE_LENGTH = 100000;
+
+/****** Low-level TorControlConnection ********/
+
+/** Reply from Tor, can be single or multi-line */
+class TorControlReply
+{
+public:
+ TorControlReply() { Clear(); }
+
+ int code;
+ std::vector<std::string> lines;
+
+ void Clear()
+ {
+ code = 0;
+ lines.clear();
+ }
+};
+
+/** Low-level handling for Tor control connection.
+ * Speaks the SMTP-like protocol as defined in torspec/control-spec.txt
+ */
+class TorControlConnection
+{
+public:
+ typedef boost::function<void(TorControlConnection&)> ConnectionCB;
+ typedef boost::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
+
+ /** Create a new TorControlConnection.
+ */
+ TorControlConnection(struct event_base *base);
+ ~TorControlConnection();
+
+ /**
+ * Connect to a Tor control port.
+ * target is address of the form host:port.
+ * connected is the handler that is called when connection is succesfully established.
+ * disconnected is a handler that is called when the connection is broken.
+ * Return true on success.
+ */
+ bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected);
+
+ /**
+ * Disconnect from Tor control port.
+ */
+ bool Disconnect();
+
+ /** Send a command, register a handler for the reply.
+ * A trailing CRLF is automatically added.
+ * Return true on success.
+ */
+ bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);
+
+ /** Response handlers for async replies */
+ boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;
+private:
+ /** Callback when ready for use */
+ boost::function<void(TorControlConnection&)> connected;
+ /** Callback when connection lost */
+ boost::function<void(TorControlConnection&)> disconnected;
+ /** Libevent event base */
+ struct event_base *base;
+ /** Connection to control socket */
+ struct bufferevent *b_conn;
+ /** Message being received */
+ TorControlReply message;
+ /** Response handlers */
+ std::deque<ReplyHandlerCB> reply_handlers;
+
+ /** Libevent handlers: internal */
+ static void readcb(struct bufferevent *bev, void *ctx);
+ static void eventcb(struct bufferevent *bev, short what, void *ctx);
+};
+
+TorControlConnection::TorControlConnection(struct event_base *base):
+ base(base), b_conn(0)
+{
+}
+
+TorControlConnection::~TorControlConnection()
+{
+ if (b_conn)
+ bufferevent_free(b_conn);
+}
+
+void TorControlConnection::readcb(struct bufferevent *bev, void *ctx)
+{
+ TorControlConnection *self = (TorControlConnection*)ctx;
+ struct evbuffer *input = bufferevent_get_input(bev);
+ size_t n_read_out = 0;
+ char *line;
+ assert(input);
+ // If there is not a whole line to read, evbuffer_readln returns NULL
+ while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != NULL)
+ {
+ std::string s(line, n_read_out);
+ free(line);
+ if (s.size() < 4) // Short line
+ continue;
+ // <status>(-|+| )<data><CRLF>
+ self->message.code = atoi(s.substr(0,3));
+ self->message.lines.push_back(s.substr(4));
+ char ch = s[3]; // '-','+' or ' '
+ if (ch == ' ') {
+ // Final line, dispatch reply and clean up
+ if (self->message.code >= 600) {
+ // Dispatch async notifications to async handler
+ // Synchronous and asynchronous messages are never interleaved
+ self->async_handler(*self, self->message);
+ } else {
+ if (!self->reply_handlers.empty()) {
+ // Invoke reply handler with message
+ self->reply_handlers.front()(*self, self->message);
+ self->reply_handlers.pop_front();
+ } else {
+ LogPrint("tor", "tor: Received unexpected sync reply %i\n", self->message.code);
+ }
+ }
+ self->message.Clear();
+ }
+ }
+ // Check for size of buffer - protect against memory exhaustion with very long lines
+ // Do this after evbuffer_readln to make sure all full lines have been
+ // removed from the buffer. Everything left is an incomplete line.
+ if (evbuffer_get_length(input) > MAX_LINE_LENGTH) {
+ LogPrintf("tor: Disconnecting because MAX_LINE_LENGTH exceeded\n");
+ self->Disconnect();
+ }
+}
+
+void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ TorControlConnection *self = (TorControlConnection*)ctx;
+ if (what & BEV_EVENT_CONNECTED) {
+ LogPrint("tor", "tor: Succesfully connected!\n");
+ self->connected(*self);
+ } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+ if (what & BEV_EVENT_ERROR)
+ LogPrint("tor", "tor: Error connecting to Tor control socket\n");
+ else
+ LogPrint("tor", "tor: End of stream\n");
+ self->Disconnect();
+ self->disconnected(*self);
+ }
+}
+
+bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected)
+{
+ if (b_conn)
+ Disconnect();
+ // Parse target address:port
+ struct sockaddr_storage connect_to_addr;
+ int connect_to_addrlen = sizeof(connect_to_addr);
+ if (evutil_parse_sockaddr_port(target.c_str(),
+ (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) {
+ LogPrintf("tor: Error parsing socket address %s\n", target);
+ return false;
+ }
+
+ // Create a new socket, set up callbacks and enable notification bits
+ b_conn = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
+ if (!b_conn)
+ return false;
+ bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this);
+ bufferevent_enable(b_conn, EV_READ|EV_WRITE);
+ this->connected = connected;
+ this->disconnected = disconnected;
+
+ // Finally, connect to target
+ if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) {
+ LogPrintf("tor: Error connecting to address %s\n", target);
+ return false;
+ }
+ return true;
+}
+
+bool TorControlConnection::Disconnect()
+{
+ if (b_conn)
+ bufferevent_free(b_conn);
+ b_conn = 0;
+ return true;
+}
+
+bool TorControlConnection::Command(const std::string &cmd, const ReplyHandlerCB& reply_handler)
+{
+ if (!b_conn)
+ return false;
+ struct evbuffer *buf = bufferevent_get_output(b_conn);
+ if (!buf)
+ return false;
+ evbuffer_add(buf, cmd.data(), cmd.size());
+ evbuffer_add(buf, "\r\n", 2);
+ reply_handlers.push_back(reply_handler);
+ return true;
+}
+
+/****** General parsing utilities ********/
+
+/* Split reply line in the form 'AUTH METHODS=...' into a type
+ * 'AUTH' and arguments 'METHODS=...'.
+ */
+static std::pair<std::string,std::string> SplitTorReplyLine(const std::string &s)
+{
+ size_t ptr=0;
+ std::string type;
+ while (ptr < s.size() && s[ptr] != ' ') {
+ type.push_back(s[ptr]);
+ ++ptr;
+ }
+ if (ptr < s.size())
+ ++ptr; // skip ' '
+ return make_pair(type, s.substr(ptr));
+}
+
+/** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=".../control_auth_cookie"'.
+ */
+static std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
+{
+ std::map<std::string,std::string> mapping;
+ size_t ptr=0;
+ while (ptr < s.size()) {
+ std::string key, value;
+ while (ptr < s.size() && s[ptr] != '=') {
+ key.push_back(s[ptr]);
+ ++ptr;
+ }
+ if (ptr == s.size()) // unexpected end of line
+ return std::map<std::string,std::string>();
+ ++ptr; // skip '='
+ if (ptr < s.size() && s[ptr] == '"') { // Quoted string
+ ++ptr; // skip '='
+ bool escape_next = false;
+ while (ptr < s.size() && (!escape_next && s[ptr] != '"')) {
+ escape_next = (s[ptr] == '\\');
+ value.push_back(s[ptr]);
+ ++ptr;
+ }
+ if (ptr == s.size()) // unexpected end of line
+ return std::map<std::string,std::string>();
+ ++ptr; // skip closing '"'
+ /* TODO: unescape value - according to the spec this depends on the
+ * context, some strings use C-LogPrintf style escape codes, some
+ * don't. So may be better handled at the call site.
+ */
+ } else { // Unquoted value. Note that values can contain '=' at will, just no spaces
+ while (ptr < s.size() && s[ptr] != ' ') {
+ value.push_back(s[ptr]);
+ ++ptr;
+ }
+ }
+ if (ptr < s.size() && s[ptr] == ' ')
+ ++ptr; // skip ' ' after key=value
+ mapping[key] = value;
+ }
+ return mapping;
+}
+
+/** Read full contents of a file and return them in a std::string.
+ * Returns a pair <status, string>.
+ * If an error occured, status will be false, otherwise status will be true and the data will be returned in string.
+ *
+ * @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data
+ * (with len > maxsize) will be returned.
+ */
+static std::pair<bool,std::string> ReadBinaryFile(const std::string &filename, size_t maxsize=std::numeric_limits<size_t>::max())
+{
+ FILE *f = fopen(filename.c_str(), "rb");
+ if (f == NULL)
+ return std::make_pair(false,"");
+ std::string retval;
+ char buffer[128];
+ size_t n;
+ while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) {
+ retval.append(buffer, buffer+n);
+ if (retval.size() > maxsize)
+ break;
+ }
+ fclose(f);
+ return std::make_pair(true,retval);
+}
+
+/** Write contents of std::string to a file.
+ * @return true on success.
+ */
+static bool WriteBinaryFile(const std::string &filename, const std::string &data)
+{
+ FILE *f = fopen(filename.c_str(), "wb");
+ if (f == NULL)
+ return false;
+ if (fwrite(data.data(), 1, data.size(), f) != data.size()) {
+ fclose(f);
+ return false;
+ }
+ fclose(f);
+ return true;
+}
+
+/****** Bitcoin specific TorController implementation ********/
+
+/** Controller that connects to Tor control socket, authenticate, then create
+ * and maintain a ephemeral hidden service.
+ */
+class TorController
+{
+public:
+ TorController(struct event_base* base, const std::string& target);
+ ~TorController();
+
+ /** Get name fo file to store private key in */
+ std::string GetPrivateKeyFile();
+
+ /** Reconnect, after getting disconnected */
+ void Reconnect();
+private:
+ struct event_base* base;
+ std::string target;
+ TorControlConnection conn;
+ std::string private_key;
+ std::string service_id;
+ bool reconnect;
+ struct event *reconnect_ev;
+ float reconnect_timeout;
+ CService service;
+ /** Cooie for SAFECOOKIE auth */
+ std::vector<uint8_t> cookie;
+ /** ClientNonce for SAFECOOKIE auth */
+ std::vector<uint8_t> clientNonce;
+
+ /** Callback for ADD_ONION result */
+ void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
+ /** Callback for AUTHENTICATE result */
+ void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
+ /** Callback for AUTHCHALLENGE result */
+ void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
+ /** Callback for PROTOCOLINFO result */
+ void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
+ /** Callback after succesful connection */
+ void connected_cb(TorControlConnection& conn);
+ /** Callback after connection lost or failed connection attempt */
+ void disconnected_cb(TorControlConnection& conn);
+
+ /** Callback for reconnect timer */
+ static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
+};
+
+TorController::TorController(struct event_base* base, const std::string& target):
+ base(base),
+ target(target), conn(base), reconnect(true), reconnect_ev(0),
+ reconnect_timeout(RECONNECT_TIMEOUT_START)
+{
+ // Start connection attempts immediately
+ if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1),
+ boost::bind(&TorController::disconnected_cb, this, _1) )) {
+ LogPrintf("tor: Initiating connection to Tor control port %s failed\n", target);
+ }
+ // Read service private key if cached
+ std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());
+ if (pkf.first) {
+ LogPrint("tor", "tor: Reading cached private key from %s\n", GetPrivateKeyFile());
+ private_key = pkf.second;
+ }
+}
+
+TorController::~TorController()
+{
+ if (reconnect_ev)
+ event_del(reconnect_ev);
+ if (service.IsValid()) {
+ RemoveLocal(service);
+ }
+}
+
+void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply)
+{
+ if (reply.code == 250) {
+ LogPrint("tor", "tor: ADD_ONION succesful\n");
+ BOOST_FOREACH(const std::string &s, reply.lines) {
+ std::map<std::string,std::string> m = ParseTorReplyMapping(s);
+ std::map<std::string,std::string>::iterator i;
+ if ((i = m.find("ServiceID")) != m.end())
+ service_id = i->second;
+ if ((i = m.find("PrivateKey")) != m.end())
+ private_key = i->second;
+ }
+
+ service = CService(service_id+".onion", GetListenPort(), false);
+ LogPrintf("tor: Got service ID %s, advertizing service %s\n", service_id, service.ToString());
+ if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
+ LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile());
+ } else {
+ LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile());
+ }
+ AddLocal(service, LOCAL_MANUAL);
+ // ... onion requested - keep connection open
+ } else if (reply.code == 510) { // 510 Unrecognized command
+ LogPrintf("tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\n");
+ } else {
+ LogPrintf("tor: Add onion failed; error code %d\n", reply.code);
+ }
+}
+
+void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply)
+{
+ if (reply.code == 250) {
+ LogPrint("tor", "tor: Authentication succesful\n");
+ // Finally - now create the service
+ if (private_key.empty()) // No private key, generate one
+ private_key = "NEW:BEST";
+ // Request hidden service, redirect port.
+ // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient
+ // choice. TODO; refactor the shutdown sequence some day.
+ conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()),
+ boost::bind(&TorController::add_onion_cb, this, _1, _2));
+ } else {
+ LogPrintf("tor: Authentication failed\n");
+ }
+}
+
+/** Compute Tor SAFECOOKIE response.
+ *
+ * ServerHash is computed as:
+ * HMAC-SHA256("Tor safe cookie authentication server-to-controller hash",
+ * CookieString | ClientNonce | ServerNonce)
+ * (with the HMAC key as its first argument)
+ *
+ * After a controller sends a successful AUTHCHALLENGE command, the
+ * next command sent on the connection must be an AUTHENTICATE command,
+ * and the only authentication string which that AUTHENTICATE command
+ * will accept is:
+ *
+ * HMAC-SHA256("Tor safe cookie authentication controller-to-server hash",
+ * CookieString | ClientNonce | ServerNonce)
+ *
+ */
+static std::vector<uint8_t> ComputeResponse(const std::string &key, const std::vector<uint8_t> &cookie, const std::vector<uint8_t> &clientNonce, const std::vector<uint8_t> &serverNonce)
+{
+ CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size());
+ std::vector<uint8_t> computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0);
+ computeHash.Write(begin_ptr(cookie), cookie.size());
+ computeHash.Write(begin_ptr(clientNonce), clientNonce.size());
+ computeHash.Write(begin_ptr(serverNonce), serverNonce.size());
+ computeHash.Finalize(begin_ptr(computedHash));
+ return computedHash;
+}
+
+void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply)
+{
+ if (reply.code == 250) {
+ LogPrint("tor", "tor: SAFECOOKIE authentication challenge succesful\n");
+ std::pair<std::string,std::string> l = SplitTorReplyLine(reply.lines[0]);
+ if (l.first == "AUTHCHALLENGE") {
+ std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
+ std::vector<uint8_t> serverHash = ParseHex(m["SERVERHASH"]);
+ std::vector<uint8_t> serverNonce = ParseHex(m["SERVERNONCE"]);
+ LogPrint("tor", "tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce));
+ if (serverNonce.size() != 32) {
+ LogPrintf("tor: ServerNonce is not 32 bytes, as required by spec\n");
+ return;
+ }
+
+ std::vector<uint8_t> computedServerHash = ComputeResponse(TOR_SAFE_SERVERKEY, cookie, clientNonce, serverNonce);
+ if (computedServerHash != serverHash) {
+ LogPrintf("tor: ServerHash %s does not match expected ServerHash %s\n", HexStr(serverHash), HexStr(computedServerHash));
+ return;
+ }
+
+ std::vector<uint8_t> computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce);
+ conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2));
+ } else {
+ LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n");
+ }
+ } else {
+ LogPrintf("tor: SAFECOOKIE authentication challenge failed\n");
+ }
+}
+
+void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply)
+{
+ if (reply.code == 250) {
+ std::set<std::string> methods;
+ std::string cookiefile;
+ /*
+ * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="/home/x/.tor/control_auth_cookie"
+ * 250-AUTH METHODS=NULL
+ * 250-AUTH METHODS=HASHEDPASSWORD
+ */
+ BOOST_FOREACH(const std::string &s, reply.lines) {
+ std::pair<std::string,std::string> l = SplitTorReplyLine(s);
+ if (l.first == "AUTH") {
+ std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
+ std::map<std::string,std::string>::iterator i;
+ if ((i = m.find("METHODS")) != m.end())
+ boost::split(methods, i->second, boost::is_any_of(","));
+ if ((i = m.find("COOKIEFILE")) != m.end())
+ cookiefile = i->second;
+ } else if (l.first == "VERSION") {
+ std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
+ std::map<std::string,std::string>::iterator i;
+ if ((i = m.find("Tor")) != m.end()) {
+ LogPrint("tor", "tor: Connected to Tor version %s\n", i->second);
+ }
+ }
+ }
+ BOOST_FOREACH(const std::string &s, methods) {
+ LogPrint("tor", "tor: Supported authentication method: %s\n", s);
+ }
+ // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD
+ /* Authentication:
+ * cookie: hex-encoded ~/.tor/control_auth_cookie
+ * password: "password"
+ */
+ std::string torpassword = GetArg("-torpassword", "");
+ if (methods.count("NULL")) {
+ LogPrint("tor", "tor: Using NULL authentication\n");
+ conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2));
+ } else if (methods.count("SAFECOOKIE")) {
+ // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
+ LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile);
+ std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE);
+ if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) {
+ // conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2));
+ cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
+ clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);
+ GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE);
+ conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));
+ } else {
+ if (status_cookie.first) {
+ LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE);
+ } else {
+ LogPrintf("tor: Authentication cookie %s could not be opened (check permissions)\n", cookiefile);
+ }
+ }
+ } else if (methods.count("HASHEDPASSWORD")) {
+ if (!torpassword.empty()) {
+ LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n");
+ boost::replace_all(torpassword, "\"", "\\\"");
+ conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2));
+ } else {
+ LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n");
+ }
+ } else {
+ LogPrintf("tor: No supported authentication method\n");
+ }
+ } else {
+ LogPrintf("tor: Requesting protocol info failed\n");
+ }
+}
+
+void TorController::connected_cb(TorControlConnection& conn)
+{
+ reconnect_timeout = RECONNECT_TIMEOUT_START;
+ // First send a PROTOCOLINFO command to figure out what authentication is expected
+ if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2)))
+ LogPrintf("tor: Error sending initial protocolinfo command\n");
+}
+
+void TorController::disconnected_cb(TorControlConnection& conn)
+{
+ // Stop advertizing service when disconnected
+ if (service.IsValid())
+ RemoveLocal(service);
+ service = CService();
+ if (!reconnect)
+ return;
+ LogPrintf("tor: Disconnected from Tor control port %s, trying to reconnect\n", target);
+ // Single-shot timer for reconnect. Use exponential backoff.
+ struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
+ reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
+ event_add(reconnect_ev, &time);
+ reconnect_timeout *= RECONNECT_TIMEOUT_EXP;
+}
+
+void TorController::Reconnect()
+{
+ /* Try to reconnect and reestablish if we get booted - for example, Tor
+ * may be restarting.
+ */
+ if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1),
+ boost::bind(&TorController::disconnected_cb, this, _1) )) {
+ LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target);
+ }
+}
+
+std::string TorController::GetPrivateKeyFile()
+{
+ return (GetDataDir() / "onion_private_key").string();
+}
+
+void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)
+{
+ TorController *self = (TorController*)arg;
+ self->Reconnect();
+}
+
+/****** Thread ********/
+struct event_base *base;
+boost::thread torControlThread;
+
+static void TorControlThread()
+{
+ TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL));
+
+ event_base_dispatch(base);
+}
+
+void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler)
+{
+ assert(!base);
+#ifdef WIN32
+ evthread_use_windows_threads();
+#else
+ evthread_use_pthreads();
+#endif
+ base = event_base_new();
+ if (!base) {
+ LogPrintf("tor: Unable to create event_base\n");
+ return;
+ }
+
+ torControlThread = boost::thread(boost::bind(&TraceThread<void (*)()>, "torcontrol", &TorControlThread));
+}
+
+void InterruptTorControl()
+{
+ if (base) {
+ LogPrintf("tor: Thread interrupt\n");
+ event_base_loopbreak(base);
+ }
+}
+
+void StopTorControl()
+{
+ if (base) {
+ torControlThread.join();
+ event_base_free(base);
+ base = 0;
+ }
+}
+
diff --git a/src/torcontrol.h b/src/torcontrol.h
new file mode 100644
index 0000000000..72dc82c5b1
--- /dev/null
+++ b/src/torcontrol.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+/**
+ * Functionality for communicating with Tor.
+ */
+#ifndef BITCOIN_TORCONTROL_H
+#define BITCOIN_TORCONTROL_H
+
+#include "scheduler.h"
+
+extern const std::string DEFAULT_TOR_CONTROL;
+static const bool DEFAULT_LISTEN_ONION = true;
+
+void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler);
+void InterruptTorControl();
+void StopTorControl();
+
+#endif /* BITCOIN_TORCONTROL_H */