aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/devtools/README.md13
-rwxr-xr-xcontrib/devtools/git-subtree-check.sh74
-rw-r--r--doc/release-notes/release-notes-0.10.0.md762
-rw-r--r--doc/release-process.md17
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/addrman.cpp295
-rw-r--r--src/addrman.h206
-rw-r--r--src/alert.cpp9
-rw-r--r--src/alert.h4
-rw-r--r--src/chainparams.cpp6
-rw-r--r--src/chainparams.h6
-rw-r--r--src/init.cpp5
-rw-r--r--src/key.cpp18
-rw-r--r--src/key.h3
-rw-r--r--src/main.cpp156
-rw-r--r--src/main.h1
-rw-r--r--src/net.cpp3
-rw-r--r--src/pow.cpp6
-rw-r--r--src/qt/forms/sendcoinsdialog.ui2
-rw-r--r--src/secp256k1/Makefile.am10
-rw-r--r--src/secp256k1/README.md20
-rw-r--r--src/secp256k1/configure.ac12
-rw-r--r--src/secp256k1/include/secp256k1.h46
-rw-r--r--src/secp256k1/src/bench.h29
-rw-r--r--src/secp256k1/src/bench_internal.c318
-rw-r--r--src/secp256k1/src/bench_inv.c52
-rw-r--r--src/secp256k1/src/bench_recover.c17
-rw-r--r--src/secp256k1/src/bench_sign.c15
-rw-r--r--src/secp256k1/src/bench_verify.c14
-rw-r--r--src/secp256k1/src/ecdsa.h4
-rw-r--r--src/secp256k1/src/ecdsa_impl.h173
-rw-r--r--src/secp256k1/src/eckey_impl.h19
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h57
-rw-r--r--src/secp256k1/src/ecmult_impl.h144
-rw-r--r--src/secp256k1/src/field.h27
-rw-r--r--src/secp256k1/src/field_10x26.h26
-rw-r--r--src/secp256k1/src/field_10x26_impl.h185
-rw-r--r--src/secp256k1/src/field_5x52.h26
-rw-r--r--src/secp256k1/src/field_5x52_impl.h82
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h120
-rw-r--r--src/secp256k1/src/field_impl.h187
-rw-r--r--src/secp256k1/src/group.h42
-rw-r--r--src/secp256k1/src/group_impl.h250
-rw-r--r--src/secp256k1/src/hash.h4
-rw-r--r--src/secp256k1/src/hash_impl.h117
-rw-r--r--src/secp256k1/src/num_gmp_impl.h29
-rw-r--r--src/secp256k1/src/scalar.h7
-rw-r--r--src/secp256k1/src/scalar_4x64.h2
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h551
-rw-r--r--src/secp256k1/src/scalar_8x32.h2
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h87
-rw-r--r--src/secp256k1/src/scalar_impl.h279
-rw-r--r--src/secp256k1/src/secp256k1.c311
-rw-r--r--src/secp256k1/src/testrand.h6
-rw-r--r--src/secp256k1/src/testrand_impl.h48
-rw-r--r--src/secp256k1/src/tests.c651
-rw-r--r--src/secp256k1/src/util.h21
-rw-r--r--src/test/alert_tests.cpp7
-rw-r--r--src/test/data/script_invalid.json46
-rw-r--r--src/test/data/script_valid.json42
-rw-r--r--src/test/mempool_tests.cpp104
-rw-r--r--src/test/test_bitcoin.cpp1
-rw-r--r--src/txmempool.cpp12
63 files changed, 3989 insertions, 1800 deletions
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index 40495cce8b..f90afa7f20 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -81,3 +81,16 @@ It will do the following automatically:
See doc/translation-process.md for more information.
+git-subtree-check.sh
+====================
+
+Run this script from the root of the repository to verify that a subtree matches the contents of
+the commit it claims to have been updated to.
+
+To use, make sure that you have fetched the upstream repository branch in which the subtree is
+maintained:
+* for src/secp256k1: https://github.com/bitcoin/secp256k1.git (branch master)
+* for sec/leveldb: https://github.com/bitcoin/leveldb.git (branch bitcoin-fork)
+
+Usage: git-subtree-check.sh DIR COMMIT
+COMMIT may be omitted, in which case HEAD is used.
diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh
new file mode 100755
index 0000000000..1cb82fe682
--- /dev/null
+++ b/contrib/devtools/git-subtree-check.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+DIR="$1"
+COMMIT="$2"
+if [ -z "$COMMIT" ]; then
+ COMMIT=HEAD
+fi
+
+# Taken from git-subtree (Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>)
+find_latest_squash()
+{
+ dir="$1"
+ sq=
+ main=
+ sub=
+ git log --grep="^git-subtree-dir: $dir/*\$" \
+ --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$COMMIT" |
+ while read a b junk; do
+ case "$a" in
+ START) sq="$b" ;;
+ git-subtree-mainline:) main="$b" ;;
+ git-subtree-split:) sub="$b" ;;
+ END)
+ if [ -n "$sub" ]; then
+ if [ -n "$main" ]; then
+ # a rejoin commit?
+ # Pretend its sub was a squash.
+ sq="$sub"
+ fi
+ echo "$sq" "$sub"
+ break
+ fi
+ sq=
+ main=
+ sub=
+ ;;
+ esac
+ done
+}
+
+latest_squash="$(find_latest_squash "$DIR")"
+if [ -z "$latest_squash" ]; then
+ echo "ERROR: $DIR is not a subtree" >&2
+ exit 2
+fi
+
+set $latest_squash
+old=$1
+rev=$2
+if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then
+ echo "ERROR: subtree commit $rev unavailable. Fetch/update the subtree repository" >&2
+ exit 2
+fi
+tree_subtree=$(git show -s --format="%T" $rev)
+echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)"
+tree_actual=$(git ls-tree -d "$COMMIT" "$DIR" | head -n 1)
+if [ -z "$tree_actual" ]; then
+ echo "FAIL: subtree directory $DIR not found in $COMMIT" >&2
+ exit 1
+fi
+set $tree_actual
+tree_actual_type=$2
+tree_actual_tree=$3
+echo "$DIR in $COMMIT currently refers to $tree_actual_type $tree_actual_tree"
+if [ "d$tree_actual_type" != "dtree" ]; then
+ echo "FAIL: subtree directory $DIR is not a tree in $COMMIT" >&2
+ exit 1
+fi
+if [ "$tree_actual_tree" != "$tree_subtree" ]; then
+ git diff-tree $tree_actual_tree $tree_subtree >&2
+ echo "FAIL: subtree directory tree doesn't match subtree commit tree" >&2
+ exit 1
+fi
+echo "GOOD"
diff --git a/doc/release-notes/release-notes-0.10.0.md b/doc/release-notes/release-notes-0.10.0.md
new file mode 100644
index 0000000000..986b8832ec
--- /dev/null
+++ b/doc/release-notes/release-notes-0.10.0.md
@@ -0,0 +1,762 @@
+Bitcoin Core version 0.10.0 is now available from:
+
+ https://bitcoin.org/bin/0.10.0/
+
+This is a new major version release, bringing both new features and
+bug fixes.
+
+Please report bugs using the issue tracker at github:
+
+ https://github.com/bitcoin/bitcoin/issues
+
+Upgrading and downgrading
+=========================
+
+How to Upgrade
+--------------
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or
+bitcoind/bitcoin-qt (on Linux).
+
+Downgrading warning
+---------------------
+
+Because release 0.10.0 makes use of headers-first synchronization and parallel
+block download (see further), the block files and databases are not
+backwards-compatible with older versions of Bitcoin Core or other software:
+
+* Blocks will be stored on disk out of order (in the order they are
+received, really), which makes it incompatible with some tools or
+other programs. Reindexing using earlier versions will also not work
+anymore as a result of this.
+
+* The block index database will now hold headers for which no block is
+stored on disk, which earlier versions won't support.
+
+If you want to be able to downgrade smoothly, make a backup of your entire data
+directory. Without this your node will need start syncing (or importing from
+bootstrap.dat) anew afterwards. It is possible that the data from a completely
+synchronised 0.10 node may be usable in older versions as-is, but this is not
+supported and may break as soon as the older version attempts to reindex.
+
+This does not affect wallet forward or backward compatibility.
+
+
+Notable changes
+===============
+
+Faster synchronization
+----------------------
+
+Bitcoin Core now uses 'headers-first synchronization'. This means that we first
+ask peers for block headers (a total of 27 megabytes, as of December 2014) and
+validate those. In a second stage, when the headers have been discovered, we
+download the blocks. However, as we already know about the whole chain in
+advance, the blocks can be downloaded in parallel from all available peers.
+
+In practice, this means a much faster and more robust synchronization. On
+recent hardware with a decent network link, it can be as little as 3 hours
+for an initial full synchronization. You may notice a slower progress in the
+very first few minutes, when headers are still being fetched and verified, but
+it should gain speed afterwards.
+
+A few RPCs were added/updated as a result of this:
+- `getblockchaininfo` now returns the number of validated headers in addition to
+the number of validated blocks.
+- `getpeerinfo` lists both the number of blocks and headers we know we have in
+common with each peer. While synchronizing, the heights of the blocks that we
+have requested from peers (but haven't received yet) are also listed as
+'inflight'.
+- A new RPC `getchaintips` lists all known branches of the block chain,
+including those we only have headers for.
+
+Transaction fee changes
+-----------------------
+
+This release automatically estimates how high a transaction fee (or how
+high a priority) transactions require to be confirmed quickly. The default
+settings will create transactions that confirm quickly; see the new
+'txconfirmtarget' setting to control the tradeoff between fees and
+confirmation times. Fees are added by default unless the 'sendfreetransactions'
+setting is enabled.
+
+Prior releases used hard-coded fees (and priorities), and would
+sometimes create transactions that took a very long time to confirm.
+
+Statistics used to estimate fees and priorities are saved in the
+data directory in the `fee_estimates.dat` file just before
+program shutdown, and are read in at startup.
+
+New command line options for transaction fee changes:
+- `-txconfirmtarget=n` : create transactions that have enough fees (or priority)
+so they are likely to begin confirmation within n blocks (default: 1). This setting
+is over-ridden by the -paytxfee option.
+- `-sendfreetransactions` : Send transactions as zero-fee transactions if possible
+(default: 0)
+
+New RPC commands for fee estimation:
+- `estimatefee nblocks` : Returns approximate fee-per-1,000-bytes needed for
+a transaction to begin confirmation within nblocks. Returns -1 if not enough
+transactions have been observed to compute a good estimate.
+- `estimatepriority nblocks` : Returns approximate priority needed for
+a zero-fee transaction to begin confirmation within nblocks. Returns -1 if not
+enough free transactions have been observed to compute a good
+estimate.
+
+RPC access control changes
+--------------------------
+
+Subnet matching for the purpose of access control is now done
+by matching the binary network address, instead of with string wildcard matching.
+For the user this means that `-rpcallowip` takes a subnet specification, which can be
+
+- a single IP address (e.g. `1.2.3.4` or `fe80::0012:3456:789a:bcde`)
+- a network/CIDR (e.g. `1.2.3.0/24` or `fe80::0000/64`)
+- a network/netmask (e.g. `1.2.3.4/255.255.255.0` or `fe80::0012:3456:789a:bcde/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff`)
+
+An arbitrary number of `-rpcallow` arguments can be given. An incoming connection will be accepted if its origin address
+matches one of them.
+
+For example:
+
+| 0.9.x and before | 0.10.x |
+|--------------------------------------------|---------------------------------------|
+| `-rpcallowip=192.168.1.1` | `-rpcallowip=192.168.1.1` (unchanged) |
+| `-rpcallowip=192.168.1.*` | `-rpcallowip=192.168.1.0/24` |
+| `-rpcallowip=192.168.*` | `-rpcallowip=192.168.0.0/16` |
+| `-rpcallowip=*` (dangerous!) | `-rpcallowip=::/0` (still dangerous!) |
+
+Using wildcards will result in the rule being rejected with the following error in debug.log:
+
+ Error: Invalid -rpcallowip subnet specification: *. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).
+
+
+REST interface
+--------------
+
+A new HTTP API is exposed when running with the `-rest` flag, which allows
+unauthenticated access to public node data.
+
+It is served on the same port as RPC, but does not need a password, and uses
+plain HTTP instead of JSON-RPC.
+
+Assuming a local RPC server running on port 8332, it is possible to request:
+- Blocks: http://localhost:8332/rest/block/*HASH*.*EXT*
+- Blocks without transactions: http://localhost:8332/rest/block/notxdetails/*HASH*.*EXT*
+- Transactions (requires `-txindex`): http://localhost:8332/rest/tx/*HASH*.*EXT*
+
+In every case, *EXT* can be `bin` (for raw binary data), `hex` (for hex-encoded
+binary) or `json`.
+
+For more details, see the `doc/REST-interface.md` document in the repository.
+
+RPC Server "Warm-Up" Mode
+-------------------------
+
+The RPC server is started earlier now, before most of the expensive
+intialisations like loading the block index. It is available now almost
+immediately after starting the process. However, until all initialisations
+are done, it always returns an immediate error with code -28 to all calls.
+
+This new behaviour can be useful for clients to know that a server is already
+started and will be available soon (for instance, so that they do not
+have to start it themselves).
+
+Improved signing security
+-------------------------
+
+For 0.10 the security of signing against unusual attacks has been
+improved by making the signatures constant time and deterministic.
+
+This change is a result of switching signing to use libsecp256k1
+instead of OpenSSL. Libsecp256k1 is a cryptographic library
+optimized for the curve Bitcoin uses which was created by Bitcoin
+Core developer Pieter Wuille.
+
+There exist attacks[1] against most ECC implementations where an
+attacker on shared virtual machine hardware could extract a private
+key if they could cause a target to sign using the same key hundreds
+of times. While using shared hosts and reusing keys are inadvisable
+for other reasons, it's a better practice to avoid the exposure.
+
+OpenSSL has code in their source repository for derandomization
+and reduction in timing leaks that we've eagerly wanted to use for a
+long time, but this functionality has still not made its
+way into a released version of OpenSSL. Libsecp256k1 achieves
+significantly stronger protection: As far as we're aware this is
+the only deployed implementation of constant time signing for
+the curve Bitcoin uses and we have reason to believe that
+libsecp256k1 is better tested and more thoroughly reviewed
+than the implementation in OpenSSL.
+
+[1] https://eprint.iacr.org/2014/161.pdf
+
+Watch-only wallet support
+-------------------------
+
+The wallet can now track transactions to and from wallets for which you know
+all addresses (or scripts), even without the private keys.
+
+This can be used to track payments without needing the private keys online on a
+possibly vulnerable system. In addition, it can help for (manual) construction
+of multisig transactions where you are only one of the signers.
+
+One new RPC, `importaddress`, is added which functions similarly to
+`importprivkey`, but instead takes an address or script (in hexadecimal) as
+argument. After using it, outputs credited to this address or script are
+considered to be received, and transactions consuming these outputs will be
+considered to be sent.
+
+The following RPCs have optional support for watch-only:
+`getbalance`, `listreceivedbyaddress`, `listreceivedbyaccount`,
+`listtransactions`, `listaccounts`, `listsinceblock`, `gettransaction`. See the
+RPC documentation for those methods for more information.
+
+Compared to using `getrawtransaction`, this mechanism does not require
+`-txindex`, scales better, integrates better with the wallet, and is compatible
+with future block chain pruning functionality. It does mean that all relevant
+addresses need to added to the wallet before the payment, though.
+
+Consensus library
+-----------------
+
+Starting from 0.10.0, the Bitcoin Core distribution includes a consensus library.
+
+The purpose of this library is to make the verification functionality that is
+critical to Bitcoin's consensus available to other applications, e.g. to language
+bindings such as [python-bitcoinlib](https://pypi.python.org/pypi/python-bitcoinlib) or
+alternative node implementations.
+
+This library is called `libbitcoinconsensus.so` (or, `.dll` for Windows).
+Its interface is defined in the C header [bitcoinconsensus.h](https://github.com/bitcoin/bitcoin/blob/0.10/src/script/bitcoinconsensus.h).
+
+In its initial version the API includes two functions:
+
+- `bitcoinconsensus_verify_script` verifies a script. It returns whether the indicated input of the provided serialized transaction
+correctly spends the passed scriptPubKey under additional constraints indicated by flags
+- `bitcoinconsensus_version` returns the API version, currently at an experimental `0`
+
+The functionality is planned to be extended to e.g. UTXO management in upcoming releases, but the interface
+for existing methods should remain stable.
+
+Standard script rules relaxed for P2SH addresses
+------------------------------------------------
+
+The IsStandard() rules have been almost completely removed for P2SH
+redemption scripts, allowing applications to make use of any valid
+script type, such as "n-of-m OR y", hash-locked oracle addresses, etc.
+While the Bitcoin protocol has always supported these types of script,
+actually using them on mainnet has been previously inconvenient as
+standard Bitcoin Core nodes wouldn't relay them to miners, nor would
+most miners include them in blocks they mined.
+
+bitcoin-tx
+----------
+
+It has been observed that many of the RPC functions offered by bitcoind are
+"pure functions", and operate independently of the bitcoind wallet. This
+included many of the RPC "raw transaction" API functions, such as
+createrawtransaction.
+
+bitcoin-tx is a newly introduced command line utility designed to enable easy
+manipulation of bitcoin transactions. A summary of its operation may be
+obtained via "bitcoin-tx --help" Transactions may be created or signed in a
+manner similar to the RPC raw tx API. Transactions may be updated, deleting
+inputs or outputs, or appending new inputs and outputs. Custom scripts may be
+easily composed using a simple text notation, borrowed from the bitcoin test
+suite.
+
+This tool may be used for experimenting with new transaction types, signing
+multi-party transactions, and many other uses. Long term, the goal is to
+deprecate and remove "pure function" RPC API calls, as those do not require a
+server round-trip to execute.
+
+Other utilities "bitcoin-key" and "bitcoin-script" have been proposed, making
+key and script operations easily accessible via command line.
+
+Mining and relay policy enhancements
+------------------------------------
+
+Bitcoin Core's block templates are now for version 3 blocks only, and any mining
+software relying on its `getblocktemplate` must be updated in parallel to use
+libblkmaker either version 0.4.2 or any version from 0.5.1 onward.
+If you are solo mining, this will affect you the moment you upgrade Bitcoin
+Core, which must be done prior to BIP66 achieving its 951/1001 status.
+If you are mining with the stratum mining protocol: this does not affect you.
+If you are mining with the getblocktemplate protocol to a pool: this will affect
+you at the pool operator's discretion, which must be no later than BIP66
+achieving its 951/1001 status.
+
+The `prioritisetransaction` RPC method has been added to enable miners to
+manipulate the priority of transactions on an individual basis.
+
+Bitcoin Core now supports BIP 22 long polling, so mining software can be
+notified immediately of new templates rather than having to poll periodically.
+
+Support for BIP 23 block proposals is now available in Bitcoin Core's
+`getblocktemplate` method. This enables miners to check the basic validity of
+their next block before expending work on it, reducing risks of accidental
+hardforks or mining invalid blocks.
+
+Two new options to control mining policy:
+- `-datacarrier=0/1` : Relay and mine "data carrier" (OP_RETURN) transactions
+if this is 1.
+- `-datacarriersize=n` : Maximum size, in bytes, we consider acceptable for
+"data carrier" outputs.
+
+The relay policy has changed to more properly implement the desired behavior of not
+relaying free (or very low fee) transactions unless they have a priority above the
+AllowFreeThreshold(), in which case they are relayed subject to the rate limiter.
+
+BIP 66: strict DER encoding for signatures
+------------------------------------------
+
+Bitcoin Core 0.10 implements BIP 66, which introduces block version 3, and a new
+consensus rule, which prohibits non-DER signatures. Such transactions have been
+non-standard since Bitcoin v0.8.0 (released in February 2013), but were
+technically still permitted inside blocks.
+
+This change breaks the dependency on OpenSSL's signature parsing, and is
+required if implementations would want to remove all of OpenSSL from the
+consensus code.
+
+The same miner-voting mechanism as in BIP 34 is used: when 751 out of a
+sequence of 1001 blocks have version number 3 or higher, the new consensus
+rule becomes active for those blocks. When 951 out of a sequence of 1001
+blocks have version number 3 or higher, it becomes mandatory for all blocks.
+
+Backward compatibility with current mining software is NOT provided, thus miners
+should read the first paragraph of "Mining and relay policy enhancements" above.
+
+0.10.0 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect external
+behavior, not code moves, refactors or string updates.
+
+RPC:
+- `f923c07` Support IPv6 lookup in bitcoin-cli even when IPv6 only bound on localhost
+- `b641c9c` Fix addnode "onetry": Connect with OpenNetworkConnection
+- `171ca77` estimatefee / estimatepriority RPC methods
+- `b750cf1` Remove cli functionality from bitcoind
+- `f6984e8` Add "chain" to getmininginfo, improve help in getblockchaininfo
+- `99ddc6c` Add nLocalServices info to RPC getinfo
+- `cf0c47b` Remove getwork() RPC call
+- `2a72d45` prioritisetransaction <txid> <priority delta> <priority tx fee>
+- `e44fea5` Add an option `-datacarrier` to allow users to disable relaying/mining data carrier transactions
+- `2ec5a3d` Prevent easy RPC memory exhaustion attack
+- `d4640d7` Added argument to getbalance to include watchonly addresses and fixed errors in balance calculation
+- `83f3543` Added argument to listaccounts to include watchonly addresses
+- `952877e` Showing 'involvesWatchonly' property for transactions returned by 'listtransactions' and 'listsinceblock'. It is only appended when the transaction involves a watchonly address
+- `d7d5d23` Added argument to listtransactions and listsinceblock to include watchonly addresses
+- `f87ba3d` added includeWatchonly argument to 'gettransaction' because it affects balance calculation
+- `0fa2f88` added includedWatchonly argument to listreceivedbyaddress/...account
+- `6c37f7f` `getrawchangeaddress`: fail when keypool exhausted and wallet locked
+- `ff6a7af` getblocktemplate: longpolling support
+- `c4a321f` Add peerid to getpeerinfo to allow correlation with the logs
+- `1b4568c` Add vout to ListTransactions output
+- `b33bd7a` Implement "getchaintips" RPC command to monitor blockchain forks
+- `733177e` Remove size limit in RPC client, keep it in server
+- `6b5b7cb` Categorize rpc help overview
+- `6f2c26a` Closely track mempool byte total. Add "getmempoolinfo" RPC
+- `aa82795` Add detailed network info to getnetworkinfo RPC
+- `01094bd` Don't reveal whether password is <20 or >20 characters in RPC
+- `57153d4` rpc: Compute number of confirmations of a block from block height
+- `ff36cbe` getnetworkinfo: export local node's client sub-version string
+- `d14d7de` SanitizeString: allow '(' and ')'
+- `31d6390` Fixed setaccount accepting foreign address
+- `b5ec5fe` update getnetworkinfo help with subversion
+- `ad6e601` RPC additions after headers-first
+- `33dfbf5` rpc: Fix leveldb iterator leak, and flush before `gettxoutsetinfo`
+- `2aa6329` Enable customising node policy for datacarrier data size with a -datacarriersize option
+- `f877aaa` submitblock: Use a temporary CValidationState to determine accurately the outcome of ProcessBlock
+- `e69a587` submitblock: Support for returning specific rejection reasons
+- `af82884` Add "warmup mode" for RPC server
+- `e2655e0` Add unauthenticated HTTP REST interface to public blockchain data
+- `683dc40` Disable SSLv3 (in favor of TLS) for the RPC client and server
+- `44b4c0d` signrawtransaction: validate private key
+- `9765a50` Implement BIP 23 Block Proposal
+- `f9de17e` Add warning comment to getinfo
+
+Command-line options:
+- `ee21912` Use netmasks instead of wildcards for IP address matching
+- `deb3572` Add `-rpcbind` option to allow binding RPC port on a specific interface
+- `96b733e` Add `-version` option to get just the version
+- `1569353` Add `-stopafterblockimport` option
+- `77cbd46` Let -zapwallettxes recover transaction meta data
+- `1c750db` remove -tor compatibility code (only allow -onion)
+- `4aaa017` rework help messages for fee-related options
+- `4278b1d` Clarify error message when invalid -rpcallowip
+- `6b407e4` -datadir is now allowed in config files
+- `bdd5b58` Add option `-sysperms` to disable 077 umask (create new files with system default umask)
+- `cbe39a3` Add "bitcoin-tx" command line utility and supporting modules
+- `dbca89b` Trigger -alertnotify if network is upgrading without you
+- `ad96e7c` Make -reindex cope with out-of-order blocks
+- `16d5194` Skip reindexed blocks individually
+- `ec01243` --tracerpc option for regression tests
+- `f654f00` Change -genproclimit default to 1
+- `3c77714` Make -proxy set all network types, avoiding a connect leak
+- `57be955` Remove -printblock, -printblocktree, and -printblockindex
+- `ad3d208` remove -maxorphanblocks config parameter since it is no longer functional
+
+Block and transaction handling:
+- `7a0e84d` ProcessGetData(): abort if a block file is missing from disk
+- `8c93bf4` LoadBlockIndexDB(): Require block db reindex if any `blk*.dat` files are missing
+- `77339e5` Get rid of the static chainMostWork (optimization)
+- `4e0eed8` Allow ActivateBestChain to release its lock on cs_main
+- `18e7216` Push cs_mains down in ProcessBlock
+- `fa126ef` Avoid undefined behavior using CFlatData in CScript serialization
+- `7f3b4e9` Relax IsStandard rules for pay-to-script-hash transactions
+- `c9a0918` Add a skiplist to the CBlockIndex structure
+- `bc42503` Use unordered_map for CCoinsViewCache with salted hash (optimization)
+- `d4d3fbd` Do not flush the cache after every block outside of IBD (optimization)
+- `ad08d0b` Bugfix: make CCoinsViewMemPool support pruned entries in underlying cache
+- `5734d4d` Only remove actualy failed blocks from setBlockIndexValid
+- `d70bc52` Rework block processing benchmark code
+- `714a3e6` Only keep setBlockIndexValid entries that are possible improvements
+- `ea100c7` Reduce maximum coinscache size during verification (reduce memory usage)
+- `4fad8e6` Reject transactions with excessive numbers of sigops
+- `b0875eb` Allow BatchWrite to destroy its input, reducing copying (optimization)
+- `92bb6f2` Bypass reloading blocks from disk (optimization)
+- `2e28031` Perform CVerifyDB on pcoinsdbview instead of pcoinsTip (reduce memory usage)
+- `ab15b2e` Avoid copying undo data (optimization)
+- `341735e` Headers-first synchronization
+- `afc32c5` Fix rebuild-chainstate feature and improve its performance
+- `e11b2ce` Fix large reorgs
+- `ed6d1a2` Keep information about all block files in memory
+- `a48f2d6` Abstract context-dependent block checking from acceptance
+- `7e615f5` Fixed mempool sync after sending a transaction
+- `51ce901` Improve chainstate/blockindex disk writing policy
+- `a206950` Introduce separate flushing modes
+- `9ec75c5` Add a locking mechanism to IsInitialBlockDownload to ensure it never goes from false to true
+- `868d041` Remove coinbase-dependant transactions during reorg
+- `723d12c` Remove txn which are invalidated by coinbase maturity during reorg
+- `0cb8763` Check against MANDATORY flags prior to accepting to mempool
+- `8446262` Reject headers that build on an invalid parent
+- `008138c` Bugfix: only track UTXO modification after lookup
+
+P2P protocol and network code:
+- `f80cffa` Do not trigger a DoS ban if SCRIPT_VERIFY_NULLDUMMY fails
+- `c30329a` Add testnet DNS seed of Alex Kotenko
+- `45a4baf` Add testnet DNS seed of Andreas Schildbach
+- `f1920e8` Ping automatically every 2 minutes (unconditionally)
+- `806fd19` Allocate receive buffers in on the fly
+- `6ecf3ed` Display unknown commands received
+- `aa81564` Track peers' available blocks
+- `caf6150` Use async name resolving to improve net thread responsiveness
+- `9f4da19` Use pong receive time rather than processing time
+- `0127a9b` remove SOCKS4 support from core and GUI, use SOCKS5
+- `40f5cb8` Send rejects and apply DoS scoring for errors in direct block validation
+- `dc942e6` Introduce whitelisted peers
+- `c994d2e` prevent SOCKET leak in BindListenPort()
+- `a60120e` Add built-in seeds for .onion
+- `60dc8e4` Allow -onlynet=onion to be used
+- `3a56de7` addrman: Do not propagate obviously poor addresses onto the network
+- `6050ab6` netbase: Make SOCKS5 negotiation interruptible
+- `604ee2a` Remove tx from AlreadyAskedFor list once we receive it, not when we process it
+- `efad808` Avoid reject message feedback loops
+- `71697f9` Separate protocol versioning from clientversion
+- `20a5f61` Don't relay alerts to peers before version negotiation
+- `b4ee0bd` Introduce preferred download peers
+- `845c86d` Do not use third party services for IP detection
+- `12a49ca` Limit the number of new addressses to accumulate
+- `35e408f` Regard connection failures as attempt for addrman
+- `a3a7317` Introduce 10 minute block download timeout
+- `3022e7d` Require sufficent priority for relay of free transactions
+- `58fda4d` Update seed IPs, based on bitcoin.sipa.be crawler data
+- `18021d0` Remove bitnodes.io from dnsseeds.
+
+Validation:
+- `6fd7ef2` Also switch the (unused) verification code to low-s instead of even-s
+- `584a358` Do merkle root and txid duplicates check simultaneously
+- `217a5c9` When transaction outputs exceed inputs, show the offending amounts so as to aid debugging
+- `f74fc9b` Print input index when signature validation fails, to aid debugging
+- `6fd59ee` script.h: set_vch() should shift a >32 bit value
+- `d752ba8` Add SCRIPT_VERIFY_SIGPUSHONLY (BIP62 rule 2) (test only)
+- `698c6ab` Add SCRIPT_VERIFY_MINIMALDATA (BIP62 rules 3 and 4) (test only)
+- `ab9edbd` script: create sane error return codes for script validation and remove logging
+- `219a147` script: check ScriptError values in script tests
+- `0391423` Discourage NOPs reserved for soft-fork upgrades
+- `98b135f` Make STRICTENC invalid pubkeys fail the script rather than the opcode
+- `307f7d4` Report script evaluation failures in log and reject messages
+- `ace39db` consensus: guard against openssl's new strict DER checks
+- `12b7c44` Improve robustness of DER recoding code
+- `76ce5c8` fail immediately on an empty signature
+
+Build system:
+- `f25e3ad` Fix build in OS X 10.9
+- `65e8ba4` build: Switch to non-recursive make
+- `460b32d` build: fix broken boost chrono check on some platforms
+- `9ce0774` build: Fix windows configure when using --with-qt-libdir
+- `ea96475` build: Add mention of --disable-wallet to bdb48 error messages
+- `1dec09b` depends: add shared dependency builder
+- `c101c76` build: Add --with-utils (bitcoin-cli and bitcoin-tx, default=yes). Help string consistency tweaks. Target sanity check fix
+- `e432a5f` build: add option for reducing exports (v2)
+- `6134b43` Fixing condition 'sabotaging' MSVC build
+- `af0bd5e` osx: fix signing to make Gatekeeper happy (again)
+- `a7d1f03` build: fix dynamic boost check when --with-boost= is used
+- `d5fd094` build: fix qt test build when libprotobuf is in a non-standard path
+- `2cf5f16` Add libbitcoinconsensus library
+- `914868a` build: add a deterministic dmg signer
+- `2d375fe` depends: bump openssl to 1.0.1k
+- `b7a4ecc` Build: Only check for boost when building code that requires it
+
+Wallet:
+- `b33d1f5` Use fee/priority estimates in wallet CreateTransaction
+- `4b7b1bb` Sanity checks for estimates
+- `c898846` Add support for watch-only addresses
+- `d5087d1` Use script matching rather than destination matching for watch-only
+- `d88af56` Fee fixes
+- `a35b55b` Dont run full check every time we decrypt wallet
+- `3a7c348` Fix make_change to not create half-satoshis
+- `f606bb9` fix a possible memory leak in CWalletDB::Recover
+- `870da77` fix possible memory leaks in CWallet::EncryptWallet
+- `ccca27a` Watch-only fixes
+- `9b1627d` [Wallet] Reduce minTxFee for transaction creation to 1000 satoshis
+- `a53fd41` Deterministic signing
+- `15ad0b5` Apply AreSane() checks to the fees from the network
+- `11855c1` Enforce minRelayTxFee on wallet created tx and add a maxtxfee option
+
+GUI:
+- `c21c74b` osx: Fix missing dock menu with qt5
+- `b90711c` Fix Transaction details shows wrong To:
+- `516053c` Make links in 'About Bitcoin Core' clickable
+- `bdc83e8` Ensure payment request network matches client network
+- `65f78a1` Add GUI view of peer information
+- `06a91d9` VerifyDB progress reporting
+- `fe6bff2` Add BerkeleyDB version info to RPCConsole
+- `b917555` PeerTableModel: Fix potential deadlock. #4296
+- `dff0e3b` Improve rpc console history behavior
+- `95a9383` Remove CENT-fee-rule from coin control completely
+- `56b07d2` Allow setting listen via GUI
+- `d95ba75` Log messages with type>QtDebugMsg as non-debug
+- `8969828` New status bar Unit Display Control and related changes
+- `674c070` seed OpenSSL PNRG with Windows event data
+- `509f926` Payment request parsing on startup now only changes network if a valid network name is specified
+- `acd432b` Prevent balloon-spam after rescan
+- `7007402` Implement SI-style (thin space) thoudands separator
+- `91cce17` Use fixed-point arithmetic in amount spinbox
+- `bdba2dd` Remove an obscure option no-one cares about
+- `bd0aa10` Replace the temporary file hack currently used to change Bitcoin-Qt's dock icon (OS X) with a buffer-based solution
+- `94e1b9e` Re-work overviewpage UI
+- `8bfdc9a` Better looking trayicon
+- `b197bf3` disable tray interactions when client model set to 0
+- `1c5f0af` Add column Watch-only to transactions list
+- `21f139b` Fix tablet crash. closes #4854
+- `e84843c` Broken addresses on command line no longer trigger testnet
+- `a49f11d` Change splash screen to normal window
+- `1f9be98` Disable App Nap on OSX 10.9+
+- `27c3e91` Add proxy to options overridden if necessary
+- `4bd1185` Allow "emergency" shutdown during startup
+- `d52f072` Don't show wallet options in the preferences menu when running with -disablewallet
+- `6093aa1` Qt: QProgressBar CPU-Issue workaround
+- `0ed9675` [Wallet] Add global boolean whether to send free transactions (default=true)
+- `ed3e5e4` [Wallet] Add global boolean whether to pay at least the custom fee (default=true)
+- `e7876b2` [Wallet] Prevent user from paying a non-sense fee
+- `c1c9d5b` Add Smartfee to GUI
+- `e0a25c5` Make askpassphrase dialog behave more sanely
+- `94b362d` On close of splashscreen interrupt verifyDB
+- `b790d13` English translation update
+- `8543b0d` Correct tooltip on address book page
+
+Tests:
+- `b41e594` Fix script test handling of empty scripts
+- `d3a33fc` Test CHECKMULTISIG with m == 0 and n == 0
+- `29c1749` Let tx (in)valid tests use any SCRIPT_VERIFY flag
+- `6380180` Add rejection of non-null CHECKMULTISIG dummy values
+- `21bf3d2` Add tests for BoostAsioToCNetAddr
+- `b5ad5e7` Add Python test for -rpcbind and -rpcallowip
+- `9ec0306` Add CODESEPARATOR/FindAndDelete() tests
+- `75ebced` Added many rpc wallet tests
+- `0193fb8` Allow multiple regression tests to run at once
+- `92a6220` Hook up sanity checks
+- `3820e01` Extend and move all crypto tests to crypto_tests.cpp
+- `3f9a019` added list/get received by address/ account tests
+- `a90689f` Remove timing-based signature cache unit test
+- `236982c` Add skiplist unit tests
+- `f4b00be` Add CChain::GetLocator() unit test
+- `b45a6e8` Add test for getblocktemplate longpolling
+- `cdf305e` Set -discover=0 in regtest framework
+- `ed02282` additional test for OP_SIZE in script_valid.json
+- `0072d98` script tests: BOOLAND, BOOLOR decode to integer
+- `833ff16` script tests: values that overflow to 0 are true
+- `4cac5db` script tests: value with trailing 0x00 is true
+- `89101c6` script test: test case for 5-byte bools
+- `d2d9dc0` script tests: add tests for CHECKMULTISIG limits
+- `d789386` Add "it works" test for bitcoin-tx
+- `df4d61e` Add bitcoin-tx tests
+- `aa41ac2` Test IsPushOnly() with invalid push
+- `6022b5d` Make `script_{valid,invalid}.json` validation flags configurable
+- `8138cbe` Add automatic script test generation, and actual checksig tests
+- `ed27e53` Add coins_tests with a large randomized CCoinViewCache test
+- `9df9cf5` Make SCRIPT_VERIFY_STRICTENC compatible with BIP62
+- `dcb9846` Extend getchaintips RPC test
+- `554147a` Ensure MINIMALDATA invalid tests can only fail one way
+- `dfeec18` Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule
+- `2b62e17` Clearly separate PUSHDATA and numeric argument MINIMALDATA tests
+- `16d78bd` Add valid invert of invalid every numeric opcode tests
+- `f635269` tests: enable alertnotify test for Windows
+- `7a41614` tests: allow rpc-tests to get filenames for bitcoind and bitcoin-cli from the environment
+- `5122ea7` tests: fix forknotify.py on windows
+- `fa7f8cd` tests: remove old pull-tester scripts
+- `7667850` tests: replace the old (unused since Travis) tests with new rpc test scripts
+- `f4e0aef` Do signature-s negation inside the tests
+- `1837987` Optimize -regtest setgenerate block generation
+- `2db4c8a` Fix node ranges in the test framework
+- `a8b2ce5` regression test only setmocktime RPC call
+- `daf03e7` RPC tests: create initial chain with specific timestamps
+- `8656dbb` Port/fix txnmall.sh regression test
+- `ca81587` Test the exact order of CHECKMULTISIG sig/pubkey evaluation
+- `7357893` Prioritize and display -testsafemode status in UI
+- `f321d6b` Add key generation/verification to ECC sanity check
+- `132ea9b` miner_tests: Disable checkpoints so they don't fail the subsidy-change test
+- `bc6cb41` QA RPC tests: Add tests block block proposals
+- `f67a9ce` Use deterministically generated script tests
+- `11d7a7d` [RPC] add rpc-test for http keep-alive (persistent connections)
+- `34318d7` RPC-test based on invalidateblock for mempool coinbase spends
+- `76ec867` Use actually valid transactions for script tests
+- `c8589bf` Add actual signature tests
+- `e2677d7` Fix smartfees test for change to relay policy
+- `263b65e` tests: run sanity checks in tests too
+
+Miscellaneous:
+- `122549f` Fix incorrect checkpoint data for testnet3
+- `5bd02cf` Log used config file to debug.log on startup
+- `68ba85f` Updated Debian example bitcoin.conf with config from wiki + removed some cruft and updated comments
+- `e5ee8f0` Remove -beta suffix
+- `38405ac` Add comment regarding experimental-use service bits
+- `be873f6` Issue warning if collecting RandSeed data failed
+- `8ae973c` Allocate more space if necessary in RandSeedAddPerfMon
+- `675bcd5` Correct comment for 15-of-15 p2sh script size
+- `fda3fed` libsecp256k1 integration
+- `2e36866` Show nodeid instead of addresses in log (for anonymity) unless otherwise requested
+- `cd01a5e` Enable paranoid corruption checks in LevelDB >= 1.16
+- `9365937` Add comment about never updating nTimeOffset past 199 samples
+- `403c1bf` contrib: remove getwork-based pyminer (as getwork API call has been removed)
+- `0c3e101` contrib: Added systemd .service file in order to help distributions integrate bitcoind
+- `0a0878d` doc: Add new DNSseed policy
+- `2887bff` Update coding style and add .clang-format
+- `5cbda4f` Changed LevelDB cursors to use scoped pointers to ensure destruction when going out of scope
+- `b4a72a7` contrib/linearize: split output files based on new-timestamp-year or max-file-size
+- `e982b57` Use explicit fflush() instead of setvbuf()
+- `234bfbf` contrib: Add init scripts and docs for Upstart and OpenRC
+- `01c2807` Add warning about the merkle-tree algorithm duplicate txid flaw
+- `d6712db` Also create pid file in non-daemon mode
+- `772ab0e` contrib: use batched JSON-RPC in linarize-hashes (optimization)
+- `7ab4358` Update bash-completion for v0.10
+- `6e6a36c` contrib: show pull # in prompt for github-merge script
+- `5b9f842` Upgrade leveldb to 1.18, make chainstate databases compatible between ARM and x86 (issue #2293)
+- `4e7c219` Catch UTXO set read errors and shutdown
+- `867c600` Catch LevelDB errors during flush
+- `06ca065` Fix CScriptID(const CScript& in) in empty script case
+
+Credits
+=======
+
+Thanks to everyone who contributed to this release:
+
+- 21E14
+- Adam Weiss
+- Aitor Pazos
+- Alexander Jeng
+- Alex Morcos
+- Alon Muroch
+- Andreas Schildbach
+- Andrew Poelstra
+- Andy Alness
+- Ashley Holman
+- Benedict Chan
+- Ben Holden-Crowther
+- Bryan Bishop
+- BtcDrak
+- Christian von Roques
+- Clinton Christian
+- Cory Fields
+- Cozz Lovan
+- daniel
+- Daniel Kraft
+- David Hill
+- Derek701
+- dexX7
+- dllud
+- Dominyk Tiller
+- Doug
+- elichai
+- elkingtowa
+- ENikS
+- Eric Shaw
+- Federico Bond
+- Francis GASCHET
+- Gavin Andresen
+- Giuseppe Mazzotta
+- Glenn Willen
+- Gregory Maxwell
+- gubatron
+- HarryWu
+- himynameismartin
+- Huang Le
+- Ian Carroll
+- imharrywu
+- Jameson Lopp
+- Janusz Lenar
+- JaSK
+- Jeff Garzik
+- JL2035
+- Johnathan Corgan
+- Jonas Schnelli
+- jtimon
+- Julian Haight
+- Kamil Domanski
+- kazcw
+- kevin
+- kiwigb
+- Kosta Zertsekel
+- LongShao007
+- Luke Dashjr
+- Mark Friedenbach
+- Mathy Vanvoorden
+- Matt Corallo
+- Matthew Bogosian
+- Micha
+- Michael Ford
+- Mike Hearn
+- mrbandrews
+- mruddy
+- ntrgn
+- Otto Allmendinger
+- paveljanik
+- Pavel Vasin
+- Peter Todd
+- phantomcircuit
+- Philip Kaufmann
+- Pieter Wuille
+- pryds
+- randy-waterhouse
+- R E Broadley
+- Rose Toomey
+- Ross Nicoll
+- Roy Badami
+- Ruben Dario Ponticelli
+- Rune K. Svendsen
+- Ryan X. Charles
+- Saivann
+- sandakersmann
+- SergioDemianLerner
+- shshshsh
+- sinetek
+- Stuart Cardall
+- Suhas Daftuar
+- Tawanda Kembo
+- Teran McKinney
+- tm314159
+- Tom Harding
+- Trevin Hofmann
+- Whit J
+- Wladimir J. van der Laan
+- Yoichi Hirai
+- Zak Wilcox
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
+
diff --git a/doc/release-process.md b/doc/release-process.md
index 016090c594..5dad9bf5de 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -133,15 +133,22 @@ rm SHA256SUMS
Note: check that SHA256SUMS itself doesn't end up in SHA256SUMS, which is a spurious/nonsensical entry.
- Upload zips and installers, as well as `SHA256SUMS.asc` from last step, to the bitcoin.org server
+ into `/var/www/bin/bitcoin-core-${VERSION}`
- Update bitcoin.org version
- - Make a pull request to add a file named `YYYY-MM-DD-vX.Y.Z.md` with the release notes
- to https://github.com/bitcoin/bitcoin.org/tree/master/_releases
- ([Example for 0.9.2.1](https://raw.githubusercontent.com/bitcoin/bitcoin.org/master/_releases/2014-06-19-v0.9.2.1.md)).
+ - First, check to see if the Bitcoin.org maintainers have prepared a
+ release: https://github.com/bitcoin/bitcoin.org/labels/Releases
- - After the pull request is merged, the website will automatically show the newest version, as well
- as update the OS download links. Ping Saivann in case anything goes wrong
+ - If they have, it will have previously failed their Travis CI
+ checks because the final release files weren't uploaded.
+ Trigger a Travis CI rebuild---if it passes, merge.
+
+ - If they have not prepared a release, follow the Bitcoin.org release
+ instructions: https://github.com/bitcoin/bitcoin.org#release-notes
+
+ - After the pull request is merged, the website will automatically show the newest version within 15 minutes, as well
+ as update the OS download links. Ping @saivann/@harding (saivann/harding on Freenode) in case anything goes wrong
- Announce the release:
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 8dd0a28454..52ff3f224f 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -50,6 +50,7 @@ BITCOIN_TESTS =\
test/hash_tests.cpp \
test/key_tests.cpp \
test/main_tests.cpp \
+ test/mempool_tests.cpp \
test/miner_tests.cpp \
test/mruset_tests.cpp \
test/multisig_tests.cpp \
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 4b7e4d51b9..5d9527f0e1 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -10,34 +10,27 @@
using namespace std;
-int CAddrInfo::GetTriedBucket(const std::vector<unsigned char>& nKey) const
+int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
- CDataStream ss1(SER_GETHASH, 0);
- std::vector<unsigned char> vchKey = GetKey();
- ss1 << nKey << vchKey;
- uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetCheapHash();
-
- CDataStream ss2(SER_GETHASH, 0);
- std::vector<unsigned char> vchGroupKey = GetGroup();
- ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
- uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetCheapHash();
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash();
+ uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetCheapHash();
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
-int CAddrInfo::GetNewBucket(const std::vector<unsigned char>& nKey, const CNetAddr& src) const
+int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const
{
- CDataStream ss1(SER_GETHASH, 0);
- std::vector<unsigned char> vchGroupKey = GetGroup();
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();
- ss1 << nKey << vchGroupKey << vchSourceGroupKey;
- uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetCheapHash();
-
- CDataStream ss2(SER_GETHASH, 0);
- ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
- uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetCheapHash();
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey).GetHash().GetCheapHash();
+ uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetCheapHash();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
+int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
+{
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetCheapHash();
+ return hash1 % ADDRMAN_BUCKET_SIZE;
+}
+
bool CAddrInfo::IsTerrible(int64_t nNow) const
{
if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
@@ -70,8 +63,6 @@ double CAddrInfo::GetChance(int64_t nNow) const
if (nSinceLastTry < 0)
nSinceLastTry = 0;
- fChance *= 600.0 / (600.0 + nSinceLastSeen);
-
// deprioritize very recent attempts away
if (nSinceLastTry < 60 * 10)
fChance *= 0.01;
@@ -128,85 +119,44 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
vRandom[nRndPos2] = nId1;
}
-int CAddrMan::SelectTried(int nKBucket)
+void CAddrMan::Delete(int nId)
{
- std::vector<int>& vTried = vvTried[nKBucket];
-
- // randomly shuffle the first few elements (using the entire list)
- // find the least recently tried among them
- int64_t nOldest = -1;
- int nOldestPos = -1;
- for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++) {
- int nPos = GetRandInt(vTried.size() - i) + i;
- int nTemp = vTried[nPos];
- vTried[nPos] = vTried[i];
- vTried[i] = nTemp;
- assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
- if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
- nOldest = nTemp;
- nOldestPos = nPos;
- }
- }
+ assert(mapInfo.count(nId) != 0);
+ CAddrInfo& info = mapInfo[nId];
+ assert(!info.fInTried);
+ assert(info.nRefCount == 0);
- return nOldestPos;
+ SwapRandom(info.nRandomPos, vRandom.size() - 1);
+ vRandom.pop_back();
+ mapAddr.erase(info);
+ mapInfo.erase(nId);
+ nNew--;
}
-int CAddrMan::ShrinkNew(int nUBucket)
+void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
{
- assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size());
- std::set<int>& vNew = vvNew[nUBucket];
-
- // first look for deletable items
- for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) {
- assert(mapInfo.count(*it));
- CAddrInfo& info = mapInfo[*it];
- if (info.IsTerrible()) {
- if (--info.nRefCount == 0) {
- SwapRandom(info.nRandomPos, vRandom.size() - 1);
- vRandom.pop_back();
- mapAddr.erase(info);
- mapInfo.erase(*it);
- nNew--;
- }
- vNew.erase(it);
- return 0;
- }
- }
-
- // otherwise, select four randomly, and pick the oldest of those to replace
- int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())};
- int nI = 0;
- int nOldest = -1;
- for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) {
- if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3]) {
- assert(nOldest == -1 || mapInfo.count(*it) == 1);
- if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
- nOldest = *it;
+ // if there is an entry in the specified bucket, delete it.
+ if (vvNew[nUBucket][nUBucketPos] != -1) {
+ int nIdDelete = vvNew[nUBucket][nUBucketPos];
+ CAddrInfo& infoDelete = mapInfo[nIdDelete];
+ assert(infoDelete.nRefCount > 0);
+ infoDelete.nRefCount--;
+ vvNew[nUBucket][nUBucketPos] = -1;
+ if (infoDelete.nRefCount == 0) {
+ Delete(nIdDelete);
}
- nI++;
- }
- assert(mapInfo.count(nOldest) == 1);
- CAddrInfo& info = mapInfo[nOldest];
- if (--info.nRefCount == 0) {
- SwapRandom(info.nRandomPos, vRandom.size() - 1);
- vRandom.pop_back();
- mapAddr.erase(info);
- mapInfo.erase(nOldest);
- nNew--;
}
- vNew.erase(nOldest);
-
- return 1;
}
-void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
+void CAddrMan::MakeTried(CAddrInfo& info, int nId)
{
- assert(vvNew[nOrigin].count(nId) == 1);
-
// remove the entry from all new buckets
- for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++) {
- if ((*it).erase(nId))
+ for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
+ int pos = info.GetBucketPosition(nKey, true, bucket);
+ if (vvNew[bucket][pos] == nId) {
+ vvNew[bucket][pos] = -1;
info.nRefCount--;
+ }
}
nNew--;
@@ -214,44 +164,36 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
// which tried bucket to move the entry to
int nKBucket = info.GetTriedBucket(nKey);
- std::vector<int>& vTried = vvTried[nKBucket];
-
- // first check whether there is place to just add it
- if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) {
- vTried.push_back(nId);
- nTried++;
- info.fInTried = true;
- return;
- }
-
- // otherwise, find an item to evict
- int nPos = SelectTried(nKBucket);
-
- // find which new bucket it belongs to
- assert(mapInfo.count(vTried[nPos]) == 1);
- int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
- std::set<int>& vNew = vvNew[nUBucket];
-
- // remove the to-be-replaced tried entry from the tried set
- CAddrInfo& infoOld = mapInfo[vTried[nPos]];
- infoOld.fInTried = false;
- infoOld.nRefCount = 1;
- // do not update nTried, as we are going to move something else there immediately
-
- // check whether there is place in that one,
- if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) {
- // if so, move it back there
- vNew.insert(vTried[nPos]);
- } else {
- // otherwise, move it to the new bucket nId came from (there is certainly place there)
- vvNew[nOrigin].insert(vTried[nPos]);
+ int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
+
+ // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
+ if (vvTried[nKBucket][nKBucketPos] != -1) {
+ // find an item to evict
+ int nIdEvict = vvTried[nKBucket][nKBucketPos];
+ assert(mapInfo.count(nIdEvict) == 1);
+ CAddrInfo& infoOld = mapInfo[nIdEvict];
+
+ // Remove the to-be-evicted item from the tried set.
+ infoOld.fInTried = false;
+ vvTried[nKBucket][nKBucketPos] = -1;
+ nTried--;
+
+ // find which new bucket it belongs to
+ int nUBucket = infoOld.GetNewBucket(nKey);
+ int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
+ ClearNew(nUBucket, nUBucketPos);
+ assert(vvNew[nUBucket][nUBucketPos] == -1);
+
+ // Enter it into the new set again.
+ infoOld.nRefCount = 1;
+ vvNew[nUBucket][nUBucketPos] = nIdEvict;
+ nNew++;
}
- nNew++;
+ assert(vvTried[nKBucket][nKBucketPos] == -1);
- vTried[nPos] = nId;
- // we just overwrote an entry in vTried; no need to update nTried
+ vvTried[nKBucket][nKBucketPos] = nId;
+ nTried++;
info.fInTried = true;
- return;
}
void CAddrMan::Good_(const CService& addr, int64_t nTime)
@@ -281,12 +223,12 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
return;
// find a bucket it is in now
- int nRnd = GetRandInt(vvNew.size());
+ int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucket = -1;
- for (unsigned int n = 0; n < vvNew.size(); n++) {
- int nB = (n + nRnd) % vvNew.size();
- std::set<int>& vNew = vvNew[nB];
- if (vNew.count(nId)) {
+ for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
+ int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
+ int nBpos = info.GetBucketPosition(nKey, true, nB);
+ if (vvNew[nB][nBpos] == nId) {
nUBucket = nB;
break;
}
@@ -300,7 +242,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
// move nId to the tried tables
- MakeTried(info, nId, nUBucket);
+ MakeTried(info, nId);
}
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
@@ -348,12 +290,25 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
}
int nUBucket = pinfo->GetNewBucket(nKey, source);
- std::set<int>& vNew = vvNew[nUBucket];
- if (!vNew.count(nId)) {
- pinfo->nRefCount++;
- if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE)
- ShrinkNew(nUBucket);
- vvNew[nUBucket].insert(nId);
+ int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
+ if (vvNew[nUBucket][nUBucketPos] != nId) {
+ bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
+ if (!fInsert) {
+ CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
+ if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
+ // Overwrite the existing new table entry.
+ fInsert = true;
+ }
+ }
+ if (fInsert) {
+ ClearNew(nUBucket, nUBucketPos);
+ pinfo->nRefCount++;
+ vvNew[nUBucket][nUBucketPos] = nId;
+ } else {
+ if (pinfo->nRefCount == 0) {
+ Delete(nId);
+ }
+ }
}
return fNew;
}
@@ -377,24 +332,23 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime)
info.nAttempts++;
}
-CAddress CAddrMan::Select_(int nUnkBias)
+CAddress CAddrMan::Select_()
{
if (size() == 0)
return CAddress();
- double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
- double nCorNew = sqrt(nNew) * nUnkBias;
- if ((nCorTried + nCorNew) * GetRandInt(1 << 30) / (1 << 30) < nCorTried) {
+ // Use a 50% chance for choosing between tried and new table entries.
+ if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) {
// use a tried node
double fChanceFactor = 1.0;
while (1) {
- int nKBucket = GetRandInt(vvTried.size());
- std::vector<int>& vTried = vvTried[nKBucket];
- if (vTried.size() == 0)
+ int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT);
+ int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
+ if (vvTried[nKBucket][nKBucketPos] == -1)
continue;
- int nPos = GetRandInt(vTried.size());
- assert(mapInfo.count(vTried[nPos]) == 1);
- CAddrInfo& info = mapInfo[vTried[nPos]];
+ int nId = vvTried[nKBucket][nKBucketPos];
+ assert(mapInfo.count(nId) == 1);
+ CAddrInfo& info = mapInfo[nId];
if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
@@ -403,16 +357,13 @@ CAddress CAddrMan::Select_(int nUnkBias)
// use a new node
double fChanceFactor = 1.0;
while (1) {
- int nUBucket = GetRandInt(vvNew.size());
- std::set<int>& vNew = vvNew[nUBucket];
- if (vNew.size() == 0)
+ int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
+ int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
+ if (vvNew[nUBucket][nUBucketPos] == -1)
continue;
- int nPos = GetRandInt(vNew.size());
- std::set<int>::iterator it = vNew.begin();
- while (nPos--)
- it++;
- assert(mapInfo.count(*it) == 1);
- CAddrInfo& info = mapInfo[*it];
+ int nId = vvNew[nUBucket][nUBucketPos];
+ assert(mapInfo.count(nId) == 1);
+ CAddrInfo& info = mapInfo[nId];
if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
@@ -460,22 +411,30 @@ int CAddrMan::Check_()
if (mapNew.size() != nNew)
return -10;
- for (int n = 0; n < vvTried.size(); n++) {
- std::vector<int>& vTried = vvTried[n];
- for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++) {
- if (!setTried.count(*it))
- return -11;
- setTried.erase(*it);
+ for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvTried[n][i] != -1) {
+ if (!setTried.count(vvTried[n][i]))
+ return -11;
+ if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n)
+ return -17;
+ if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
+ return -18;
+ setTried.erase(vvTried[n][i]);
+ }
}
}
- for (int n = 0; n < vvNew.size(); n++) {
- std::set<int>& vNew = vvNew[n];
- for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) {
- if (!mapNew.count(*it))
- return -12;
- if (--mapNew[*it] == 0)
- mapNew.erase(*it);
+ for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvNew[n][i] != -1) {
+ if (!mapNew.count(vvNew[n][i]))
+ return -12;
+ if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
+ return -19;
+ if (--mapNew[vvNew[n][i]] == 0)
+ mapNew.erase(vvNew[n][i]);
+ }
}
}
@@ -483,6 +442,8 @@ int CAddrMan::Check_()
return -13;
if (mapNew.size())
return -15;
+ if (nKey.IsNull())
+ return -16;
return 0;
}
diff --git a/src/addrman.h b/src/addrman.h
index d47217683c..8116d0b763 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -79,17 +79,20 @@ public:
}
//! Calculate in which "tried" bucket this entry belongs
- int GetTriedBucket(const std::vector<unsigned char> &nKey) const;
+ int GetTriedBucket(const uint256 &nKey) const;
//! Calculate in which "new" bucket this entry belongs, given a certain source
- int GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const;
+ int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const;
//! Calculate in which "new" bucket this entry belongs, using its default source
- int GetNewBucket(const std::vector<unsigned char> &nKey) const
+ int GetNewBucket(const uint256 &nKey) const
{
return GetNewBucket(nKey, source);
}
+ //! Calculate in which position of a bucket to store this entry.
+ int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
+
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
@@ -106,15 +109,15 @@ public:
*
* To that end:
* * Addresses are organized into buckets.
- * * Address that have not yet been tried go into 256 "new" buckets.
- * * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random
+ * * Address that have not yet been tried go into 1024 "new" buckets.
+ * * Based on the address range (/16 for IPv4) of source of the information, 64 buckets are selected at random
* * The actual bucket is chosen from one of these, based on the range the address itself is located.
- * * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that
+ * * One single address can occur in up to 8 different buckets, to increase selection chances for addresses that
* are seen frequently. The chance for increasing this multiplicity decreases exponentially.
* * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
* ones) is removed from it first.
- * * Addresses of nodes that are known to be accessible go into 64 "tried" buckets.
- * * Each address range selects at random 4 of these buckets.
+ * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
+ * * Each address range selects at random 8 of these buckets.
* * The actual bucket is chosen from one of these, based on the full address.
* * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
* tried ones) is evicted from it, back to the "new" buckets.
@@ -125,28 +128,22 @@ public:
*/
//! total number of buckets for tried addresses
-#define ADDRMAN_TRIED_BUCKET_COUNT 64
-
-//! maximum allowed number of entries in buckets for tried addresses
-#define ADDRMAN_TRIED_BUCKET_SIZE 64
+#define ADDRMAN_TRIED_BUCKET_COUNT 256
//! total number of buckets for new addresses
-#define ADDRMAN_NEW_BUCKET_COUNT 256
+#define ADDRMAN_NEW_BUCKET_COUNT 1024
-//! maximum allowed number of entries in buckets for new addresses
-#define ADDRMAN_NEW_BUCKET_SIZE 64
+//! maximum allowed number of entries in buckets for new and tried addresses
+#define ADDRMAN_BUCKET_SIZE 64
//! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
-#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4
+#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
//! over how many buckets entries with new addresses originating from a single group are spread
-#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32
+#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
//! in how many buckets for entries with new addresses a single address may occur
-#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4
-
-//! how many entries in a bucket with tried addresses are inspected, when selecting one to replace
-#define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4
+#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
//! how old addresses can maximally be
#define ADDRMAN_HORIZON_DAYS 30
@@ -176,7 +173,7 @@ private:
mutable CCriticalSection cs;
//! secret key to randomize bucket select with
- std::vector<unsigned char> nKey;
+ uint256 nKey;
//! last used nId
int nIdCount;
@@ -194,13 +191,13 @@ private:
int nTried;
//! list of "tried" buckets
- std::vector<std::vector<int> > vvTried;
+ int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
//! number of (unique) "new" entries
int nNew;
//! list of "new" buckets
- std::vector<std::set<int> > vvNew;
+ int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
protected:
@@ -214,17 +211,14 @@ protected:
//! Swap two elements in vRandom.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
- //! Return position in given bucket to replace.
- int SelectTried(int nKBucket);
+ //! Move an entry from the "new" table(s) to the "tried" table
+ void MakeTried(CAddrInfo& info, int nId);
- //! Remove an element from a "new" bucket.
- //! This is the only place where actual deletions occur.
- //! Elements are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
- int ShrinkNew(int nUBucket);
+ //! Delete an entry. It must not be in tried, and have refcount 0.
+ void Delete(int nId);
- //! Move an entry from the "new" table(s) to the "tried" table
- //! @pre vvUnkown[nOrigin].count(nId) != 0
- void MakeTried(CAddrInfo& info, int nId, int nOrigin);
+ //! Clear a position in a "new" table. This is the only place where entries are actually deleted.
+ void ClearNew(int nUBucket, int nUBucketPos);
//! Mark an entry "good", possibly moving it from "new" to "tried".
void Good_(const CService &addr, int64_t nTime);
@@ -237,7 +231,7 @@ protected:
//! Select an address to connect to.
//! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
- CAddress Select_(int nUnkBias);
+ CAddress Select_();
#ifdef DEBUG_ADDRMAN
//! Perform consistency check. Returns an error code or zero.
@@ -253,17 +247,21 @@ protected:
public:
/**
* serialized format:
- * * version byte (currently 0)
- * * nKey
+ * * version byte (currently 1)
+ * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
* * nNew
* * nTried
- * * number of "new" buckets
+ * * number of "new" buckets XOR 2**30
* * all nNew addrinfos in vvNew
* * all nTried addrinfos in vvTried
* * for each bucket:
* * number of elements
* * for each element: index
*
+ * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
+ * as incompatible. This is necessary because it did not check the version number on
+ * deserialization.
+ *
* Notice that vvTried, mapAddr and vVector are never encoded explicitly;
* they are instead reconstructed from the other information.
*
@@ -275,48 +273,53 @@ public:
*
* We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
- *
*/
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersionDummy) const
{
LOCK(cs);
- unsigned char nVersion = 0;
+ unsigned char nVersion = 1;
s << nVersion;
+ s << ((unsigned char)32);
s << nKey;
s << nNew;
s << nTried;
- int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT;
+ int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
std::map<int, int> mapUnkIds;
int nIds = 0;
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- if (nIds == nNew) break; // this means nNew was wrong, oh ow
mapUnkIds[(*it).first] = nIds;
const CAddrInfo &info = (*it).second;
if (info.nRefCount) {
+ assert(nIds != nNew); // this means nNew was wrong, oh ow
s << info;
nIds++;
}
}
nIds = 0;
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- if (nIds == nTried) break; // this means nTried was wrong, oh ow
const CAddrInfo &info = (*it).second;
if (info.fInTried) {
+ assert(nIds != nTried); // this means nTried was wrong, oh ow
s << info;
nIds++;
}
}
- for (std::vector<std::set<int> >::const_iterator it = vvNew.begin(); it != vvNew.end(); it++) {
- const std::set<int> &vNew = (*it);
- int nSize = vNew.size();
+ for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
+ int nSize = 0;
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvNew[bucket][i] != -1)
+ nSize++;
+ }
s << nSize;
- for (std::set<int>::const_iterator it2 = vNew.begin(); it2 != vNew.end(); it2++) {
- int nIndex = mapUnkIds[*it2];
- s << nIndex;
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvNew[bucket][i] != -1) {
+ int nIndex = mapUnkIds[vvNew[bucket][i]];
+ s << nIndex;
+ }
}
}
}
@@ -326,64 +329,97 @@ public:
{
LOCK(cs);
+ Clear();
+
unsigned char nVersion;
s >> nVersion;
+ unsigned char nKeySize;
+ s >> nKeySize;
+ if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
s >> nKey;
s >> nNew;
s >> nTried;
-
int nUBuckets = 0;
s >> nUBuckets;
- nIdCount = 0;
- mapInfo.clear();
- mapAddr.clear();
- vRandom.clear();
- vvTried = std::vector<std::vector<int> >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0));
- vvNew = std::vector<std::set<int> >(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>());
+ if (nVersion != 0) {
+ nUBuckets ^= (1 << 30);
+ }
+
+ // Deserialize entries from the new table.
for (int n = 0; n < nNew; n++) {
CAddrInfo &info = mapInfo[n];
s >> info;
mapAddr[info] = n;
info.nRandomPos = vRandom.size();
vRandom.push_back(n);
- if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
- vvNew[info.GetNewBucket(nKey)].insert(n);
- info.nRefCount++;
+ if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
+ // In case the new table data cannot be used (nVersion unknown, or bucket count wrong),
+ // immediately try to give them a reference based on their primary source address.
+ int nUBucket = info.GetNewBucket(nKey);
+ int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);
+ if (vvNew[nUBucket][nUBucketPos] == -1) {
+ vvNew[nUBucket][nUBucketPos] = n;
+ info.nRefCount++;
+ }
}
}
nIdCount = nNew;
+
+ // Deserialize entries from the tried table.
int nLost = 0;
for (int n = 0; n < nTried; n++) {
CAddrInfo info;
s >> info;
- std::vector<int> &vTried = vvTried[info.GetTriedBucket(nKey)];
- if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) {
+ int nKBucket = info.GetTriedBucket(nKey);
+ int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
+ if (vvTried[nKBucket][nKBucketPos] == -1) {
info.nRandomPos = vRandom.size();
info.fInTried = true;
vRandom.push_back(nIdCount);
mapInfo[nIdCount] = info;
mapAddr[info] = nIdCount;
- vTried.push_back(nIdCount);
+ vvTried[nKBucket][nKBucketPos] = nIdCount;
nIdCount++;
} else {
nLost++;
}
}
nTried -= nLost;
- for (int b = 0; b < nUBuckets; b++) {
- std::set<int> &vNew = vvNew[b];
+
+ // Deserialize positions in the new table (if possible).
+ for (int bucket = 0; bucket < nUBuckets; bucket++) {
int nSize = 0;
s >> nSize;
for (int n = 0; n < nSize; n++) {
int nIndex = 0;
s >> nIndex;
- CAddrInfo &info = mapInfo[nIndex];
- if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
- info.nRefCount++;
- vNew.insert(nIndex);
+ if (nIndex >= 0 && nIndex < nNew) {
+ CAddrInfo &info = mapInfo[nIndex];
+ int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
+ if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
+ info.nRefCount++;
+ vvNew[bucket][nUBucketPos] = nIndex;
+ }
}
}
}
+
+ // Prune new entries with refcount 0 (as a result of collisions).
+ int nLostUnk = 0;
+ for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
+ if (it->second.fInTried == false && it->second.nRefCount == 0) {
+ std::map<int, CAddrInfo>::const_iterator itCopy = it++;
+ Delete(itCopy->first);
+ nLostUnk++;
+ } else {
+ it++;
+ }
+ }
+ if (nLost + nLostUnk > 0) {
+ LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
+ }
+
+ Check();
}
unsigned int GetSerializeSize(int nType, int nVersion) const
@@ -391,14 +427,34 @@ public:
return (CSizeComputer(nType, nVersion) << *this).size();
}
- CAddrMan() : vRandom(0), vvTried(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0)), vvNew(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>())
+ void Clear()
{
- nKey.resize(32);
- GetRandBytes(&nKey[0], 32);
+ std::vector<int>().swap(vRandom);
+ nKey = GetRandHash();
+ for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
+ for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
+ vvNew[bucket][entry] = -1;
+ }
+ }
+ for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
+ for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
+ vvTried[bucket][entry] = -1;
+ }
+ }
+
+ nIdCount = 0;
+ nTried = 0;
+ nNew = 0;
+ }
- nIdCount = 0;
- nTried = 0;
- nNew = 0;
+ CAddrMan()
+ {
+ Clear();
+ }
+
+ ~CAddrMan()
+ {
+ nKey.SetNull();
}
//! Return the number of (unique) addresses in all tables.
@@ -477,13 +533,13 @@ public:
* Choose an address to connect to.
* nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
*/
- CAddress Select(int nUnkBias = 50)
+ CAddress Select()
{
CAddress addrRet;
{
LOCK(cs);
Check();
- addrRet = Select_(nUnkBias);
+ addrRet = Select_();
Check();
}
return addrRet;
diff --git a/src/alert.cpp b/src/alert.cpp
index 323939913b..aa7ac748da 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -5,7 +5,6 @@
#include "alert.h"
-#include "chainparams.h"
#include "clientversion.h"
#include "net.h"
#include "pubkey.h"
@@ -145,9 +144,9 @@ bool CAlert::RelayTo(CNode* pnode) const
return false;
}
-bool CAlert::CheckSignature() const
+bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
{
- CPubKey key(Params().AlertKey());
+ CPubKey key(alertKey);
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
return error("CAlert::CheckSignature(): verify signature failed");
@@ -169,9 +168,9 @@ CAlert CAlert::getAlertByHash(const uint256 &hash)
return retval;
}
-bool CAlert::ProcessAlert(bool fThread)
+bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
{
- if (!CheckSignature())
+ if (!CheckSignature(alertKey))
return false;
if (!IsInEffect())
return false;
diff --git a/src/alert.h b/src/alert.h
index af42171af5..746967c4af 100644
--- a/src/alert.h
+++ b/src/alert.h
@@ -100,8 +100,8 @@ public:
bool AppliesTo(int nVersion, std::string strSubVerIn) const;
bool AppliesToMe() const;
bool RelayTo(CNode* pnode) const;
- bool CheckSignature() const;
- bool ProcessAlert(bool fThread = true); // fThread means run -alertnotify in a free-running thread
+ bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
+ bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread
static void Notify(const std::string& strMessage, bool fThread);
/*
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 3e20d9f8f2..8633d51b2f 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -167,7 +167,7 @@ public:
fRequireRPCPassword = true;
fMiningRequiresPeers = true;
- fDefaultCheckMemPool = false;
+ fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = false;
@@ -222,7 +222,7 @@ public:
fRequireRPCPassword = true;
fMiningRequiresPeers = true;
- fDefaultCheckMemPool = false;
+ fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = true;
@@ -263,7 +263,7 @@ public:
fRequireRPCPassword = false;
fMiningRequiresPeers = false;
- fDefaultCheckMemPool = true;
+ fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
fTestnetToBeDeprecatedFieldRPC = false;
diff --git a/src/chainparams.h b/src/chainparams.h
index aa2ec1e301..d0613beb45 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -57,8 +57,8 @@ public:
bool RequireRPCPassword() const { return fRequireRPCPassword; }
/** Make miner wait to have peers to avoid wasting work */
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
- /** Default value for -checkmempool argument */
- bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; }
+ /** Default value for -checkmempool and -checkblockindex argument */
+ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
/** Allow mining of a min-difficulty block */
bool AllowMinDifficultyBlocks() const { return consensus.fPowAllowMinDifficultyBlocks; }
/** Make standard checks */
@@ -92,7 +92,7 @@ protected:
std::vector<CAddress> vFixedSeeds;
bool fRequireRPCPassword;
bool fMiningRequiresPeers;
- bool fDefaultCheckMemPool;
+ bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
bool fTestnetToBeDeprecatedFieldRPC;
diff --git a/src/init.cpp b/src/init.cpp
index 9445e2fa10..53e521983f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -698,8 +698,9 @@ bool AppInit2(boost::thread_group& threadGroup)
if (GetBoolArg("-benchmark", false))
InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench."));
- // Checkmempool defaults to true in regtest mode
- mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultCheckMemPool()));
+ // Checkmempool and checkblockindex default to true in regtest mode
+ mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultConsistencyChecks()));
+ fCheckBlockIndex = GetBoolArg("-checkblockindex", Params().DefaultConsistencyChecks());
Checkpoints::fEnabled = GetBoolArg("-checkpoints", true);
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
diff --git a/src/key.cpp b/src/key.cpp
index 64c9bc7119..e146e47d0d 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -5,6 +5,7 @@
#include "key.h"
#include "arith_uint256.h"
+#include "crypto/common.h"
#include "crypto/hmac_sha512.h"
#include "eccryptoverify.h"
#include "pubkey.h"
@@ -73,25 +74,14 @@ CPubKey CKey::GetPubKey() const {
return result;
}
-extern "C"
-{
-static int secp256k1_nonce_function_test_case(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int attempt, const void *data)
-{
- const uint32_t *test_case = static_cast<const uint32_t*>(data);
- uint256 nonce;
- secp256k1_nonce_function_rfc6979(nonce.begin(), msg32, key32, attempt, NULL);
- nonce = ArithToUint256(UintToArith256(nonce) + *test_case);
- memcpy(nonce32, nonce.begin(), 32);
- return 1;
-}
-}
-
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const {
if (!fValid)
return false;
vchSig.resize(72);
int nSigLen = 72;
- int ret = secp256k1_ecdsa_sign(hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), test_case == 0 ? secp256k1_nonce_function_rfc6979 : secp256k1_nonce_function_test_case, test_case == 0 ? NULL : &test_case);
+ unsigned char extra_entropy[32] = {0};
+ WriteLE32(extra_entropy, test_case);
+ int ret = secp256k1_ecdsa_sign(hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
assert(ret);
vchSig.resize(nSigLen);
return true;
diff --git a/src/key.h b/src/key.h
index 1f1d142887..104a8f5c72 100644
--- a/src/key.h
+++ b/src/key.h
@@ -124,8 +124,7 @@ public:
/**
* Create a DER-serialized signature.
- * The test_case parameter tweaks the deterministic nonce, and is only for
- * testing. It should be zero for normal use.
+ * The test_case parameter tweaks the deterministic nonce.
*/
bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, uint32_t test_case = 0) const;
diff --git a/src/main.cpp b/src/main.cpp
index 3ceacf32e7..8fb6766301 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -53,6 +53,7 @@ bool fImporting = false;
bool fReindex = false;
bool fTxIndex = false;
bool fIsBareMultisigStd = true;
+bool fCheckBlockIndex = false;
unsigned int nCoinCacheSize = 5000;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
@@ -74,6 +75,7 @@ void EraseOrphansFor(NodeId peer);
* and going backwards.
*/
static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired);
+static void CheckBlockIndex();
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
@@ -85,7 +87,7 @@ namespace {
struct CBlockIndexWorkComparator
{
- bool operator()(CBlockIndex *pa, CBlockIndex *pb) {
+ bool operator()(CBlockIndex *pa, CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->nChainWork > pb->nChainWork) return false;
if (pa->nChainWork < pb->nChainWork) return true;
@@ -107,8 +109,8 @@ namespace {
CBlockIndex *pindexBestInvalid;
/**
- * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
- * as good as our current tip. Entries may be failed, though.
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
+ * as good as our current tip or better. Entries may be failed, though.
*/
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/** Number of nodes with fSyncStarted. */
@@ -2226,6 +2228,7 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
uiInterface.NotifyBlockTip(hashNewTip);
}
} while(pindexMostWork != chainActive.Tip());
+ CheckBlockIndex();
// Write changes periodically to disk, after relay.
if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) {
@@ -2362,7 +2365,9 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
CBlockIndex *pindex = queue.front();
queue.pop_front();
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
- setBlockIndexCandidates.insert(pindex);
+ if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) {
+ setBlockIndexCandidates.insert(pindex);
+ }
std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex);
while (range.first != range.second) {
std::multimap<CBlockIndex*, CBlockIndex*>::iterator it = range.first;
@@ -2725,6 +2730,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
if (pindex && pfrom) {
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
}
+ CheckBlockIndex();
if (!ret)
return error("%s: AcceptBlock FAILED", __func__);
}
@@ -3213,6 +3219,144 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
return nLoaded > 0;
}
+void static CheckBlockIndex()
+{
+ if (!fCheckBlockIndex) {
+ return;
+ }
+
+ LOCK(cs_main);
+
+ // Build forward-pointing map of the entire block tree.
+ std::multimap<CBlockIndex*,CBlockIndex*> forward;
+ for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
+ forward.insert(std::make_pair(it->second->pprev, it->second));
+ }
+
+ assert(forward.size() == mapBlockIndex.size());
+
+ std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(NULL);
+ CBlockIndex *pindex = rangeGenesis.first->second;
+ rangeGenesis.first++;
+ assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL.
+
+ // Iterate over the entire block tree, using depth-first search.
+ // Along the way, remember whether there are blocks on the path from genesis
+ // block being explored which are the first to have certain properties.
+ size_t nNodes = 0;
+ int nHeight = 0;
+ CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid.
+ CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.
+ CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not).
+ CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not).
+ CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not).
+ CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not).
+ while (pindex != NULL) {
+ nNodes++;
+ if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
+ if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex;
+ if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex;
+ if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex;
+ if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex;
+ if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex;
+
+ // Begin: actual consistency checks.
+ if (pindex->pprev == NULL) {
+ // Genesis block checks.
+ assert(pindex->GetBlockHash() == Params().HashGenesisBlock()); // Genesis block's hash must match.
+ assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block.
+ }
+ // HAVE_DATA is equivalent to VALID_TRANSACTIONS and equivalent to nTx > 0 (we stored the number of transactions in the block)
+ assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
+ assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0));
+ // All parents having data is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set.
+ assert((pindexFirstMissing != NULL) == (pindex->nChainTx == 0)); // nChainTx == 0 is used to signal that all parent block's transaction data is available.
+ assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0));
+ assert(pindex->nHeight == nHeight); // nHeight must be consistent.
+ assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
+ assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.
+ assert(pindexFirstNotTreeValid == NULL); // All mapBlockIndex entries must at least be TREE valid
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == NULL); // TREE valid implies all parents are TREE valid
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == NULL); // CHAIN valid implies all parents are CHAIN valid
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == NULL); // SCRIPTS valid implies all parents are SCRIPTS valid
+ if (pindexFirstInvalid == NULL) {
+ // Checks for not-invalid blocks.
+ assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.
+ }
+ if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstMissing == NULL) {
+ if (pindexFirstInvalid == NULL) { // If this block sorts at least as good as the current tip and is valid, it must be in setBlockIndexCandidates.
+ assert(setBlockIndexCandidates.count(pindex));
+ }
+ } else { // If this block sorts worse than the current tip, it cannot be in setBlockIndexCandidates.
+ assert(setBlockIndexCandidates.count(pindex) == 0);
+ }
+ // Check whether this block is in mapBlocksUnlinked.
+ std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeUnlinked = mapBlocksUnlinked.equal_range(pindex->pprev);
+ bool foundInUnlinked = false;
+ while (rangeUnlinked.first != rangeUnlinked.second) {
+ assert(rangeUnlinked.first->first == pindex->pprev);
+ if (rangeUnlinked.first->second == pindex) {
+ foundInUnlinked = true;
+ break;
+ }
+ rangeUnlinked.first++;
+ }
+ if (pindex->pprev && pindex->nStatus & BLOCK_HAVE_DATA && pindexFirstMissing != NULL) {
+ if (pindexFirstInvalid == NULL) { // If this block has block data available, some parent doesn't, and has no invalid parents, it must be in mapBlocksUnlinked.
+ assert(foundInUnlinked);
+ }
+ } else { // If this block does not have block data available, or all parents do, it cannot be in mapBlocksUnlinked.
+ assert(!foundInUnlinked);
+ }
+ // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
+ // End: actual consistency checks.
+
+ // Try descending into the first subnode.
+ std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> range = forward.equal_range(pindex);
+ if (range.first != range.second) {
+ // A subnode was found.
+ pindex = range.first->second;
+ nHeight++;
+ continue;
+ }
+ // This is a leaf node.
+ // Move upwards until we reach a node of which we have not yet visited the last child.
+ while (pindex) {
+ // We are going to either move to a parent or a sibling of pindex.
+ // If pindex was the first with a certain property, unset the corresponding variable.
+ if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL;
+ if (pindex == pindexFirstMissing) pindexFirstMissing = NULL;
+ if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL;
+ if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL;
+ if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL;
+ if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL;
+ // Find our parent.
+ CBlockIndex* pindexPar = pindex->pprev;
+ // Find which child we just visited.
+ std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangePar = forward.equal_range(pindexPar);
+ while (rangePar.first->second != pindex) {
+ assert(rangePar.first != rangePar.second); // Our parent must have at least the node we're coming from as child.
+ rangePar.first++;
+ }
+ // Proceed to the next one.
+ rangePar.first++;
+ if (rangePar.first != rangePar.second) {
+ // Move to the sibling.
+ pindex = rangePar.first->second;
+ break;
+ } else {
+ // Move up further.
+ pindex = pindexPar;
+ nHeight--;
+ continue;
+ }
+ }
+ }
+
+ // Check that we actually traversed the entire map.
+ assert(nNodes == forward.size());
+}
+
//////////////////////////////////////////////////////////////////////////////
//
// CAlert
@@ -3971,6 +4115,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256());
}
+
+ CheckBlockIndex();
}
else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing
@@ -4124,7 +4270,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
uint256 alertHash = alert.GetHash();
if (pfrom->setKnown.count(alertHash) == 0)
{
- if (alert.ProcessAlert())
+ if (alert.ProcessAlert(Params().AlertKey()))
{
// Relay
pfrom->setKnown.insert(alertHash);
diff --git a/src/main.h b/src/main.h
index 3ef042895d..bb6fd6f204 100644
--- a/src/main.h
+++ b/src/main.h
@@ -122,6 +122,7 @@ extern bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
+extern bool fCheckBlockIndex;
extern unsigned int nCoinCacheSize;
extern CFeeRate minRelayTxFee;
diff --git a/src/net.cpp b/src/net.cpp
index 11c2cd07d9..48e6367f20 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1221,8 +1221,7 @@ void ThreadOpenConnections()
int nTries = 0;
while (true)
{
- // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
- CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
+ CAddress addr = addrman.Select();
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
diff --git a/src/pow.cpp b/src/pow.cpp
index 3c5a8d9d96..cf7ac387f2 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -42,9 +42,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
}
// Go back by what we want to be 14 days worth of blocks
- const CBlockIndex* pindexFirst = pindexLast;
- for (int i = 0; pindexFirst && i < params.DifficultyAdjustmentInterval()-1; i++)
- pindexFirst = pindexFirst->pprev;
+ int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
+ assert(nHeightFirst >= 0);
+ const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
assert(pindexFirst);
return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index b1ed7a27b5..8911b41cbf 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -807,7 +807,7 @@
<string>collapse fee-settings</string>
</property>
<property name="text">
- <string>Minimize</string>
+ <string>Hide</string>
</property>
</widget>
</item>
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 985c172eba..cc15338b7e 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -49,7 +49,7 @@ libsecp256k1_la_LIBADD = $(SECP_LIBS)
noinst_PROGRAMS =
if USE_BENCHMARK
-noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_inv
+noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_verify_LDFLAGS = -static
@@ -59,10 +59,10 @@ bench_recover_LDFLAGS = -static
bench_sign_SOURCES = src/bench_sign.c
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_sign_LDFLAGS = -static
-bench_inv_SOURCES = src/bench_inv.c
-bench_inv_LDADD = $(SECP_LIBS)
-bench_inv_LDFLAGS = -static
-bench_inv_CPPFLAGS = $(SECP_INCLUDES)
+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
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 1e49f49416..6095db4220 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -5,25 +5,29 @@ libsecp256k1
Optimized C library for EC operations on curve secp256k1.
-This library is experimental, so use at your own risk.
+This library is a work in progress and is being used to research best practices. Use at your own risk.
Features:
-* Low-level field and group operations on secp256k1.
-* ECDSA signing/verification and key generation.
+* secp256k1 ECDSA signing/verification and key generation.
* Adding/multiplying private/public keys.
* Serialization/parsing of private keys, public keys, signatures.
+* Constant time, constant memory access signing and pubkey generation.
+* Derandomized DSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
Implementation details
----------------------
* General
- * Avoid dynamic memory usage almost everywhere.
+ * No runtime heap allocation.
+ * Extensive testing infrastructure.
+ * Structured to facilitate review and analysis.
+ * Intended to be portable to any system with a C89 compiler and uint64_t support.
+ * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
* Field operations
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
* Using 10 26-bit limbs.
- * Using GMP.
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
* Scalar operations
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
@@ -33,14 +37,15 @@ Implementation details
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
* Use addition between points in Jacobian and affine coordinates where possible.
* Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
+ * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
* Point multiplication for verification (a*P + b*G).
* Use wNAF notation for point multiplicands.
* Use a much larger window for multiples of G, using precomputed multiples.
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
- * Optionally use secp256k1's efficiently-computable endomorphism to split the multiplicands into 4 half-sized ones first.
+ * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
* Point multiplication for signing
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
- * Slice the precomputed table in memory per byte, so memory access to the table becomes uniform.
+ * Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
@@ -52,4 +57,5 @@ libsecp256k1 is built using autotools:
$ ./autogen.sh
$ ./configure
$ make
+ $ ./tests
$ sudo make install # optional
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index f691156ff7..3dc1829516 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -5,7 +5,7 @@ AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
-AH_BOTTOM([#endif //LIBSECP256K1_CONFIG_H])
+AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
AM_INIT_AUTOMAKE([foreign subdir-objects])
LT_INIT
@@ -22,9 +22,9 @@ if test "x$CFLAGS" = "x"; then
CFLAGS="-O3 -g"
fi
-AC_PROG_CC_C99
-if test x"$ac_cv_prog_cc_c99" = x"no"; then
- AC_MSG_ERROR([c99 compiler support required])
+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
@@ -70,7 +70,7 @@ esac
CFLAGS="$CFLAGS -W"
-warn_CFLAGS="-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function"
+warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $warn_CFLAGS"
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
@@ -305,6 +305,8 @@ if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
+AC_C_BIGENDIAN()
+
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index cfdae31eaf..a6e39d13db 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -78,7 +78,7 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** A pointer to a function to deterministically generate a nonce.
- * Returns: 1 if a nonce was succesfully generated. 0 will cause signing to fail.
+ * 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.
@@ -97,7 +97,10 @@ typedef int (*secp256k1_nonce_function_t)(
const void *data
);
-/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. */
+/** 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;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
@@ -106,15 +109,43 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
/** Create an ECDSA signature.
* Returns: 1: signature created
- * 0: the nonce generation function failed
+ * 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: msg32: the 32-byte message hash being signed (cannot be NULL)
- * seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
+ * 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 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).
+ * to contain the actual signature length (<=72). If 0 is returned, this will be
+ * set to zero.
* Requires starting using SECP256K1_START_SIGN.
+ *
+ * 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 unsigned char *msg32,
@@ -127,12 +158,13 @@ int secp256k1_ecdsa_sign(
/** Create a compact ECDSA signature (64 byte + recovery id).
* Returns: 1: signature created
- * 0: the nonce generation function failed
+ * 0: the nonce generation function failed, or the secret key was invalid.
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
- * seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
+ * 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)
* Requires starting using SECP256K1_START_SIGN.
*/
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index 668ec39f71..0559b3e853 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -17,21 +17,40 @@ static double gettimedouble(void) {
return tv.tv_usec * 0.000001 + tv.tv_sec;
}
-void run_benchmark(void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
+void print_number(double x) {
+ double y = x;
+ int c = 0;
+ if (y < 0.0) y = -y;
+ while (y < 100.0) {
+ y *= 10.0;
+ c++;
+ }
+ printf("%.*f", c, x);
+}
+
+void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
+ int i;
double min = HUGE_VAL;
double sum = 0.0;
double max = 0.0;
- for (int i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
+ double begin, total;
if (setup) setup(data);
- double begin = gettimedouble();
+ begin = gettimedouble();
benchmark(data);
- double total = gettimedouble() - begin;
+ total = gettimedouble() - begin;
if (teardown) teardown(data);
if (total < min) min = total;
if (total > max) max = total;
sum += total;
}
- printf("min %.3fus / avg %.3fus / max %.3fus\n", min * 1000000.0 / iter, (sum / count) * 1000000.0 / iter, max * 1000000.0 / iter);
+ printf("%s: min ", name);
+ print_number(min * 1000000.0 / iter);
+ printf("us / avg ");
+ print_number((sum / count) * 1000000.0 / iter);
+ printf("us / avg ");
+ print_number(max * 1000000.0 / iter);
+ printf("us\n");
}
#endif
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
new file mode 100644
index 0000000000..a960549b94
--- /dev/null
+++ b/src/secp256k1/src/bench_internal.c
@@ -0,0 +1,318 @@
+/**********************************************************************
+ * 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 <stdio.h>
+
+#include "include/secp256k1.h"
+
+#include "util.h"
+#include "hash_impl.h"
+#include "num_impl.h"
+#include "field_impl.h"
+#include "group_impl.h"
+#include "scalar_impl.h"
+#include "ecmult_impl.h"
+#include "bench.h"
+
+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];
+ int wnaf[256];
+} bench_inv_t;
+
+void bench_setup(void* arg) {
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ static const unsigned char init_x[32] = {
+ 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
+ 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
+ 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
+ 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
+ };
+
+ static const unsigned char init_y[32] = {
+ 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
+ 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
+ 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
+ 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
+ };
+
+ secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL);
+ secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL);
+ secp256k1_fe_set_b32(&data->fe_x, init_x);
+ secp256k1_fe_set_b32(&data->fe_y, init_y);
+ CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0));
+ CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1));
+ secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);
+ secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);
+ memcpy(data->data, init_x, 32);
+}
+
+void bench_scalar_add(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 2000000; i++) {
+ secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+
+void bench_scalar_negate(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 2000000; i++) {
+ secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
+ }
+}
+
+void bench_scalar_sqr(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
+ }
+}
+
+void bench_scalar_mul(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+
+#ifdef USE_ENDOMORPHISM
+void bench_scalar_split(void* arg) {
+ int i;
+ bench_inv_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_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+#endif
+
+void bench_scalar_inverse(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 2000; i++) {
+ secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
+ secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+
+void bench_scalar_inverse_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 2000; i++) {
+ secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
+ secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+
+void bench_field_normalize(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 2000000; i++) {
+ secp256k1_fe_normalize(&data->fe_x);
+ }
+}
+
+void bench_field_normalize_weak(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 2000000; i++) {
+ secp256k1_fe_normalize_weak(&data->fe_x);
+ }
+}
+
+void bench_field_mul(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
+ }
+}
+
+void bench_field_sqr(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
+ }
+}
+
+void bench_field_inverse(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_fe_inv(&data->fe_x, &data->fe_x);
+ secp256k1_fe_add(&data->fe_x, &data->fe_y);
+ }
+}
+
+void bench_field_inverse_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
+ secp256k1_fe_add(&data->fe_x, &data->fe_y);
+ }
+}
+
+void bench_field_sqrt_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x);
+ secp256k1_fe_add(&data->fe_x, &data->fe_y);
+ }
+}
+
+void bench_group_double_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_gej_double_var(&data->gej_x, &data->gej_x);
+ }
+}
+
+void bench_group_add_var(void* arg) {
+ int i;
+ 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);
+ }
+}
+
+void bench_group_add_affine(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
+ }
+}
+
+void bench_group_add_affine_var(void* arg) {
+ int i;
+ bench_inv_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);
+ }
+}
+
+void bench_ecmult_wnaf(void* arg) {
+ int i;
+ 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_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ }
+}
+
+
+void bench_sha256(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+ secp256k1_sha256_t sha;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, data->data, 32);
+ secp256k1_sha256_finalize(&sha, data->data);
+ }
+}
+
+void bench_hmac_sha256(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+ secp256k1_hmac_sha256_t hmac;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
+ secp256k1_hmac_sha256_write(&hmac, data->data, 32);
+ secp256k1_hmac_sha256_finalize(&hmac, data->data);
+ }
+}
+
+void bench_rfc6979_hmac_sha256(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)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_generate(&rng, data->data, 32);
+ }
+}
+
+
+int have_flag(int argc, char** argv, char *flag) {
+ char** argm = argv + argc;
+ argv++;
+ if (argv == argm) {
+ return 1;
+ }
+ while (argv != NULL && argv != argm) {
+ if (strcmp(*argv, flag) == 0) return 1;
+ argv++;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ bench_inv_t data;
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000);
+#ifdef USE_ENDOMORPHISM
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000);
+#endif
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);
+ if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);
+
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000);
+
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
+
+ if (have_flag(argc, argv, "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);
+ return 0;
+}
diff --git a/src/secp256k1/src/bench_inv.c b/src/secp256k1/src/bench_inv.c
deleted file mode 100644
index 3bdedea30e..0000000000
--- a/src/secp256k1/src/bench_inv.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/**********************************************************************
- * Copyright (c) 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
-#include <stdio.h>
-
-#include "include/secp256k1.h"
-
-#include "util.h"
-#include "num_impl.h"
-#include "field_impl.h"
-#include "group_impl.h"
-#include "scalar_impl.h"
-#include "bench.h"
-
-typedef struct {
- secp256k1_scalar_t base, x;
-} bench_inv_t;
-
-void bench_inv_setup(void* arg) {
- bench_inv_t *data = (bench_inv_t*)arg;
-
- static const unsigned char init[32] = {
- 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
- 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
- 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
- 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
- };
-
- secp256k1_scalar_set_b32(&data->base, init, NULL);
- secp256k1_scalar_set_b32(&data->x, init, NULL);
-}
-
-void bench_inv(void* arg) {
- bench_inv_t *data = (bench_inv_t*)arg;
-
- for (int i=0; i<20000; i++) {
- secp256k1_scalar_inverse(&data->x, &data->x);
- secp256k1_scalar_add(&data->x, &data->x, &data->base);
- }
-}
-
-int main(void) {
- secp256k1_ge_start();
-
- bench_inv_t data;
- run_benchmark(bench_inv, bench_inv_setup, NULL, &data, 10, 20000);
-
- secp256k1_ge_stop();
- return 0;
-}
diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c
index b1e0f33efa..6991cc9d6c 100644
--- a/src/secp256k1/src/bench_recover.c
+++ b/src/secp256k1/src/bench_recover.c
@@ -14,13 +14,15 @@ typedef struct {
} bench_recover_t;
void bench_recover(void* arg) {
+ int i;
bench_recover_t *data = (bench_recover_t*)arg;
-
unsigned char pubkey[33];
- for (int i=0; i<20000; i++) {
+
+ for (i = 0; i < 20000; i++) {
+ int j;
int pubkeylen = 33;
CHECK(secp256k1_ecdsa_recover_compact(data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2));
- for (int j = 0; j < 32; j++) {
+ 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). */
@@ -29,17 +31,18 @@ void bench_recover(void* arg) {
}
void bench_recover_setup(void* arg) {
+ int i;
bench_recover_t *data = (bench_recover_t*)arg;
- for (int i = 0; i < 32; i++) data->msg[i] = 1 + i;
- for (int 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) {
+ bench_recover_t data;
secp256k1_start(SECP256K1_START_VERIFY);
- bench_recover_t data;
- run_benchmark(bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
+ run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
secp256k1_stop();
return 0;
diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c
index 2276f00b9a..c5b6829a84 100644
--- a/src/secp256k1/src/bench_sign.c
+++ b/src/secp256k1/src/bench_sign.c
@@ -14,20 +14,23 @@ typedef struct {
} bench_sign_t;
static void bench_sign_setup(void* arg) {
+ int i;
bench_sign_t *data = (bench_sign_t*)arg;
- for (int i = 0; i < 32; i++) data->msg[i] = i + 1;
- for (int i = 0; i < 32; i++) data->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];
- for (int i=0; i<20000; i++) {
+ for (i = 0; i < 20000; i++) {
+ int j;
int recid = 0;
CHECK(secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, NULL, NULL, &recid));
- for (int j = 0; j < 32; j++) {
+ 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. */
}
@@ -35,10 +38,10 @@ static void bench_sign(void* arg) {
}
int main(void) {
+ bench_sign_t data;
secp256k1_start(SECP256K1_START_SIGN);
- bench_sign_t data;
- run_benchmark(bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
+ run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
secp256k1_stop();
return 0;
diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c
index a58ca84347..c279305a0d 100644
--- a/src/secp256k1/src/bench_verify.c
+++ b/src/secp256k1/src/bench_verify.c
@@ -21,9 +21,10 @@ typedef struct {
} benchmark_verify_t;
static void benchmark_verify(void* arg) {
+ int i;
benchmark_verify_t* data = (benchmark_verify_t*)arg;
- for (int i=0; i<20000; i++) {
+ for (i = 0; i < 20000; i++) {
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -35,18 +36,19 @@ static void benchmark_verify(void* arg) {
}
int main(void) {
- secp256k1_start(SECP256K1_START_VERIFY | SECP256K1_START_SIGN);
-
+ int i;
benchmark_verify_t data;
- for (int i = 0; i < 32; i++) data.msg[i] = 1 + i;
- for (int i = 0; i < 32; i++) data.key[i] = 33 + i;
+ secp256k1_start(SECP256K1_START_VERIFY | SECP256K1_START_SIGN);
+
+ 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.msg, data.sig, &data.siglen, data.key, NULL, NULL);
data.pubkeylen = 33;
CHECK(secp256k1_ec_pubkey_create(data.pubkey, &data.pubkeylen, data.key, 1));
- run_benchmark(benchmark_verify, NULL, NULL, &data, 10, 20000);
+ run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
secp256k1_stop();
return 0;
diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h
index 5fc5230c36..c195e7afcb 100644
--- a/src/secp256k1/src/ecdsa.h
+++ b/src/secp256k1/src/ecdsa.h
@@ -10,9 +10,6 @@
#include "scalar.h"
#include "group.h"
-static void secp256k1_ecsda_start(void);
-static void secp256k1_ecdsa_stop(void);
-
typedef struct {
secp256k1_scalar_t r, s;
} secp256k1_ecdsa_sig_t;
@@ -22,6 +19,5 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
-static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s);
#endif
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 674650c1e9..1a77649390 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -15,71 +15,69 @@
#include "ecmult_gen.h"
#include "ecdsa.h"
-typedef struct {
- secp256k1_fe_t order_as_fe;
- secp256k1_fe_t p_minus_order;
-} secp256k1_ecdsa_consts_t;
-
-static const secp256k1_ecdsa_consts_t *secp256k1_ecdsa_consts = NULL;
-
-static void secp256k1_ecdsa_start(void) {
- if (secp256k1_ecdsa_consts != NULL)
- return;
-
- /* Allocate. */
- secp256k1_ecdsa_consts_t *ret = (secp256k1_ecdsa_consts_t*)checked_malloc(sizeof(secp256k1_ecdsa_consts_t));
-
- static const unsigned char order[] = {
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
- 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
- 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
- };
-
- secp256k1_fe_set_b32(&ret->order_as_fe, order);
- secp256k1_fe_negate(&ret->p_minus_order, &ret->order_as_fe, 1);
- secp256k1_fe_normalize_var(&ret->p_minus_order);
-
- /* Set the global pointer. */
- secp256k1_ecdsa_consts = ret;
-}
-
-static void secp256k1_ecdsa_stop(void) {
- if (secp256k1_ecdsa_consts == NULL)
- return;
-
- secp256k1_ecdsa_consts_t *c = (secp256k1_ecdsa_consts_t*)secp256k1_ecdsa_consts;
- secp256k1_ecdsa_consts = NULL;
- free(c);
-}
+/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1
+ * sage: for t in xrange(1023, -1, -1):
+ * .. p = 2**256 - 2**32 - t
+ * .. if p.is_prime():
+ * .. print '%x'%p
+ * .. break
+ * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'
+ * sage: a = 0
+ * sage: b = 7
+ * sage: F = FiniteField (p)
+ * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
+ * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
+ */
+static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
+ 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
+ 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL
+);
+
+/** Difference between field and order, values 'p' and 'n' values defined in
+ * "Standards for Efficient Cryptography" (SEC2) 2.7.1.
+ * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
+ * sage: a = 0
+ * sage: b = 7
+ * sage: F = FiniteField (p)
+ * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
+ * '14551231950b75fc4402da1722fc9baee'
+ */
+static const secp256k1_fe_t 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;
- int lenr = sig[3];
+ lenr = sig[3];
if (5+lenr >= size) return 0;
- int lens = sig[lenr+5];
+ lens = sig[lenr+5];
if (sig[1] != lenr+lens+4) return 0;
if (lenr+lens+6 > size) return 0;
if (sig[2] != 0x02) return 0;
if (lenr == 0) return 0;
if (sig[lenr+4] != 0x02) return 0;
if (lens == 0) return 0;
- const unsigned char *sp = sig + 6 + lenr;
+ sp = sig + 6 + lenr;
while (lens > 0 && sp[0] == 0) {
lens--;
sp++;
}
if (lens > 32) return 0;
- const unsigned char *rp = sig + 4;
+ rp = sig + 4;
while (lenr > 0 && rp[0] == 0) {
lenr--;
rp++;
}
if (lenr > 32) return 0;
- unsigned char ra[32] = {0}, sa[32] = {0};
memcpy(ra + 32 - lenr, rp, lenr);
memcpy(sa + 32 - lens, sp, lens);
- int overflow = 0;
+ overflow = 0;
secp256k1_scalar_set_b32(&r->r, ra, &overflow);
if (overflow) return 0;
secp256k1_scalar_set_b32(&r->s, sa, &overflow);
@@ -89,10 +87,10 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned ch
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
unsigned char r[33] = {0}, s[33] = {0};
- secp256k1_scalar_get_b32(&r[1], &a->r);
- secp256k1_scalar_get_b32(&s[1], &a->s);
unsigned char *rp = r, *sp = s;
int lenR = 33, lenS = 33;
+ secp256k1_scalar_get_b32(&r[1], &a->r);
+ secp256k1_scalar_get_b32(&s[1], &a->s);
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)
@@ -110,93 +108,100 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
}
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
+ unsigned char c[32];
+ secp256k1_scalar_t sn, u1, u2;
+ secp256k1_fe_t xr;
+ secp256k1_gej_t pubkeyj;
+ secp256k1_gej_t pr;
+
if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s))
return 0;
- secp256k1_scalar_t sn, u1, u2;
secp256k1_scalar_inverse_var(&sn, &sig->s);
secp256k1_scalar_mul(&u1, &sn, message);
secp256k1_scalar_mul(&u2, &sn, &sig->r);
- secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey);
- secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
+ secp256k1_gej_set_ge(&pubkeyj, pubkey);
+ secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
if (secp256k1_gej_is_infinity(&pr)) {
return 0;
}
- unsigned char c[32];
secp256k1_scalar_get_b32(c, &sig->r);
- secp256k1_fe_t xr;
secp256k1_fe_set_b32(&xr, c);
- // We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
- // in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
- // compute the remainder modulo n, and compare it to xr. However:
- //
- // xr == X(pr) mod n
- // <=> exists h. (xr + h * n < p && xr + h * n == X(pr))
- // [Since 2 * n > p, h can only be 0 or 1]
- // <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr))
- // [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p]
- // <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p)
- // [Multiplying both sides of the equations by pr.z^2 mod p]
- // <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x)
- //
- // Thus, we can avoid the inversion, but we have to check both cases separately.
- // secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
+ /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
+ * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
+ * compute the remainder modulo n, and compare it to xr. However:
+ *
+ * xr == X(pr) mod n
+ * <=> exists h. (xr + h * n < p && xr + h * n == X(pr))
+ * [Since 2 * n > p, h can only be 0 or 1]
+ * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr))
+ * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p]
+ * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p)
+ * [Multiplying both sides of the equations by pr.z^2 mod p]
+ * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x)
+ *
+ * Thus, we can avoid the inversion, but we have to check both cases separately.
+ * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
+ */
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
- // xr.x == xr * xr.z^2 mod p, so the signature is valid.
+ /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */
return 1;
}
- if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_consts->p_minus_order) >= 0) {
- // xr + p >= n, so we can skip testing the second case.
+ if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
+ /* xr + p >= n, so we can skip testing the second case. */
return 0;
}
- secp256k1_fe_add(&xr, &secp256k1_ecdsa_consts->order_as_fe);
+ secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
- // (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid.
+ /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */
return 1;
}
return 0;
}
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
+ 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;
- unsigned char brx[32];
secp256k1_scalar_get_b32(brx, &sig->r);
- secp256k1_fe_t fx;
VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) {
- if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_consts->p_minus_order) >= 0)
+ if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0)
return 0;
- secp256k1_fe_add(&fx, &secp256k1_ecdsa_consts->order_as_fe);
+ secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
}
- secp256k1_ge_t x;
if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1))
return 0;
- secp256k1_gej_t xj;
secp256k1_gej_set_ge(&xj, &x);
- secp256k1_scalar_t rn, u1, u2;
secp256k1_scalar_inverse_var(&rn, &sig->r);
secp256k1_scalar_mul(&u1, &rn, message);
secp256k1_scalar_negate(&u1, &u1);
secp256k1_scalar_mul(&u2, &rn, &sig->s);
- secp256k1_gej_t qj;
secp256k1_ecmult(&qj, &xj, &u2, &u1);
secp256k1_ge_set_gej_var(pubkey, &qj);
return !secp256k1_gej_is_infinity(&qj);
}
static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) {
+ unsigned char b[32];
secp256k1_gej_t rp;
- secp256k1_ecmult_gen(&rp, nonce);
secp256k1_ge_t r;
+ secp256k1_scalar_t n;
+ int overflow = 0;
+
+ secp256k1_ecmult_gen(&rp, nonce);
secp256k1_ge_set_gej(&r, &rp);
- unsigned char b[32];
secp256k1_fe_normalize(&r.x);
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
- int overflow = 0;
secp256k1_scalar_set_b32(&sig->r, b, &overflow);
if (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. */
@@ -206,7 +211,6 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_
}
if (recid)
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
- secp256k1_scalar_t n;
secp256k1_scalar_mul(&n, &sig->r, seckey);
secp256k1_scalar_add(&n, &n, message);
secp256k1_scalar_inverse(&sig->s, nonce);
@@ -224,9 +228,4 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_
return 1;
}
-static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s) {
- sig->r = *r;
- sig->s = *s;
-}
-
#endif
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index b3fa7d9bd2..3e06d05b47 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -51,13 +51,16 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char
}
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 */
- int lenb = 0;
if (end < privkey+1 || !(*privkey & 0x80))
return 0;
lenb = *privkey & ~0x80; privkey++;
@@ -66,7 +69,6 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned
if (end < privkey+lenb)
return 0;
/* sequence length */
- int len = 0;
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
privkey += lenb;
if (end < privkey+len)
@@ -78,8 +80,6 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned
/* sequence element 1: octet string, up to 32 bytes */
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1])
return 0;
- int overflow = 0;
- unsigned char c[32] = {0};
memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]);
secp256k1_scalar_set_b32(key, c, &overflow);
memset(c, 0, 32);
@@ -88,8 +88,9 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned
static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) {
secp256k1_gej_t rp;
- secp256k1_ecmult_gen(&rp, key);
secp256k1_ge_t r;
+ int pubkeylen = 0;
+ secp256k1_ecmult_gen(&rp, key);
secp256k1_ge_set_gej(&r, &rp);
if (compressed) {
static const unsigned char begin[] = {
@@ -110,7 +111,6 @@ static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privke
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
secp256k1_scalar_get_b32(ptr, key); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
- int pubkeylen = 0;
if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) {
return 0;
}
@@ -137,7 +137,6 @@ static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privke
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
secp256k1_scalar_get_b32(ptr, key); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
- int pubkeylen = 0;
if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) {
return 0;
}
@@ -156,8 +155,8 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
secp256k1_gej_t pt;
- secp256k1_gej_set_ge(&pt, key);
secp256k1_scalar_t one;
+ secp256k1_gej_set_ge(&pt, key);
secp256k1_scalar_set_int(&one, 1);
secp256k1_ecmult(&pt, &pt, &one, tweak);
@@ -176,12 +175,12 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp
}
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
+ secp256k1_scalar_t zero;
+ secp256k1_gej_t pt;
if (secp256k1_scalar_is_zero(tweak))
return 0;
- secp256k1_scalar_t zero;
secp256k1_scalar_set_int(&zero, 0);
- secp256k1_gej_t pt;
secp256k1_gej_set_ge(&pt, key);
secp256k1_ecmult(&pt, &pt, tweak, &zero);
secp256k1_ge_set_gej(key, &pt);
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 48436316e1..849452c7a1 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -24,49 +24,53 @@ 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_fe_t prec[64][16][2]; /* prec[j][i] = (16^j * i * G + U_i).{x,y} */
+ secp256k1_ge_storage_t prec[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
} secp256k1_ecmult_gen_consts_t;
static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL;
static void secp256k1_ecmult_gen_start(void) {
+ secp256k1_ge_t prec[1024];
+ secp256k1_gej_t gj;
+ secp256k1_gej_t nums_gej;
+ secp256k1_ecmult_gen_consts_t *ret;
+ int i, j;
if (secp256k1_ecmult_gen_consts != NULL)
return;
/* Allocate the precomputation table. */
- secp256k1_ecmult_gen_consts_t *ret = (secp256k1_ecmult_gen_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_gen_consts_t));
+ ret = (secp256k1_ecmult_gen_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_gen_consts_t));
/* get the generator */
- const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
- secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g);
+ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
- secp256k1_gej_t nums_gej;
{
- static const unsigned char nums_b32[32] = "The scalar for this x is unknown";
+ static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
secp256k1_fe_t nums_x;
- VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
secp256k1_ge_t nums_ge;
+ VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0));
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
/* Add G to make the bits in x uniformly distributed. */
- secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, g);
+ secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g);
}
/* compute prec. */
- secp256k1_ge_t prec[1024];
{
secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */
- secp256k1_gej_t gbase; gbase = gj; /* 16^j * G */
- secp256k1_gej_t numsbase; numsbase = nums_gej; /* 2^j * nums. */
- for (int j=0; j<64; j++) {
+ secp256k1_gej_t gbase;
+ secp256k1_gej_t numsbase;
+ gbase = gj; /* 16^j * G */
+ numsbase = nums_gej; /* 2^j * nums. */
+ for (j = 0; j < 64; j++) {
/* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */
precj[j*16] = numsbase;
- for (int i=1; i<16; i++) {
+ for (i = 1; i < 16; i++) {
secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase);
}
/* Multiply gbase by 16. */
- for (int i=0; i<4; i++) {
+ for (i = 0; i < 4; i++) {
secp256k1_gej_double_var(&gbase, &gbase);
}
/* Multiply numbase by 2. */
@@ -79,11 +83,9 @@ static void secp256k1_ecmult_gen_start(void) {
}
secp256k1_ge_set_all_gej_var(1024, prec, precj);
}
- for (int j=0; j<64; j++) {
- for (int i=0; i<16; i++) {
- VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[j*16 + i]));
- ret->prec[j][i][0] = prec[j*16 + i].x;
- ret->prec[j][i][1] = prec[j*16 + i].y;
+ for (j = 0; j < 64; j++) {
+ for (i = 0; i < 16; i++) {
+ secp256k1_ge_to_storage(&ret->prec[j][i], &prec[j*16 + i]);
}
}
@@ -92,26 +94,29 @@ static void secp256k1_ecmult_gen_start(void) {
}
static void secp256k1_ecmult_gen_stop(void) {
+ secp256k1_ecmult_gen_consts_t *c;
if (secp256k1_ecmult_gen_consts == NULL)
return;
- secp256k1_ecmult_gen_consts_t *c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts;
+ c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts;
secp256k1_ecmult_gen_consts = NULL;
free(c);
}
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *gn) {
const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts;
- secp256k1_gej_set_infinity(r);
secp256k1_ge_t add;
- add.infinity = 0;
+ secp256k1_ge_storage_t adds;
int bits;
- for (int j=0; j<64; j++) {
+ int i, j;
+ secp256k1_gej_set_infinity(r);
+ add.infinity = 0;
+ for (j = 0; j < 64; j++) {
bits = secp256k1_scalar_get_bits(gn, j * 4, 4);
- for (int i=0; i<16; i++) {
- secp256k1_fe_cmov(&add.x, &c->prec[j][i][0], i == bits);
- secp256k1_fe_cmov(&add.y, &c->prec[j][i][1], i == bits);
+ for (i = 0; i < 16; i++) {
+ secp256k1_ge_storage_cmov(&adds, &c->prec[j][i], i == bits);
}
+ secp256k1_ge_from_storage(&add, &adds);
secp256k1_gej_add_ge(r, r, &add);
}
bits = 0;
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 345cfae733..ece0b0a459 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -37,22 +37,31 @@
* G is constant, so it only needs to be done once in advance.
*/
static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
+ secp256k1_gej_t d;
+ int i;
pre[0] = *a;
- secp256k1_gej_t d; secp256k1_gej_double_var(&d, &pre[0]);
- for (int i=1; i<(1 << (w-2)); i++)
+ secp256k1_gej_double_var(&d, &pre[0]);
+ for (i = 1; i < (1 << (w-2)); i++)
secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]);
}
-static void secp256k1_ecmult_table_precomp_ge_var(secp256k1_ge_t *pre, const secp256k1_gej_t *a, int w) {
+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;
+ int i;
const int table_size = 1 << (w-2);
secp256k1_gej_t *prej = checked_malloc(sizeof(secp256k1_gej_t) * table_size);
+ secp256k1_ge_t *prea = checked_malloc(sizeof(secp256k1_ge_t) * table_size);
prej[0] = *a;
- secp256k1_gej_t d; secp256k1_gej_double_var(&d, a);
- for (int i=1; i<table_size; i++) {
+ 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, pre, prej);
+ secp256k1_ge_set_all_gej_var(table_size, prea, prej);
+ for (i = 0; i < table_size; i++) {
+ secp256k1_ge_to_storage(&pre[i], &prea[i]);
+ }
free(prej);
+ free(prea);
}
/** The number of entries a table with precomputed multiples needs to have. */
@@ -60,51 +69,63 @@ static void secp256k1_ecmult_table_precomp_ge_var(secp256k1_ge_t *pre, const sec
/** The following two macro retrieves a particular odd multiple from a table
* of precomputed multiples. */
-#define ECMULT_TABLE_GET(r,pre,n,w,neg) do { \
+#define ECMULT_TABLE_GET_GEJ(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 \
- (neg)((r), &(pre)[(-(n)-1)/2]); \
+ secp256k1_gej_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)); \
+ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
+ if ((n) > 0) \
+ secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
+ else {\
+ secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
+ secp256k1_ge_neg((r), (r)); \
+ } \
} while(0)
-
-#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg)
-#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg)
typedef struct {
/* For accelerating the computation of a*P + b*G: */
- secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */
+ secp256k1_ge_storage_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */
#ifdef USE_ENDOMORPHISM
- secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */
+ secp256k1_ge_storage_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */
#endif
} secp256k1_ecmult_consts_t;
static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
static void secp256k1_ecmult_start(void) {
+ secp256k1_gej_t gj;
+ secp256k1_ecmult_consts_t *ret;
if (secp256k1_ecmult_consts != NULL)
return;
/* Allocate the precomputation table. */
- secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_consts_t));
+ ret = (secp256k1_ecmult_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_consts_t));
/* get the generator */
- const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
- secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g);
+ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
-#ifdef USE_ENDOMORPHISM
- /* calculate 2^128*generator */
- secp256k1_gej_t g_128j = gj;
- for (int i=0; i<128; i++)
- secp256k1_gej_double_var(&g_128j, &g_128j);
-#endif
/* precompute the tables with odd multiples */
- secp256k1_ecmult_table_precomp_ge_var(ret->pre_g, &gj, WINDOW_G);
+ secp256k1_ecmult_table_precomp_ge_storage_var(ret->pre_g, &gj, WINDOW_G);
+
#ifdef USE_ENDOMORPHISM
- secp256k1_ecmult_table_precomp_ge_var(ret->pre_g_128, &g_128j, WINDOW_G);
+ {
+ secp256k1_gej_t g_128j;
+ int i;
+ /* calculate 2^128*generator */
+ g_128j = gj;
+ for (i = 0; i < 128; i++)
+ secp256k1_gej_double_var(&g_128j, &g_128j);
+ secp256k1_ecmult_table_precomp_ge_storage_var(ret->pre_g_128, &g_128j, WINDOW_G);
+ }
#endif
/* Set the global pointer to the precomputation table. */
@@ -112,10 +133,11 @@ static void secp256k1_ecmult_start(void) {
}
static void secp256k1_ecmult_stop(void) {
+ secp256k1_ecmult_consts_t *c;
if (secp256k1_ecmult_consts == NULL)
return;
- secp256k1_ecmult_consts_t *c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts;
+ c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts;
secp256k1_ecmult_consts = NULL;
free(c);
}
@@ -129,16 +151,18 @@ static void secp256k1_ecmult_stop(void) {
*/
static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) {
secp256k1_scalar_t s = *a;
-
+ int set_bits = 0;
+ int bit = 0;
int sign = 1;
+
if (secp256k1_scalar_get_bits(&s, 255, 1)) {
secp256k1_scalar_negate(&s, &s);
sign = -1;
}
- int set_bits = 0;
- int bit = 0;
while (bit < 256) {
+ int now;
+ int word;
if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) {
bit++;
continue;
@@ -146,11 +170,11 @@ static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w)
while (set_bits < bit) {
wnaf[set_bits++] = 0;
}
- int now = w;
+ now = w;
if (bit + now > 256) {
now = 256 - bit;
}
- int word = secp256k1_scalar_get_bits_var(&s, bit, now);
+ 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));
@@ -163,58 +187,74 @@ static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w)
}
static void secp256k1_ecmult(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;
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
-
#ifdef USE_ENDOMORPHISM
+ secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_scalar_t na_1, na_lam;
+ /* Splitted G factors. */
+ secp256k1_scalar_t ng_1, ng_128;
+ int wnaf_na_1[130];
+ int wnaf_na_lam[130];
+ int bits_na_1;
+ int bits_na_lam;
+ int wnaf_ng_1[129];
+ int bits_ng_1;
+ int wnaf_ng_128[129];
+ int bits_ng_128;
+#else
+ int wnaf_na[256];
+ int bits_na;
+ int wnaf_ng[257];
+ int bits_ng;
+#endif
+ int i;
+ int bits;
+
+#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);
/* build wnaf representation for na_1 and na_lam. */
- int wnaf_na_1[130]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
- int wnaf_na_lam[130]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
+ 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);
VERIFY_CHECK(bits_na_1 <= 130);
VERIFY_CHECK(bits_na_lam <= 130);
- int bits = bits_na_1;
+ bits = bits_na_1;
if (bits_na_lam > bits) bits = bits_na_lam;
#else
/* build wnaf representation for na. */
- int wnaf_na[256]; int bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
- int bits = bits_na;
+ bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
+ bits = bits_na;
#endif
/* calculate odd multiples of a */
- secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A);
#ifdef USE_ENDOMORPHISM
- secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
- for (int i=0; i<ECMULT_TABLE_SIZE(WINDOW_A); i++)
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++)
secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]);
- /* Splitted G factors. */
- secp256k1_scalar_t ng_1, ng_128;
-
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
/* Build wnaf representation for ng_1 and ng_128 */
- int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
- int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
+ 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);
if (bits_ng_1 > bits) bits = bits_ng_1;
if (bits_ng_128 > bits) bits = bits_ng_128;
#else
- int wnaf_ng[257]; int bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G);
+ bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G);
if (bits_ng > bits) bits = bits_ng;
#endif
secp256k1_gej_set_infinity(r);
- secp256k1_gej_t tmpj;
- secp256k1_ge_t tmpa;
- for (int i=bits-1; i>=0; i--) {
- secp256k1_gej_double_var(r, r);
+ for (i = bits-1; i >= 0; i--) {
int n;
+ secp256k1_gej_double_var(r, r);
#ifdef USE_ENDOMORPHISM
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
@@ -225,11 +265,11 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
secp256k1_gej_add_var(r, r, &tmpj);
}
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
+ ECMULT_TABLE_GET_GE_STORAGE(&tmpa, c->pre_g, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa);
}
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
+ ECMULT_TABLE_GET_GE_STORAGE(&tmpa, c->pre_g_128, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa);
}
#else
@@ -238,7 +278,7 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
secp256k1_gej_add_var(r, r, &tmpj);
}
if (i < bits_ng && (n = wnaf_ng[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
+ ECMULT_TABLE_GET_GE_STORAGE(&tmpa, c->pre_g, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa);
}
#endif
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 14e2b813c1..9e6d7d3c04 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -30,21 +30,6 @@
#error "Please select field implementation"
#endif
-typedef struct {
-#ifndef USE_NUM_NONE
- secp256k1_num_t p;
-#endif
- secp256k1_fe_t order;
-} secp256k1_fe_consts_t;
-
-static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
-
-/** Initialize field element precomputation data. */
-static void secp256k1_fe_start(void);
-
-/** Unload field element precomputation data. */
-static void secp256k1_fe_stop(void);
-
/** Normalize a field element. */
static void secp256k1_fe_normalize(secp256k1_fe_t *r);
@@ -117,15 +102,15 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *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[len], const secp256k1_fe_t a[len]);
+static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a);
-/** Convert a field element to a hexadecimal string. */
-static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
+/** Convert a field element to the storage type. */
+static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*);
-/** Convert a hexadecimal string to a field element. */
-static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
+/** Convert a field element back from the storage type. */
+static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*);
/** 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_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag);
#endif
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 66fb3f2563..44bce6525d 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -18,4 +18,30 @@ typedef struct {
#endif
} secp256k1_fe_t;
+/* 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) \
+}
+
+#ifdef VERIFY
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
+#else
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
+#endif
+
+typedef struct {
+ uint32_t n[8];
+} secp256k1_fe_storage_t;
+
+#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
+
#endif
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 9ef60a807a..0afbb18a4a 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -13,9 +13,6 @@
#include "num.h"
#include "field.h"
-static void secp256k1_fe_inner_start(void) {}
-static void secp256k1_fe_inner_stop(void) {}
-
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
const uint32_t *d = a->n;
@@ -54,8 +51,8 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
/* Reduce t9 at the start so there will be at most a single carry from the first pass */
- uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;
uint32_t m;
+ uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x3D1UL; t1 += (x << 6);
@@ -140,8 +137,8 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
/* Reduce t9 at the start so there will be at most a single carry from the first pass */
- uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;
uint32_t m;
+ uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x3D1UL; t1 += (x << 6);
@@ -195,12 +192,12 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
- /* Reduce t9 at the start so there will be at most a single carry from the first pass */
- uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;
-
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
uint32_t z0, z1;
+ /* Reduce t9 at the start so there will be at most a single carry from the first pass */
+ uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;
+
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x3D1UL; t1 += (x << 6);
t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL;
@@ -221,23 +218,36 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
}
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
- uint32_t t0 = r->n[0], t9 = r->n[9];
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t z0, z1;
+ uint32_t x;
+
+ t0 = r->n[0];
+ t9 = r->n[9];
/* Reduce t9 at the start so there will be at most a single carry from the first pass */
- uint32_t x = t9 >> 22;
+ x = t9 >> 22;
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x3D1UL;
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
- uint32_t z0 = t0 & 0x3FFFFFFUL, z1 = z0 ^ 0x3D0UL;
+ z0 = t0 & 0x3FFFFFFUL;
+ z1 = z0 ^ 0x3D0UL;
/* Fast return path should catch the majority of cases */
if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL))
return 0;
- uint32_t t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
- t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8];
+ t1 = r->n[1];
+ t2 = r->n[2];
+ t3 = r->n[3];
+ t4 = r->n[4];
+ t5 = r->n[5];
+ t6 = r->n[6];
+ t7 = r->n[7];
+ t8 = r->n[8];
+
t9 &= 0x03FFFFFUL;
t1 += (x << 6);
@@ -269,11 +279,11 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
}
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+ const uint32_t *t = a->n;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- const uint32_t *t = a->n;
return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;
}
@@ -286,23 +296,25 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
}
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
+ int i;
#ifdef VERIFY
a->magnitude = 0;
a->normalized = 1;
#endif
- for (int i=0; i<10; i++) {
+ for (i=0; i<10; i++) {
a->n[i] = 0;
}
}
static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+ int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
#endif
- for (int i = 9; i >= 0; i--) {
+ for (i = 9; i >= 0; i--) {
if (a->n[i] > b->n[i]) return 1;
if (a->n[i] < b->n[i]) return -1;
}
@@ -310,10 +322,12 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b
}
static int secp256k1_fe_set_b32(secp256k1_fe_t *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;
- for (int i=0; i<32; i++) {
- for (int j=0; j<4; j++) {
+ for (i=0; i<32; i++) {
+ int j;
+ for (j=0; j<4; j++) {
int limb = (8*i+2*j)/26;
int shift = (8*i+2*j)%26;
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
@@ -332,13 +346,15 @@ 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) {
+ int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- for (int i=0; i<32; i++) {
+ for (i=0; i<32; i++) {
+ int j;
int c = 0;
- for (int j=0; j<4; j++) {
+ for (j=0; j<4; j++) {
int limb = (8*i+2*j)/26;
int shift = (8*i+2*j)%26;
c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
@@ -415,6 +431,11 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
+ uint64_t c, d;
+ uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8;
+ uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7;
+ const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL;
+
VERIFY_BITS(a[0], 30);
VERIFY_BITS(a[1], 30);
VERIFY_BITS(a[2], 30);
@@ -436,14 +457,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
VERIFY_BITS(b[8], 30);
VERIFY_BITS(b[9], 26);
- const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL;
/** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
*/
- uint64_t c, d;
-
d = (uint64_t)a[0] * b[9]
+ (uint64_t)a[1] * b[8]
+ (uint64_t)a[2] * b[7]
@@ -456,7 +474,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[0];
/* VERIFY_BITS(d, 64); */
/* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
- uint32_t t9 = d & M; d >>= 26;
+ t9 = d & M; d >>= 26;
VERIFY_BITS(t9, 26);
VERIFY_BITS(d, 38);
/* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
@@ -475,12 +493,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[1];
VERIFY_BITS(d, 63);
/* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
- uint64_t u0 = d & M; d >>= 26; c += u0 * R0;
+ u0 = d & M; d >>= 26; c += u0 * R0;
VERIFY_BITS(u0, 26);
VERIFY_BITS(d, 37);
VERIFY_BITS(c, 61);
/* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
- uint32_t t0 = c & M; c >>= 26; c += u0 * R1;
+ t0 = c & M; c >>= 26; c += u0 * R1;
VERIFY_BITS(t0, 26);
VERIFY_BITS(c, 37);
/* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
@@ -500,12 +518,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[2];
VERIFY_BITS(d, 63);
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
- uint64_t u1 = d & M; d >>= 26; c += u1 * R0;
+ u1 = d & M; d >>= 26; c += u1 * R0;
VERIFY_BITS(u1, 26);
VERIFY_BITS(d, 37);
VERIFY_BITS(c, 63);
/* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
- uint32_t t1 = c & M; c >>= 26; c += u1 * R1;
+ t1 = c & M; c >>= 26; c += u1 * R1;
VERIFY_BITS(t1, 26);
VERIFY_BITS(c, 38);
/* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
@@ -525,12 +543,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[3];
VERIFY_BITS(d, 63);
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
- uint64_t u2 = d & M; d >>= 26; c += u2 * R0;
+ u2 = d & M; d >>= 26; c += u2 * R0;
VERIFY_BITS(u2, 26);
VERIFY_BITS(d, 37);
VERIFY_BITS(c, 63);
/* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
- uint32_t t2 = c & M; c >>= 26; c += u2 * R1;
+ t2 = c & M; c >>= 26; c += u2 * R1;
VERIFY_BITS(t2, 26);
VERIFY_BITS(c, 38);
/* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
@@ -550,12 +568,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[4];
VERIFY_BITS(d, 63);
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
- uint64_t u3 = d & M; d >>= 26; c += u3 * R0;
+ u3 = d & M; d >>= 26; c += u3 * R0;
VERIFY_BITS(u3, 26);
VERIFY_BITS(d, 37);
/* VERIFY_BITS(c, 64); */
/* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
- uint32_t t3 = c & M; c >>= 26; c += u3 * R1;
+ t3 = c & M; c >>= 26; c += u3 * R1;
VERIFY_BITS(t3, 26);
VERIFY_BITS(c, 39);
/* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
@@ -575,12 +593,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[5];
VERIFY_BITS(d, 62);
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
- uint64_t u4 = d & M; d >>= 26; c += u4 * R0;
+ u4 = d & M; d >>= 26; c += u4 * R0;
VERIFY_BITS(u4, 26);
VERIFY_BITS(d, 36);
/* VERIFY_BITS(c, 64); */
/* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
- uint32_t t4 = c & M; c >>= 26; c += u4 * R1;
+ t4 = c & M; c >>= 26; c += u4 * R1;
VERIFY_BITS(t4, 26);
VERIFY_BITS(c, 39);
/* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
@@ -600,12 +618,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[6];
VERIFY_BITS(d, 62);
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
- uint64_t u5 = d & M; d >>= 26; c += u5 * R0;
+ u5 = d & M; d >>= 26; c += u5 * R0;
VERIFY_BITS(u5, 26);
VERIFY_BITS(d, 36);
/* VERIFY_BITS(c, 64); */
/* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
- uint32_t t5 = c & M; c >>= 26; c += u5 * R1;
+ t5 = c & M; c >>= 26; c += u5 * R1;
VERIFY_BITS(t5, 26);
VERIFY_BITS(c, 39);
/* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
@@ -625,12 +643,12 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[7];
VERIFY_BITS(d, 61);
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
- uint64_t u6 = d & M; d >>= 26; c += u6 * R0;
+ u6 = d & M; d >>= 26; c += u6 * R0;
VERIFY_BITS(u6, 26);
VERIFY_BITS(d, 35);
/* VERIFY_BITS(c, 64); */
/* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
- uint32_t t6 = c & M; c >>= 26; c += u6 * R1;
+ t6 = c & M; c >>= 26; c += u6 * R1;
VERIFY_BITS(t6, 26);
VERIFY_BITS(c, 39);
/* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
@@ -651,13 +669,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[9] * b[8];
VERIFY_BITS(d, 58);
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
- uint64_t u7 = d & M; d >>= 26; c += u7 * R0;
+ u7 = d & M; d >>= 26; c += u7 * R0;
VERIFY_BITS(u7, 26);
VERIFY_BITS(d, 32);
/* VERIFY_BITS(c, 64); */
VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL);
/* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
- uint32_t t7 = c & M; c >>= 26; c += u7 * R1;
+ t7 = c & M; c >>= 26; c += u7 * R1;
VERIFY_BITS(t7, 26);
VERIFY_BITS(c, 38);
/* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
@@ -678,7 +696,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
d += (uint64_t)a[9] * b[9];
VERIFY_BITS(d, 57);
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- uint64_t u8 = d & M; d >>= 26; c += u8 * R0;
+ u8 = d & M; d >>= 26; c += u8 * R0;
VERIFY_BITS(u8, 26);
VERIFY_BITS(d, 31);
/* VERIFY_BITS(c, 64); */
@@ -742,6 +760,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
}
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) {
+ uint64_t c, d;
+ uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8;
+ uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7;
+ const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL;
+
VERIFY_BITS(a[0], 30);
VERIFY_BITS(a[1], 30);
VERIFY_BITS(a[2], 30);
@@ -753,14 +776,11 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
VERIFY_BITS(a[8], 30);
VERIFY_BITS(a[9], 26);
- const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL;
/** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
* px is a shorthand for sum(a[i]*a[x-i], i=0..x).
* Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
*/
- uint64_t c, d;
-
d = (uint64_t)(a[0]*2) * a[9]
+ (uint64_t)(a[1]*2) * a[8]
+ (uint64_t)(a[2]*2) * a[7]
@@ -768,7 +788,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)(a[4]*2) * a[5];
/* VERIFY_BITS(d, 64); */
/* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
- uint32_t t9 = d & M; d >>= 26;
+ t9 = d & M; d >>= 26;
VERIFY_BITS(t9, 26);
VERIFY_BITS(d, 38);
/* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
@@ -783,12 +803,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[5] * a[5];
VERIFY_BITS(d, 63);
/* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
- uint64_t u0 = d & M; d >>= 26; c += u0 * R0;
+ u0 = d & M; d >>= 26; c += u0 * R0;
VERIFY_BITS(u0, 26);
VERIFY_BITS(d, 37);
VERIFY_BITS(c, 61);
/* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
- uint32_t t0 = c & M; c >>= 26; c += u0 * R1;
+ t0 = c & M; c >>= 26; c += u0 * R1;
VERIFY_BITS(t0, 26);
VERIFY_BITS(c, 37);
/* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
@@ -803,12 +823,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)(a[5]*2) * a[6];
VERIFY_BITS(d, 63);
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
- uint64_t u1 = d & M; d >>= 26; c += u1 * R0;
+ u1 = d & M; d >>= 26; c += u1 * R0;
VERIFY_BITS(u1, 26);
VERIFY_BITS(d, 37);
VERIFY_BITS(c, 63);
/* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
- uint32_t t1 = c & M; c >>= 26; c += u1 * R1;
+ t1 = c & M; c >>= 26; c += u1 * R1;
VERIFY_BITS(t1, 26);
VERIFY_BITS(c, 38);
/* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
@@ -824,12 +844,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[6] * a[6];
VERIFY_BITS(d, 63);
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
- uint64_t u2 = d & M; d >>= 26; c += u2 * R0;
+ u2 = d & M; d >>= 26; c += u2 * R0;
VERIFY_BITS(u2, 26);
VERIFY_BITS(d, 37);
VERIFY_BITS(c, 63);
/* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
- uint32_t t2 = c & M; c >>= 26; c += u2 * R1;
+ t2 = c & M; c >>= 26; c += u2 * R1;
VERIFY_BITS(t2, 26);
VERIFY_BITS(c, 38);
/* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
@@ -844,12 +864,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)(a[6]*2) * a[7];
VERIFY_BITS(d, 63);
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
- uint64_t u3 = d & M; d >>= 26; c += u3 * R0;
+ u3 = d & M; d >>= 26; c += u3 * R0;
VERIFY_BITS(u3, 26);
VERIFY_BITS(d, 37);
/* VERIFY_BITS(c, 64); */
/* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
- uint32_t t3 = c & M; c >>= 26; c += u3 * R1;
+ t3 = c & M; c >>= 26; c += u3 * R1;
VERIFY_BITS(t3, 26);
VERIFY_BITS(c, 39);
/* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
@@ -865,12 +885,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[7] * a[7];
VERIFY_BITS(d, 62);
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
- uint64_t u4 = d & M; d >>= 26; c += u4 * R0;
+ u4 = d & M; d >>= 26; c += u4 * R0;
VERIFY_BITS(u4, 26);
VERIFY_BITS(d, 36);
/* VERIFY_BITS(c, 64); */
/* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
- uint32_t t4 = c & M; c >>= 26; c += u4 * R1;
+ t4 = c & M; c >>= 26; c += u4 * R1;
VERIFY_BITS(t4, 26);
VERIFY_BITS(c, 39);
/* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
@@ -885,12 +905,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)(a[7]*2) * a[8];
VERIFY_BITS(d, 62);
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
- uint64_t u5 = d & M; d >>= 26; c += u5 * R0;
+ u5 = d & M; d >>= 26; c += u5 * R0;
VERIFY_BITS(u5, 26);
VERIFY_BITS(d, 36);
/* VERIFY_BITS(c, 64); */
/* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
- uint32_t t5 = c & M; c >>= 26; c += u5 * R1;
+ t5 = c & M; c >>= 26; c += u5 * R1;
VERIFY_BITS(t5, 26);
VERIFY_BITS(c, 39);
/* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
@@ -906,12 +926,12 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
+ (uint64_t)a[8] * a[8];
VERIFY_BITS(d, 61);
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
- uint64_t u6 = d & M; d >>= 26; c += u6 * R0;
+ u6 = d & M; d >>= 26; c += u6 * R0;
VERIFY_BITS(u6, 26);
VERIFY_BITS(d, 35);
/* VERIFY_BITS(c, 64); */
/* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
- uint32_t t6 = c & M; c >>= 26; c += u6 * R1;
+ t6 = c & M; c >>= 26; c += u6 * R1;
VERIFY_BITS(t6, 26);
VERIFY_BITS(c, 39);
/* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
@@ -927,13 +947,13 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
d += (uint64_t)(a[8]*2) * a[9];
VERIFY_BITS(d, 58);
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
- uint64_t u7 = d & M; d >>= 26; c += u7 * R0;
+ u7 = d & M; d >>= 26; c += u7 * R0;
VERIFY_BITS(u7, 26);
VERIFY_BITS(d, 32);
/* VERIFY_BITS(c, 64); */
VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL);
/* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
- uint32_t t7 = c & M; c >>= 26; c += u7 * R1;
+ t7 = c & M; c >>= 26; c += u7 * R1;
VERIFY_BITS(t7, 26);
VERIFY_BITS(c, 38);
/* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
@@ -950,7 +970,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
d += (uint64_t)a[9] * a[9];
VERIFY_BITS(d, 57);
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- uint64_t u8 = d & M; d >>= 26; c += u8 * R0;
+ u8 = d & M; d >>= 26; c += u8 * R0;
VERIFY_BITS(u8, 26);
VERIFY_BITS(d, 31);
/* VERIFY_BITS(c, 64); */
@@ -1043,8 +1063,10 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
-static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
- uint32_t mask0 = flag + ~((uint32_t)0), mask1 = ~mask0;
+static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) {
+ uint32_t mask0, mask1;
+ mask0 = flag + ~((uint32_t)0);
+ mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
@@ -1053,13 +1075,36 @@ static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int fl
r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1);
r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1);
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
- r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
- r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
+}
+
+static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
- if (flag) {
- r->magnitude = a->magnitude;
- r->normalized = a->normalized;
- }
+ VERIFY_CHECK(a->normalized);
+#endif
+ r->n[0] = a->n[0] | a->n[1] << 26;
+ r->n[1] = a->n[1] >> 6 | a->n[2] << 20;
+ r->n[2] = a->n[2] >> 12 | a->n[3] << 14;
+ r->n[3] = a->n[3] >> 18 | a->n[4] << 8;
+ r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28;
+ r->n[5] = a->n[6] >> 4 | a->n[7] << 22;
+ r->n[6] = a->n[7] >> 10 | a->n[8] << 16;
+ r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
+}
+
+static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) {
+ r->n[0] = a->n[0] & 0x3FFFFFFUL;
+ r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);
+ r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);
+ r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL);
+ r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL);
+ r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL;
+ r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL);
+ r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL);
+ r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL);
+ r->n[9] = a->n[7] >> 10;
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
#endif
}
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index aeb0a6a1e8..4513d36f49 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -18,4 +18,30 @@ typedef struct {
#endif
} secp256k1_fe_t;
+/* 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 \
+}
+
+#ifdef VERIFY
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
+#else
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
+#endif
+
+typedef struct {
+ uint64_t n[4];
+} secp256k1_fe_storage_t;
+
+#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \
+ (d0) | ((uint64_t)(d1)) << 32, \
+ (d2) | ((uint64_t)(d3)) << 32, \
+ (d4) | ((uint64_t)(d5)) << 32, \
+ (d6) | ((uint64_t)(d7)) << 32 \
+}}
+
#endif
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 4db9e6f5ff..2f9c8704a8 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -30,13 +30,11 @@
* output.
*/
-static void secp256k1_fe_inner_start(void) {}
-static void secp256k1_fe_inner_stop(void) {}
-
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
const uint64_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
+ /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m);
r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m);
r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m);
@@ -62,8 +60,8 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
- uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
uint64_t m;
+ uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x1000003D1ULL;
@@ -129,8 +127,8 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
- uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
uint64_t m;
+ uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x1000003D1ULL;
@@ -172,12 +170,12 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
- /* Reduce t4 at the start so there will be at most a single carry from the first pass */
- uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
-
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
uint64_t z0, z1;
+ /* Reduce t4 at the start so there will be at most a single carry from the first pass */
+ uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
+
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x1000003D1ULL;
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL;
@@ -193,22 +191,31 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
}
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
- uint64_t t0 = r->n[0], t4 = r->n[4];
+ uint64_t t0, t1, t2, t3, t4;
+ uint64_t z0, z1;
+ uint64_t x;
+
+ t0 = r->n[0];
+ t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
- uint64_t x = t4 >> 48;
+ x = t4 >> 48;
/* The first pass ensures the magnitude is 1, ... */
t0 += x * 0x1000003D1ULL;
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
- uint64_t z0 = t0 & 0xFFFFFFFFFFFFFULL, z1 = z0 ^ 0x1000003D0ULL;
+ z0 = t0 & 0xFFFFFFFFFFFFFULL;
+ z1 = z0 ^ 0x1000003D0ULL;
/* Fast return path should catch the majority of cases */
if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL))
return 0;
- uint64_t t1 = r->n[1], t2 = r->n[2], t3 = r->n[3];
+ t1 = r->n[1];
+ t2 = r->n[2];
+ t3 = r->n[3];
+
t4 &= 0x0FFFFFFFFFFFFULL;
t1 += (t0 >> 52); t0 = z0;
@@ -234,11 +241,11 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
}
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+ const uint64_t *t = a->n;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- const uint64_t *t = a->n;
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
}
@@ -251,23 +258,25 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
}
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
+ int i;
#ifdef VERIFY
a->magnitude = 0;
a->normalized = 1;
#endif
- for (int i=0; i<5; i++) {
+ for (i=0; i<5; i++) {
a->n[i] = 0;
}
}
static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+ int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
#endif
- for (int i = 4; i >= 0; i--) {
+ for (i = 4; i >= 0; i--) {
if (a->n[i] > b->n[i]) return 1;
if (a->n[i] < b->n[i]) return -1;
}
@@ -275,9 +284,11 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b
}
static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+ int i;
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
- for (int i=0; i<32; i++) {
- for (int j=0; j<2; j++) {
+ for (i=0; i<32; i++) {
+ int j;
+ for (j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
@@ -296,13 +307,15 @@ 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) {
+ int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- for (int i=0; i<32; i++) {
+ for (i=0; i<32; i++) {
+ int j;
int c = 0;
- for (int j=0; j<2; j++) {
+ for (j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
@@ -386,18 +399,35 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
-static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
- uint64_t mask0 = flag + ~((uint64_t)0), mask1 = ~mask0;
+static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) {
+ uint64_t mask0, mask1;
+ mask0 = flag + ~((uint64_t)0);
+ mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
- r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
+}
+
+static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
- if (flag) {
- r->magnitude = a->magnitude;
- r->normalized = a->normalized;
- }
+ VERIFY_CHECK(a->normalized);
+#endif
+ r->n[0] = a->n[0] | a->n[1] << 52;
+ r->n[1] = a->n[1] >> 12 | a->n[2] << 40;
+ r->n[2] = a->n[2] >> 24 | a->n[3] << 28;
+ r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
+}
+
+static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) {
+ r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
+ r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
+ r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
+ r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);
+ r->n[4] = a->n[3] >> 16;
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
#endif
}
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index ec631833cf..9280bb5ea2 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -16,6 +16,11 @@
#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
+ uint128_t c, d;
+ uint64_t t3, t4, tx, u0;
+ uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
+ const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
+
VERIFY_BITS(a[0], 56);
VERIFY_BITS(a[1], 56);
VERIFY_BITS(a[2], 56);
@@ -28,63 +33,58 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(b[4], 52);
VERIFY_CHECK(r != b);
- const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* Note that [x 0 0 0 0 0] = [x*R].
*/
- uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
-
- __int128 c, d;
-
- d = (__int128)a0 * b[3]
- + (__int128)a1 * b[2]
- + (__int128)a2 * b[1]
- + (__int128)a3 * b[0];
+ d = (uint128_t)a0 * b[3]
+ + (uint128_t)a1 * b[2]
+ + (uint128_t)a2 * b[1]
+ + (uint128_t)a3 * b[0];
VERIFY_BITS(d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
- c = (__int128)a4 * b[4];
+ c = (uint128_t)a4 * b[4];
VERIFY_BITS(c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (c & M) * R; c >>= 52;
VERIFY_BITS(d, 115);
VERIFY_BITS(c, 60);
/* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- uint64_t t3 = d & M; d >>= 52;
+ t3 = d & M; d >>= 52;
VERIFY_BITS(t3, 52);
VERIFY_BITS(d, 63);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- d += (__int128)a0 * b[4]
- + (__int128)a1 * b[3]
- + (__int128)a2 * b[2]
- + (__int128)a3 * b[1]
- + (__int128)a4 * b[0];
+ d += (uint128_t)a0 * b[4]
+ + (uint128_t)a1 * b[3]
+ + (uint128_t)a2 * b[2]
+ + (uint128_t)a3 * b[1]
+ + (uint128_t)a4 * b[0];
VERIFY_BITS(d, 115);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += c * R;
VERIFY_BITS(d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- uint64_t t4 = d & M; d >>= 52;
+ t4 = d & M; d >>= 52;
VERIFY_BITS(t4, 52);
VERIFY_BITS(d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- uint64_t tx = (t4 >> 48); t4 &= (M >> 4);
+ tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- c = (__int128)a0 * b[0];
+ c = (uint128_t)a0 * b[0];
VERIFY_BITS(c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
- d += (__int128)a1 * b[4]
- + (__int128)a2 * b[3]
- + (__int128)a3 * b[2]
- + (__int128)a4 * b[1];
+ d += (uint128_t)a1 * b[4]
+ + (uint128_t)a2 * b[3]
+ + (uint128_t)a3 * b[2]
+ + (uint128_t)a4 * b[1];
VERIFY_BITS(d, 115);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- uint64_t u0 = d & M; d >>= 52;
+ u0 = d & M; d >>= 52;
VERIFY_BITS(u0, 52);
VERIFY_BITS(d, 63);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
@@ -92,7 +92,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (__int128)u0 * (R >> 4);
+ c += (uint128_t)u0 * (R >> 4);
VERIFY_BITS(c, 115);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = c & M; c >>= 52;
@@ -100,13 +100,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (__int128)a0 * b[1]
- + (__int128)a1 * b[0];
+ c += (uint128_t)a0 * b[1]
+ + (uint128_t)a1 * b[0];
VERIFY_BITS(c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
- d += (__int128)a2 * b[4]
- + (__int128)a3 * b[3]
- + (__int128)a4 * b[2];
+ d += (uint128_t)a2 * b[4]
+ + (uint128_t)a3 * b[3]
+ + (uint128_t)a4 * b[2];
VERIFY_BITS(d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
@@ -118,13 +118,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (__int128)a0 * b[2]
- + (__int128)a1 * b[1]
- + (__int128)a2 * b[0];
+ c += (uint128_t)a0 * b[2]
+ + (uint128_t)a1 * b[1]
+ + (uint128_t)a2 * b[0];
VERIFY_BITS(c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
- d += (__int128)a3 * b[4]
- + (__int128)a4 * b[3];
+ d += (uint128_t)a3 * b[4]
+ + (uint128_t)a4 * b[3];
VERIFY_BITS(d, 114);
/* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (d & M) * R; d >>= 52;
@@ -153,64 +153,64 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
}
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
+ uint128_t c, d;
+ uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
+ int64_t t3, t4, tx, u0;
+ const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
+
VERIFY_BITS(a[0], 56);
VERIFY_BITS(a[1], 56);
VERIFY_BITS(a[2], 56);
VERIFY_BITS(a[3], 56);
VERIFY_BITS(a[4], 52);
- const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
/** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
* px is a shorthand for sum(a[i]*a[x-i], i=0..x).
* Note that [x 0 0 0 0 0] = [x*R].
*/
- __int128 c, d;
-
- uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
-
- d = (__int128)(a0*2) * a3
- + (__int128)(a1*2) * a2;
+ d = (uint128_t)(a0*2) * a3
+ + (uint128_t)(a1*2) * a2;
VERIFY_BITS(d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
- c = (__int128)a4 * a4;
+ c = (uint128_t)a4 * a4;
VERIFY_BITS(c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (c & M) * R; c >>= 52;
VERIFY_BITS(d, 115);
VERIFY_BITS(c, 60);
/* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
- uint64_t t3 = d & M; d >>= 52;
+ t3 = d & M; d >>= 52;
VERIFY_BITS(t3, 52);
VERIFY_BITS(d, 63);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
a4 *= 2;
- d += (__int128)a0 * a4
- + (__int128)(a1*2) * a3
- + (__int128)a2 * a2;
+ d += (uint128_t)a0 * a4
+ + (uint128_t)(a1*2) * a3
+ + (uint128_t)a2 * a2;
VERIFY_BITS(d, 115);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += c * R;
VERIFY_BITS(d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- uint64_t t4 = d & M; d >>= 52;
+ t4 = d & M; d >>= 52;
VERIFY_BITS(t4, 52);
VERIFY_BITS(d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- uint64_t tx = (t4 >> 48); t4 &= (M >> 4);
+ tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
- c = (__int128)a0 * a0;
+ c = (uint128_t)a0 * a0;
VERIFY_BITS(c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
- d += (__int128)a1 * a4
- + (__int128)(a2*2) * a3;
+ d += (uint128_t)a1 * a4
+ + (uint128_t)(a2*2) * a3;
VERIFY_BITS(d, 114);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- uint64_t u0 = d & M; d >>= 52;
+ u0 = d & M; d >>= 52;
VERIFY_BITS(u0, 52);
VERIFY_BITS(d, 62);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
@@ -218,7 +218,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
- c += (__int128)u0 * (R >> 4);
+ c += (uint128_t)u0 * (R >> 4);
VERIFY_BITS(c, 113);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = c & M; c >>= 52;
@@ -227,11 +227,11 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
a0 *= 2;
- c += (__int128)a0 * a1;
+ c += (uint128_t)a0 * a1;
VERIFY_BITS(c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
- d += (__int128)a2 * a4
- + (__int128)a3 * a3;
+ d += (uint128_t)a2 * a4
+ + (uint128_t)a3 * a3;
VERIFY_BITS(d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
@@ -243,11 +243,11 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
VERIFY_BITS(c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
- c += (__int128)a0 * a2
- + (__int128)a1 * a1;
+ c += (uint128_t)a0 * a2
+ + (uint128_t)a1 * a1;
VERIFY_BITS(c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
- d += (__int128)a3 * a4;
+ d += (uint128_t)a3 * a4;
VERIFY_BITS(d, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (d & M) * R; d >>= 52;
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 4e2c24aa15..047914cf28 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -21,49 +21,6 @@
#error "Please select field implementation"
#endif
-static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
- if (*rlen < 65) {
- *rlen = 65;
- return;
- }
- *rlen = 65;
- unsigned char tmp[32];
- secp256k1_fe_t b = *a;
- secp256k1_fe_normalize(&b);
- secp256k1_fe_get_b32(tmp, &b);
- for (int i=0; i<32; i++) {
- static const char *c = "0123456789ABCDEF";
- r[2*i] = c[(tmp[i] >> 4) & 0xF];
- r[2*i+1] = c[(tmp[i]) & 0xF];
- }
- r[64] = 0x00;
-}
-
-static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
- unsigned char tmp[32] = {};
- static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
- 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
- 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0};
- for (int i=0; i<32; i++) {
- if (alen > i*2)
- tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]];
- }
- return secp256k1_fe_set_b32(r, tmp);
-}
-
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
secp256k1_fe_t na;
secp256k1_fe_negate(&na, a, 1);
@@ -72,62 +29,62 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, cons
}
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;
+ int j;
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
* 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
*/
- secp256k1_fe_t x2;
secp256k1_fe_sqr(&x2, a);
secp256k1_fe_mul(&x2, &x2, a);
- secp256k1_fe_t x3;
secp256k1_fe_sqr(&x3, &x2);
secp256k1_fe_mul(&x3, &x3, a);
- secp256k1_fe_t x6 = x3;
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6);
+ x6 = x3;
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6);
secp256k1_fe_mul(&x6, &x6, &x3);
- secp256k1_fe_t x9 = x6;
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9);
+ x9 = x6;
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9);
secp256k1_fe_mul(&x9, &x9, &x3);
- secp256k1_fe_t x11 = x9;
- for (int j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11);
+ x11 = x9;
+ for (j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11);
secp256k1_fe_mul(&x11, &x11, &x2);
- secp256k1_fe_t x22 = x11;
- for (int j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22);
+ x22 = x11;
+ for (j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22);
secp256k1_fe_mul(&x22, &x22, &x11);
- secp256k1_fe_t x44 = x22;
- for (int j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44);
+ x44 = x22;
+ for (j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44);
secp256k1_fe_mul(&x44, &x44, &x22);
- secp256k1_fe_t x88 = x44;
- for (int j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88);
+ x88 = x44;
+ for (j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88);
secp256k1_fe_mul(&x88, &x88, &x44);
- secp256k1_fe_t x176 = x88;
- for (int j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176);
+ x176 = x88;
+ for (j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176);
secp256k1_fe_mul(&x176, &x176, &x88);
- secp256k1_fe_t x220 = x176;
- for (int j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220);
+ x220 = x176;
+ for (j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220);
secp256k1_fe_mul(&x220, &x220, &x44);
- secp256k1_fe_t x223 = x220;
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223);
+ x223 = x220;
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223);
secp256k1_fe_mul(&x223, &x223, &x3);
/* The final result is then assembled using a sliding window over the blocks. */
- secp256k1_fe_t t1 = x223;
- for (int j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1);
+ t1 = x223;
+ for (j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, &x22);
- for (int j=0; j<6; j++) secp256k1_fe_sqr(&t1, &t1);
+ for (j=0; j<6; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, &x2);
secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_sqr(r, &t1);
@@ -139,66 +96,66 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *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;
+ int j;
/** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
* { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
* [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
*/
- secp256k1_fe_t x2;
secp256k1_fe_sqr(&x2, a);
secp256k1_fe_mul(&x2, &x2, a);
- secp256k1_fe_t x3;
secp256k1_fe_sqr(&x3, &x2);
secp256k1_fe_mul(&x3, &x3, a);
- secp256k1_fe_t x6 = x3;
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6);
+ x6 = x3;
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6);
secp256k1_fe_mul(&x6, &x6, &x3);
- secp256k1_fe_t x9 = x6;
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9);
+ x9 = x6;
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9);
secp256k1_fe_mul(&x9, &x9, &x3);
- secp256k1_fe_t x11 = x9;
- for (int j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11);
+ x11 = x9;
+ for (j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11);
secp256k1_fe_mul(&x11, &x11, &x2);
- secp256k1_fe_t x22 = x11;
- for (int j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22);
+ x22 = x11;
+ for (j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22);
secp256k1_fe_mul(&x22, &x22, &x11);
- secp256k1_fe_t x44 = x22;
- for (int j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44);
+ x44 = x22;
+ for (j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44);
secp256k1_fe_mul(&x44, &x44, &x22);
- secp256k1_fe_t x88 = x44;
- for (int j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88);
+ x88 = x44;
+ for (j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88);
secp256k1_fe_mul(&x88, &x88, &x44);
- secp256k1_fe_t x176 = x88;
- for (int j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176);
+ x176 = x88;
+ for (j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176);
secp256k1_fe_mul(&x176, &x176, &x88);
- secp256k1_fe_t x220 = x176;
- for (int j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220);
+ x220 = x176;
+ for (j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220);
secp256k1_fe_mul(&x220, &x220, &x44);
- secp256k1_fe_t x223 = x220;
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223);
+ x223 = x220;
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223);
secp256k1_fe_mul(&x223, &x223, &x3);
/* The final result is then assembled using a sliding window over the blocks. */
- secp256k1_fe_t t1 = x223;
- for (int j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1);
+ t1 = x223;
+ for (j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, &x22);
- for (int j=0; j<5; j++) secp256k1_fe_sqr(&t1, &t1);
+ for (j=0; j<5; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, a);
- for (int j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1);
+ for (j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, &x2);
- for (int j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1);
+ for (j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(r, a, &t1);
}
@@ -206,13 +163,21 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#if defined(USE_FIELD_INV_BUILTIN)
secp256k1_fe_inv(r, a);
#elif defined(USE_FIELD_INV_NUM)
+ secp256k1_num_t n, m;
+ /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
+ static const unsigned char prime[32] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
+ };
unsigned char b[32];
secp256k1_fe_t c = *a;
secp256k1_fe_normalize_var(&c);
secp256k1_fe_get_b32(b, &c);
- secp256k1_num_t n;
secp256k1_num_set_bin(&n, b, 32);
- secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
+ secp256k1_num_set_bin(&m, prime, 32);
+ secp256k1_num_mod_inverse(&n, &n, &m);
secp256k1_num_get_bin(b, 32, &n);
VERIFY_CHECK(secp256k1_fe_set_b32(r, b));
#else
@@ -220,7 +185,9 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif
}
-static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]) {
+static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+ secp256k1_fe_t u;
+ size_t i;
if (len < 1)
return;
@@ -228,12 +195,12 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const se
r[0] = a[0];
- size_t i = 0;
+ i = 0;
while (++i < len) {
secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]);
}
- secp256k1_fe_t u; secp256k1_fe_inv_var(&u, &r[--i]);
+ secp256k1_fe_inv_var(&u, &r[--i]);
while (i > 0) {
int j = i--;
@@ -244,32 +211,4 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const se
r[0] = u;
}
-static void secp256k1_fe_start(void) {
-#ifndef USE_NUM_NONE
- static const unsigned char secp256k1_fe_consts_p[] = {
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
- };
-#endif
- if (secp256k1_fe_consts == NULL) {
- secp256k1_fe_inner_start();
- secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)checked_malloc(sizeof(secp256k1_fe_consts_t));
-#ifndef USE_NUM_NONE
- secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
-#endif
- secp256k1_fe_consts = ret;
- }
-}
-
-static void secp256k1_fe_stop(void) {
- if (secp256k1_fe_consts != NULL) {
- secp256k1_fe_consts_t *c = (secp256k1_fe_consts_t*)secp256k1_fe_consts;
- free((void*)c);
- secp256k1_fe_consts = NULL;
- secp256k1_fe_inner_stop();
- }
-}
-
#endif
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index 6dea6bb5ac..d1e5834909 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -17,6 +17,9 @@ typedef struct {
int infinity; /* whether this represents the point at infinity */
} secp256k1_ge_t;
+#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 */
@@ -25,23 +28,15 @@ typedef struct {
int infinity; /* whether this represents the point at infinity */
} secp256k1_gej_t;
-/** Global constants related to the group */
-typedef struct {
- secp256k1_ge_t g; /* the generator point */
-
-#ifdef USE_ENDOMORPHISM
- /* constants related to secp256k1's efficiently computable endomorphism */
- secp256k1_fe_t beta;
-#endif
-} secp256k1_ge_consts_t;
-
-static const secp256k1_ge_consts_t *secp256k1_ge_consts = NULL;
+#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0}
+#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
-/** Initialize the group module. */
-static void secp256k1_ge_start(void);
+typedef struct {
+ secp256k1_fe_storage_t x;
+ secp256k1_fe_storage_t y;
+} secp256k1_ge_storage_t;
-/** De-initialize the group module. */
-static void secp256k1_ge_stop(void);
+#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))}
/** Set a group element equal to the point at infinity */
static void secp256k1_ge_set_infinity(secp256k1_ge_t *r);
@@ -61,14 +56,11 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a);
static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a);
-/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
-static void secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a);
-
/** 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);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
-static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t r[len], const secp256k1_gej_t a[len]);
+static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a);
/** Set a group element (jacobian) equal to the point at infinity. */
@@ -103,9 +95,6 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
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);
-/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
-static void secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a);
-
#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);
@@ -117,4 +106,13 @@ static void secp256k1_gej_clear(secp256k1_gej_t *r);
/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */
static void secp256k1_ge_clear(secp256k1_ge_t *r);
+/** Convert a group element to the storage type. */
+static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t*);
+
+/** Convert a group element back from the storage type. */
+static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t*);
+
+/** 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);
+
#endif
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index fef06df289..8d8c359c5a 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -13,6 +13,16 @@
#include "field.h"
#include "group.h"
+/** 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(
+ 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;
}
@@ -33,32 +43,12 @@ static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) {
secp256k1_fe_negate(&r->y, &r->y, 1);
}
-static void secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a) {
- char cx[65]; int lx=65;
- char cy[65]; int ly=65;
- secp256k1_fe_get_hex(cx, &lx, &a->x);
- secp256k1_fe_get_hex(cy, &ly, &a->y);
- lx = strlen(cx);
- ly = strlen(cy);
- int len = lx + ly + 3 + 1;
- if (*rlen < len) {
- *rlen = len;
- return;
- }
- *rlen = len;
- r[0] = '(';
- memcpy(r+1, cx, lx);
- r[1+lx] = ',';
- memcpy(r+2+lx, cy, ly);
- r[2+lx+ly] = ')';
- r[3+lx+ly] = 0;
-}
-
static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
+ secp256k1_fe_t z2, z3;
r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z);
- secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
- secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2);
+ secp256k1_fe_sqr(&z2, &a->z);
+ secp256k1_fe_mul(&z3, &a->z, &z2);
secp256k1_fe_mul(&a->x, &a->x, &z2);
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
@@ -67,13 +57,14 @@ static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
}
static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) {
+ secp256k1_fe_t z2, z3;
r->infinity = a->infinity;
if (a->infinity) {
return;
}
secp256k1_fe_inv_var(&a->z, &a->z);
- secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
- secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2);
+ secp256k1_fe_sqr(&z2, &a->z);
+ secp256k1_fe_mul(&z3, &a->z, &z2);
secp256k1_fe_mul(&a->x, &a->x, &z2);
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
@@ -81,26 +72,30 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) {
r->y = a->y;
}
-static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t r[len], const secp256k1_gej_t a[len]) {
+static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) {
+ secp256k1_fe_t *az;
+ secp256k1_fe_t *azi;
+ size_t i;
size_t count = 0;
- secp256k1_fe_t *az = checked_malloc(sizeof(secp256k1_fe_t) * len);
- for (size_t i=0; i<len; i++) {
+ az = checked_malloc(sizeof(secp256k1_fe_t) * len);
+ for (i = 0; i < len; i++) {
if (!a[i].infinity) {
az[count++] = a[i].z;
}
}
- secp256k1_fe_t *azi = checked_malloc(sizeof(secp256k1_fe_t) * count);
+ azi = checked_malloc(sizeof(secp256k1_fe_t) * count);
secp256k1_fe_inv_all_var(count, azi, az);
free(az);
count = 0;
- for (size_t i=0; i<len; i++) {
+ 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_t zi2; secp256k1_fe_sqr(&zi2, zi);
- secp256k1_fe_t zi3; secp256k1_fe_mul(&zi3, &zi2, zi);
+ 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);
}
@@ -136,11 +131,12 @@ static void secp256k1_ge_clear(secp256k1_ge_t *r) {
}
static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) {
+ secp256k1_fe_t x2, x3, c;
r->x = *x;
- secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, x);
- secp256k1_fe_t x3; secp256k1_fe_mul(&x3, x, &x2);
+ secp256k1_fe_sqr(&x2, x);
+ secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
- secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
+ secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&c, &x3);
if (!secp256k1_fe_sqrt_var(&r->y, &c))
return 0;
@@ -158,9 +154,10 @@ static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) {
}
static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) {
+ secp256k1_fe_t r, r2;
VERIFY_CHECK(!a->infinity);
- secp256k1_fe_t r; secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
- secp256k1_fe_t r2 = a->x; secp256k1_fe_normalize_weak(&r2);
+ 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);
}
@@ -178,6 +175,7 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) {
}
static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
+ secp256k1_fe_t y2, x3, z2, z6;
if (a->infinity)
return 0;
/** y^2 = x^3 + 7
@@ -185,10 +183,10 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
* Y^2 / Z^6 = X^3 / Z^6 + 7
* Y^2 = X^3 + 7*Z^6
*/
- secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
- secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
- secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
- secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
+ secp256k1_fe_sqr(&y2, &a->y);
+ secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
+ secp256k1_fe_sqr(&z2, &a->z);
+ secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
secp256k1_fe_mul_int(&z6, 7);
secp256k1_fe_add(&x3, &z6);
secp256k1_fe_normalize_weak(&x3);
@@ -196,27 +194,30 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
}
static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) {
+ secp256k1_fe_t y2, x3, c;
if (a->infinity)
return 0;
/* y^2 = x^3 + 7 */
- secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
- secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
- secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
+ secp256k1_fe_sqr(&y2, &a->y);
+ secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
+ secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&x3, &c);
secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3);
}
static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
- // For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
- // Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
- // y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
+ /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
+ secp256k1_fe_t 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) {
return;
}
- secp256k1_fe_t t1,t2,t3,t4;
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);
@@ -240,6 +241,8 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *
}
static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
+ /* 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;
if (a->infinity) {
*r = *b;
return;
@@ -249,14 +252,14 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
return;
}
r->infinity = 0;
- secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &b->z);
- secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
- secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &a->x, &z22);
- secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
- secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
- secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
- secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
- secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
+ secp256k1_fe_sqr(&z22, &b->z);
+ secp256k1_fe_sqr(&z12, &a->z);
+ secp256k1_fe_mul(&u1, &a->x, &z22);
+ secp256k1_fe_mul(&u2, &b->x, &z12);
+ secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
+ secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
+ secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
+ secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a);
@@ -265,11 +268,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
}
return;
}
- secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
- secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
- secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
+ secp256k1_fe_sqr(&i2, &i);
+ secp256k1_fe_sqr(&h2, &h);
+ secp256k1_fe_mul(&h3, &h, &h2);
secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h);
- secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
+ secp256k1_fe_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);
@@ -277,6 +280,8 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
}
static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
+ /* 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;
if (a->infinity) {
r->infinity = b->infinity;
r->x = b->x;
@@ -289,13 +294,13 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
return;
}
r->infinity = 0;
- secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
- secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize_weak(&u1);
- secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
- secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize_weak(&s1);
- secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
- secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
- secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
+ secp256k1_fe_sqr(&z12, &a->z);
+ u1 = a->x; secp256k1_fe_normalize_weak(&u1);
+ secp256k1_fe_mul(&u2, &b->x, &z12);
+ s1 = a->y; secp256k1_fe_normalize_weak(&s1);
+ secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
+ secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
+ secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a);
@@ -304,11 +309,11 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
}
return;
}
- secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
- secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
- secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
+ secp256k1_fe_sqr(&i2, &i);
+ secp256k1_fe_sqr(&h2, &h);
+ secp256k1_fe_mul(&h3, &h, &h2);
r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);
- secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
+ secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
@@ -316,6 +321,9 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
}
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, 19 mul_int/add/negate */
+ secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr;
+ int infinity;
VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
@@ -341,24 +349,24 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
*/
- secp256k1_fe_t zz; secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */
- secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */
- secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */
- secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */
- secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */
- secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */
- secp256k1_fe_t z = a->z; /* z = Z = Z1*Z2 (8) */
- secp256k1_fe_t t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */
- secp256k1_fe_t m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */
- secp256k1_fe_t n; secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */
- secp256k1_fe_t q; secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */
- secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */
- secp256k1_fe_t rr; secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */
+ secp256k1_fe_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, &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) */
- int infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
+ infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */
r->x = t; /* r->x = R^2 (1) */
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
@@ -386,63 +394,37 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
r->infinity = infinity;
}
+static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) {
+ secp256k1_fe_t x, y;
+ VERIFY_CHECK(!a->infinity);
+ x = a->x;
+ secp256k1_fe_normalize(&x);
+ y = a->y;
+ secp256k1_fe_normalize(&y);
+ secp256k1_fe_to_storage(&r->x, &x);
+ secp256k1_fe_to_storage(&r->y, &y);
+}
+static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) {
+ secp256k1_fe_from_storage(&r->x, &a->x);
+ secp256k1_fe_from_storage(&r->y, &a->y);
+ r->infinity = 0;
+}
-static void secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a) {
- secp256k1_gej_t c = *a;
- secp256k1_ge_t t; secp256k1_ge_set_gej(&t, &c);
- secp256k1_ge_get_hex(r, rlen, &t);
+static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag) {
+ secp256k1_fe_storage_cmov(&r->x, &a->x, flag);
+ secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
}
#ifdef USE_ENDOMORPHISM
static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
- const secp256k1_fe_t *beta = &secp256k1_ge_consts->beta;
+ static const secp256k1_fe_t beta = SECP256K1_FE_CONST(
+ 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
+ 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
+ );
*r = *a;
- secp256k1_fe_mul(&r->x, &r->x, beta);
+ secp256k1_fe_mul(&r->x, &r->x, &beta);
}
#endif
-static void secp256k1_ge_start(void) {
- static const unsigned char secp256k1_ge_consts_g_x[] = {
- 0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
- 0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
- 0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,
- 0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98
- };
- static const unsigned char secp256k1_ge_consts_g_y[] = {
- 0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,
- 0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8,
- 0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,
- 0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8
- };
-#ifdef USE_ENDOMORPHISM
- /* properties of secp256k1's efficiently computable endomorphism */
- static const unsigned char secp256k1_ge_consts_beta[] = {
- 0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
- 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
- 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
- 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee
- };
-#endif
- if (secp256k1_ge_consts == NULL) {
- secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)checked_malloc(sizeof(secp256k1_ge_consts_t));
-#ifdef USE_ENDOMORPHISM
- VERIFY_CHECK(secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta));
-#endif
- secp256k1_fe_t g_x, g_y;
- VERIFY_CHECK(secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x));
- VERIFY_CHECK(secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y));
- secp256k1_ge_set_xy(&ret->g, &g_x, &g_y);
- secp256k1_ge_consts = ret;
- }
-}
-
-static void secp256k1_ge_stop(void) {
- if (secp256k1_ge_consts != NULL) {
- secp256k1_ge_consts_t *c = (secp256k1_ge_consts_t*)secp256k1_ge_consts;
- free((void*)c);
- secp256k1_ge_consts = NULL;
- }
-}
-
#endif
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index d1e65b968a..843423d7f7 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -12,7 +12,7 @@
typedef struct {
uint32_t s[32];
- unsigned char buf[64];
+ uint32_t buf[16]; /* In big endian */
size_t bytes;
} secp256k1_sha256_t;
@@ -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);
+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_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 f35c5f7a82..60fdbf7718 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
@@ -26,8 +27,11 @@
(h) = t1 + t2; \
} while(0)
-#define ReadBE32(p) (((uint32_t)((p)[0])) << 24 | ((uint32_t)((p)[1])) << 16 | ((uint32_t)((p)[2])) << 8 | ((uint32_t)((p)[3])))
-#define WriteBE32(p, v) do { (p)[0] = (v) >> 24; (p)[1] = (v) >> 16; (p)[2] = (v) >> 8; (p)[3] = (v); } while(0)
+#ifdef WORDS_BIGENDIAN
+#define BE32(x) (x)
+#else
+#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
+#endif
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
hash->s[0] = 0x6a09e667ul;
@@ -41,27 +45,27 @@ static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
hash->bytes = 0;
}
-/** Perform one SHA-256 transformation, processing a 64-byte chunk. */
-static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* chunk) {
+/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
+static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
- Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0));
- Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4));
- Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8));
- Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12));
- Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16));
- Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20));
- Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24));
- Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28));
- Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32));
- Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36));
- Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40));
- Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44));
- Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48));
- Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = ReadBE32(chunk + 52));
- Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56));
- Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60));
+ Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));
+ Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
+ Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
+ Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
+ Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
+ Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
+ Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
+ Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
+ Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
+ Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
+ Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
+ Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
+ Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
+ Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
+ Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
+ Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
@@ -125,55 +129,40 @@ static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* chunk)
}
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) {
- const unsigned char* end = data + len;
- size_t bufsize = hash->bytes % 64;
- if (bufsize && bufsize + len >= 64) {
- // Fill the buffer, and process it.
- memcpy(hash->buf + bufsize, data, 64 - bufsize);
- hash->bytes += 64 - bufsize;
+ size_t bufsize = hash->bytes & 0x3F;
+ hash->bytes += len;
+ while (bufsize + len >= 64) {
+ /* Fill the buffer, and process it. */
+ memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);
data += 64 - bufsize;
+ len -= 64 - bufsize;
secp256k1_sha256_transform(hash->s, hash->buf);
bufsize = 0;
}
- while (end >= data + 64) {
- // Process full chunks directly from the source.
- secp256k1_sha256_transform(hash->s, data);
- hash->bytes += 64;
- data += 64;
- }
- if (end > data) {
- // Fill the buffer with what remains.
- memcpy(hash->buf + bufsize, data, end - data);
- hash->bytes += end - data;
+ if (len) {
+ /* Fill the buffer with what remains. */
+ memcpy(((unsigned char*)hash->buf) + bufsize, data, len);
}
}
static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) {
static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sizedesc[8];
- WriteBE32(sizedesc, hash->bytes >> 29);
- WriteBE32(sizedesc + 4, hash->bytes << 3);
+ uint32_t sizedesc[2];
+ uint32_t out[8];
+ int i = 0;
+ sizedesc[0] = BE32(hash->bytes >> 29);
+ sizedesc[1] = BE32(hash->bytes << 3);
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
- secp256k1_sha256_write(hash, sizedesc, 8);
- WriteBE32(out32, hash->s[0]);
- hash->s[0] = 0;
- WriteBE32(out32 + 4, hash->s[1]);
- hash->s[1] = 0;
- WriteBE32(out32 + 8, hash->s[2]);
- hash->s[2] = 0;
- WriteBE32(out32 + 12, hash->s[3]);
- hash->s[3] = 0;
- WriteBE32(out32 + 16, hash->s[4]);
- hash->s[4] = 0;
- WriteBE32(out32 + 20, hash->s[5]);
- hash->s[5] = 0;
- WriteBE32(out32 + 24, hash->s[6]);
- hash->s[6] = 0;
- WriteBE32(out32 + 28, hash->s[7]);
- hash->s[7] = 0;
+ secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);
+ for (i = 0; i < 8; i++) {
+ out[i] = BE32(hash->s[i]);
+ hash->s[i] = 0;
+ }
+ memcpy(out32, (const unsigned char*)out, 32);
}
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) {
+ int n;
unsigned char rkey[64];
if (keylen <= 64) {
memcpy(rkey, key, keylen);
@@ -187,12 +176,12 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons
}
secp256k1_sha256_initialize(&hash->outer);
- for (int n = 0; n < 64; n++)
+ for (n = 0; n < 64; n++)
rkey[n] ^= 0x5c;
secp256k1_sha256_write(&hash->outer, rkey, 64);
secp256k1_sha256_initialize(&hash->inner);
- for (int n = 0; n < 64; n++)
+ for (n = 0; n < 64; n++)
rkey[n] ^= 0x5c ^ 0x36;
secp256k1_sha256_write(&hash->inner, rkey, 64);
memset(rkey, 0, 64);
@@ -211,19 +200,22 @@ 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) {
+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) {
+ secp256k1_hmac_sha256_t hmac;
static const unsigned char zero[1] = {0x00};
static const unsigned char one[1] = {0x01};
memset(rng->v, 0x01, 32);
memset(rng->k, 0x00, 32);
- secp256k1_hmac_sha256_t hmac;
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
secp256k1_hmac_sha256_write(&hmac, zero, 1);
secp256k1_hmac_sha256_write(&hmac, key, keylen);
secp256k1_hmac_sha256_write(&hmac, msg, msglen);
+ if (rnd && rndlen) {
+ 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);
@@ -234,6 +226,9 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
secp256k1_hmac_sha256_write(&hmac, one, 1);
secp256k1_hmac_sha256_write(&hmac, key, keylen);
secp256k1_hmac_sha256_write(&hmac, msg, msglen);
+ if (rnd && rndlen) {
+ 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);
@@ -256,10 +251,10 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
while (outlen > 0) {
secp256k1_hmac_sha256_t hmac;
+ int now = outlen;
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
- int now = outlen;
if (now > 32) {
now = 32;
}
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index 19d474e59f..3e4b92d329 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -29,10 +29,10 @@ static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned char tmp[65];
int len = 0;
+ int shift = 0;
if (a->limbs>1 || a->data[0] != 0) {
len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
}
- int shift = 0;
while (shift < len && tmp[shift] == 0) shift++;
VERIFY_CHECK(len-shift <= (int)rlen);
memset(r, 0, rlen - len + shift);
@@ -43,9 +43,10 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec
}
static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
+ int len;
VERIFY_CHECK(alen > 0);
VERIFY_CHECK(alen <= 64);
- int len = mpn_set_str(r->data, a, alen, 256);
+ len = mpn_set_str(r->data, a, alen, 256);
if (len == 0) {
r->data[0] = 0;
len = 1;
@@ -91,6 +92,12 @@ 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) {
+ int i;
+ mp_limb_t g[NUM_LIMBS+1];
+ mp_limb_t u[NUM_LIMBS+1];
+ mp_limb_t v[NUM_LIMBS+1];
+ mp_size_t sn;
+ mp_size_t gn;
secp256k1_num_sanity(a);
secp256k1_num_sanity(m);
@@ -106,15 +113,12 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t
*/
VERIFY_CHECK(m->limbs <= NUM_LIMBS);
VERIFY_CHECK(m->data[m->limbs-1] != 0);
- mp_limb_t g[NUM_LIMBS+1];
- mp_limb_t u[NUM_LIMBS+1];
- mp_limb_t v[NUM_LIMBS+1];
- for (int i=0; i < m->limbs; i++) {
+ for (i = 0; i < m->limbs; i++) {
u[i] = (i < a->limbs) ? a->data[i] : 0;
v[i] = m->data[i];
}
- mp_size_t sn = NUM_LIMBS+1;
- mp_size_t gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
+ sn = NUM_LIMBS+1;
+ gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
VERIFY_CHECK(gn == 1);
VERIFY_CHECK(g[0] == 1);
r->neg = a->neg ^ m->neg;
@@ -183,10 +187,10 @@ static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, cons
}
static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ mp_limb_t tmp[2*NUM_LIMBS+1];
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
- mp_limb_t tmp[2*NUM_LIMBS+1];
VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
r->limbs = 1;
@@ -207,13 +211,14 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons
}
static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
+ int i;
if (bits % GMP_NUMB_BITS) {
- // Shift within limbs.
+ /* Shift within limbs. */
mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
}
if (bits >= GMP_NUMB_BITS) {
- // Shift full limbs.
- for (int i = 0; i < r->limbs; i++) {
+ /* Shift full limbs. */
+ for (i = 0; i < r->limbs; i++) {
int index = i + (bits / GMP_NUMB_BITS);
if (index < r->limbs && index < 2*NUM_LIMBS) {
r->data[i] = r->data[index];
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index 2f5ba0d447..f5d09f8d47 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -21,9 +21,6 @@
#error "Please select scalar implementation"
#endif
-static void secp256k1_scalar_start(void);
-static void secp256k1_scalar_stop(void);
-
/** Clear a scalar to prevent the leak of sensitive data. */
static void secp256k1_scalar_clear(secp256k1_scalar_t *r);
@@ -83,9 +80,9 @@ static void secp256k1_scalar_order_get_num(secp256k1_num_t *r);
/** Compare two scalars. */
static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
-static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
-
#ifdef USE_ENDOMORPHISM
+/** Find r1 and r2 such that r1+r2*2^128 = a. */
+static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *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);
#endif
diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h
index 5a751c6862..82899aa7b0 100644
--- a/src/secp256k1/src/scalar_4x64.h
+++ b/src/secp256k1/src/scalar_4x64.h
@@ -14,4 +14,6 @@ typedef struct {
uint64_t d[4];
} secp256k1_scalar_t;
+#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}
+
#endif
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index d144775220..ff365292f8 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
#define _SECP256K1_SCALAR_REPR_IMPL_H_
-typedef unsigned __int128 uint128_t;
-
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL)
@@ -69,8 +67,9 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
}
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) {
+ uint128_t t;
VERIFY_CHECK(overflow <= 1);
- uint128_t t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0;
+ t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0;
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1;
r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
@@ -82,6 +81,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig
}
static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+ int overflow;
uint128_t t = (uint128_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[1] + b->d[1];
@@ -90,15 +90,16 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[3] + b->d[3];
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
- int overflow = t + secp256k1_scalar_check_overflow(r);
+ overflow = t + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
+ uint128_t t;
VERIFY_CHECK(bit < 256);
- uint128_t t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
+ t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
@@ -113,11 +114,12 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
}
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
+ int over;
r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56;
r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56;
r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56;
r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56;
- int over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
+ over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
}
@@ -195,16 +197,16 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd2(a,b) { \
- uint64_t tl, th; \
+ uint64_t tl, th, th2, tl2; \
{ \
uint128_t t = (uint128_t)a * b; \
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = t; \
} \
- uint64_t th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
+ th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
- uint64_t tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
+ tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \
@@ -217,8 +219,9 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
+ unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
- unsigned int over = (c0 < (a)) ? 1 : 0; \
+ over = (c0 < (a)) ? 1 : 0; \
c1 += over; /* overflow is handled on the next line */ \
c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \
}
@@ -248,63 +251,301 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
}
static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) {
- uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7];
+#ifdef USE_ASM_X86_64
+ /* Reduce 512 bits into 385. */
+ uint64_t m0, m1, m2, m3, m4, m5, m6;
+ uint64_t p0, p1, p2, p3, p4;
+ uint64_t c;
+
+ __asm__ __volatile__(
+ /* Preload. */
+ "movq 32(%%rsi), %%r11\n"
+ "movq 40(%%rsi), %%r12\n"
+ "movq 48(%%rsi), %%r13\n"
+ "movq 56(%%rsi), %%r14\n"
+ /* Initialize r8,r9,r10 */
+ "movq 0(%%rsi), %%r8\n"
+ "movq $0, %%r9\n"
+ "movq $0, %%r10\n"
+ /* (r8,r9) += n0 * c0 */
+ "movq %8, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ /* extract m0 */
+ "movq %%r8, %q0\n"
+ "movq $0, %%r8\n"
+ /* (r9,r10) += l1 */
+ "addq 8(%%rsi), %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r9,r10,r8) += n1 * c0 */
+ "movq %8, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += n0 * c1 */
+ "movq %9, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* extract m1 */
+ "movq %%r9, %q1\n"
+ "movq $0, %%r9\n"
+ /* (r10,r8,r9) += l2 */
+ "addq 16(%%rsi), %%r10\n"
+ "adcq $0, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += n2 * c0 */
+ "movq %8, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += n1 * c1 */
+ "movq %9, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += n0 */
+ "addq %%r11, %%r10\n"
+ "adcq $0, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* extract m2 */
+ "movq %%r10, %q2\n"
+ "movq $0, %%r10\n"
+ /* (r8,r9,r10) += l3 */
+ "addq 24(%%rsi), %%r8\n"
+ "adcq $0, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += n3 * c0 */
+ "movq %8, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += n2 * c1 */
+ "movq %9, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += n1 */
+ "addq %%r12, %%r8\n"
+ "adcq $0, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* extract m3 */
+ "movq %%r8, %q3\n"
+ "movq $0, %%r8\n"
+ /* (r9,r10,r8) += n3 * c1 */
+ "movq %9, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += n2 */
+ "addq %%r13, %%r9\n"
+ "adcq $0, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* extract m4 */
+ "movq %%r9, %q4\n"
+ /* (r10,r8) += n3 */
+ "addq %%r14, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* extract m5 */
+ "movq %%r10, %q5\n"
+ /* extract m6 */
+ "movq %%r8, %q6\n"
+ : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
+ : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
+ : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
- /* 160 bit accumulator. */
- uint64_t c0, c1;
- uint32_t c2;
+ /* Reduce 385 bits into 258. */
+ __asm__ __volatile__(
+ /* Preload */
+ "movq %q9, %%r11\n"
+ "movq %q10, %%r12\n"
+ "movq %q11, %%r13\n"
+ /* Initialize (r8,r9,r10) */
+ "movq %q5, %%r8\n"
+ "movq $0, %%r9\n"
+ "movq $0, %%r10\n"
+ /* (r8,r9) += m4 * c0 */
+ "movq %12, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ /* extract p0 */
+ "movq %%r8, %q0\n"
+ "movq $0, %%r8\n"
+ /* (r9,r10) += m1 */
+ "addq %q6, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r9,r10,r8) += m5 * c0 */
+ "movq %12, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += m4 * c1 */
+ "movq %13, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* extract p1 */
+ "movq %%r9, %q1\n"
+ "movq $0, %%r9\n"
+ /* (r10,r8,r9) += m2 */
+ "addq %q7, %%r10\n"
+ "adcq $0, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += m6 * c0 */
+ "movq %12, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += m5 * c1 */
+ "movq %13, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += m4 */
+ "addq %%r11, %%r10\n"
+ "adcq $0, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* extract p2 */
+ "movq %%r10, %q2\n"
+ /* (r8,r9) += m3 */
+ "addq %q8, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r8,r9) += m6 * c1 */
+ "movq %13, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ /* (r8,r9) += m5 */
+ "addq %%r12, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* extract p3 */
+ "movq %%r8, %q3\n"
+ /* (r9) += m6 */
+ "addq %%r13, %%r9\n"
+ /* extract p4 */
+ "movq %%r9, %q4\n"
+ : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4)
+ : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
+ : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc");
+
+ /* Reduce 258 bits into 256. */
+ __asm__ __volatile__(
+ /* Preload */
+ "movq %q5, %%r10\n"
+ /* (rax,rdx) = p4 * c0 */
+ "movq %7, %%rax\n"
+ "mulq %%r10\n"
+ /* (rax,rdx) += p0 */
+ "addq %q1, %%rax\n"
+ "adcq $0, %%rdx\n"
+ /* extract r0 */
+ "movq %%rax, 0(%q6)\n"
+ /* Move to (r8,r9) */
+ "movq %%rdx, %%r8\n"
+ "movq $0, %%r9\n"
+ /* (r8,r9) += p1 */
+ "addq %q2, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r8,r9) += p4 * c1 */
+ "movq %8, %%rax\n"
+ "mulq %%r10\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ /* Extract r1 */
+ "movq %%r8, 8(%q6)\n"
+ "movq $0, %%r8\n"
+ /* (r9,r8) += p4 */
+ "addq %%r10, %%r9\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r8) += p2 */
+ "addq %q3, %%r9\n"
+ "adcq $0, %%r8\n"
+ /* Extract r2 */
+ "movq %%r9, 16(%q6)\n"
+ "movq $0, %%r9\n"
+ /* (r8,r9) += p3 */
+ "addq %q4, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* Extract r3 */
+ "movq %%r8, 24(%q6)\n"
+ /* Extract c */
+ "movq %%r9, %q0\n"
+ : "=g"(c)
+ : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
+ : "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
+#else
+ uint128_t c;
+ uint64_t c0, c1, c2;
+ uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7];
+ uint64_t m0, m1, m2, m3, m4, m5;
+ uint32_t m6;
+ uint64_t p0, p1, p2, p3;
+ uint32_t p4;
/* Reduce 512 bits into 385. */
/* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */
c0 = l[0]; c1 = 0; c2 = 0;
muladd_fast(n0, SECP256K1_N_C_0);
- uint64_t m0; extract_fast(m0);
+ extract_fast(m0);
sumadd_fast(l[1]);
muladd(n1, SECP256K1_N_C_0);
muladd(n0, SECP256K1_N_C_1);
- uint64_t m1; extract(m1);
+ extract(m1);
sumadd(l[2]);
muladd(n2, SECP256K1_N_C_0);
muladd(n1, SECP256K1_N_C_1);
sumadd(n0);
- uint64_t m2; extract(m2);
+ extract(m2);
sumadd(l[3]);
muladd(n3, SECP256K1_N_C_0);
muladd(n2, SECP256K1_N_C_1);
sumadd(n1);
- uint64_t m3; extract(m3);
+ extract(m3);
muladd(n3, SECP256K1_N_C_1);
sumadd(n2);
- uint64_t m4; extract(m4);
+ extract(m4);
sumadd_fast(n3);
- uint64_t m5; extract_fast(m5);
+ extract_fast(m5);
VERIFY_CHECK(c0 <= 1);
- uint32_t m6 = c0;
+ m6 = c0;
/* Reduce 385 bits into 258. */
/* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */
c0 = m0; c1 = 0; c2 = 0;
muladd_fast(m4, SECP256K1_N_C_0);
- uint64_t p0; extract_fast(p0);
+ extract_fast(p0);
sumadd_fast(m1);
muladd(m5, SECP256K1_N_C_0);
muladd(m4, SECP256K1_N_C_1);
- uint64_t p1; extract(p1);
+ extract(p1);
sumadd(m2);
muladd(m6, SECP256K1_N_C_0);
muladd(m5, SECP256K1_N_C_1);
sumadd(m4);
- uint64_t p2; extract(p2);
+ extract(p2);
sumadd_fast(m3);
muladd_fast(m6, SECP256K1_N_C_1);
sumadd_fast(m5);
- uint64_t p3; extract_fast(p3);
- uint32_t p4 = c0 + m6;
+ extract_fast(p3);
+ p4 = c0 + m6;
VERIFY_CHECK(p4 <= 2);
/* Reduce 258 bits into 256. */
/* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */
- uint128_t c = p0 + (uint128_t)SECP256K1_N_C_0 * p4;
+ c = p0 + (uint128_t)SECP256K1_N_C_0 * p4;
r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
c += p1 + (uint128_t)SECP256K1_N_C_1 * p4;
r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
@@ -312,12 +553,146 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l
r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
c += p3;
r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
+#endif
/* Final reduction of r. */
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+#ifdef USE_ASM_X86_64
+ const uint64_t *pb = b->d;
+ __asm__ __volatile__(
+ /* Preload */
+ "movq 0(%%rdi), %%r15\n"
+ "movq 8(%%rdi), %%rbx\n"
+ "movq 16(%%rdi), %%rcx\n"
+ "movq 0(%%rdx), %%r11\n"
+ "movq 8(%%rdx), %%r12\n"
+ "movq 16(%%rdx), %%r13\n"
+ "movq 24(%%rdx), %%r14\n"
+ /* (rax,rdx) = a0 * b0 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r11\n"
+ /* Extract l0 */
+ "movq %%rax, 0(%%rsi)\n"
+ /* (r8,r9,r10) = (rdx) */
+ "movq %%rdx, %%r8\n"
+ "xorq %%r9, %%r9\n"
+ "xorq %%r10, %%r10\n"
+ /* (r8,r9,r10) += a0 * b1 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += a1 * b0 */
+ "movq %%rbx, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* Extract l1 */
+ "movq %%r8, 8(%%rsi)\n"
+ "xorq %%r8, %%r8\n"
+ /* (r9,r10,r8) += a0 * b2 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += a1 * b1 */
+ "movq %%rbx, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += a2 * b0 */
+ "movq %%rcx, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* Extract l2 */
+ "movq %%r9, 16(%%rsi)\n"
+ "xorq %%r9, %%r9\n"
+ /* (r10,r8,r9) += a0 * b3 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* Preload a3 */
+ "movq 24(%%rdi), %%r15\n"
+ /* (r10,r8,r9) += a1 * b2 */
+ "movq %%rbx, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += a2 * b1 */
+ "movq %%rcx, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += a3 * b0 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r11\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* Extract l3 */
+ "movq %%r10, 24(%%rsi)\n"
+ "xorq %%r10, %%r10\n"
+ /* (r8,r9,r10) += a1 * b3 */
+ "movq %%rbx, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += a2 * b2 */
+ "movq %%rcx, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += a3 * b1 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* Extract l4 */
+ "movq %%r8, 32(%%rsi)\n"
+ "xorq %%r8, %%r8\n"
+ /* (r9,r10,r8) += a2 * b3 */
+ "movq %%rcx, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += a3 * b2 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* Extract l5 */
+ "movq %%r9, 40(%%rsi)\n"
+ /* (r10,r8) += a3 * b3 */
+ "movq %%r15, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ /* Extract l6 */
+ "movq %%r10, 48(%%rsi)\n"
+ /* Extract l7 */
+ "movq %%r8, 56(%%rsi)\n"
+ : "+d"(pb)
+ : "S"(l), "D"(a->d)
+ : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory");
+#else
/* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0;
@@ -348,9 +723,119 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a,
extract_fast(l[6]);
VERIFY_CHECK(c1 <= 0);
l[7] = c0;
+#endif
}
static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) {
+#ifdef USE_ASM_X86_64
+ __asm__ __volatile__(
+ /* Preload */
+ "movq 0(%%rdi), %%r11\n"
+ "movq 8(%%rdi), %%r12\n"
+ "movq 16(%%rdi), %%r13\n"
+ "movq 24(%%rdi), %%r14\n"
+ /* (rax,rdx) = a0 * a0 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r11\n"
+ /* Extract l0 */
+ "movq %%rax, 0(%%rsi)\n"
+ /* (r8,r9,r10) = (rdx,0) */
+ "movq %%rdx, %%r8\n"
+ "xorq %%r9, %%r9\n"
+ "xorq %%r10, %%r10\n"
+ /* (r8,r9,r10) += 2 * a0 * a1 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* Extract l1 */
+ "movq %%r8, 8(%%rsi)\n"
+ "xorq %%r8, %%r8\n"
+ /* (r9,r10,r8) += 2 * a0 * a2 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += a1 * a1 */
+ "movq %%r12, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* Extract l2 */
+ "movq %%r9, 16(%%rsi)\n"
+ "xorq %%r9, %%r9\n"
+ /* (r10,r8,r9) += 2 * a0 * a3 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += 2 * a1 * a2 */
+ "movq %%r12, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* Extract l3 */
+ "movq %%r10, 24(%%rsi)\n"
+ "xorq %%r10, %%r10\n"
+ /* (r8,r9,r10) += 2 * a1 * a3 */
+ "movq %%r12, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += a2 * a2 */
+ "movq %%r13, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* Extract l4 */
+ "movq %%r8, 32(%%rsi)\n"
+ "xorq %%r8, %%r8\n"
+ /* (r9,r10,r8) += 2 * a2 * a3 */
+ "movq %%r13, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* Extract l5 */
+ "movq %%r9, 40(%%rsi)\n"
+ /* (r10,r8) += a3 * a3 */
+ "movq %%r14, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ /* Extract l6 */
+ "movq %%r10, 48(%%rsi)\n"
+ /* Extract l7 */
+ "movq %%r8, 56(%%rsi)\n"
+ :
+ : "S"(l), "D"(a->d)
+ : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory");
+#else
/* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0;
@@ -375,6 +860,7 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a)
extract_fast(l[6]);
VERIFY_CHECK(c1 == 0);
l[7] = c0;
+#endif
}
#undef sumadd
@@ -413,12 +899,15 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, con
}
SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
- VERIFY_CHECK(shift >= 256);
uint64_t l[8];
+ unsigned int shiftlimbs;
+ unsigned int shiftlow;
+ unsigned int shifthigh;
+ VERIFY_CHECK(shift >= 256);
secp256k1_scalar_mul_512(l, a, b);
- unsigned int shiftlimbs = shift >> 6;
- unsigned int shiftlow = shift & 0x3F;
- unsigned int shifthigh = 64 - shiftlow;
+ shiftlimbs = shift >> 6;
+ shiftlow = shift & 0x3F;
+ shifthigh = 64 - shiftlow;
r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h
index f70328cfc9..f17017e24e 100644
--- a/src/secp256k1/src/scalar_8x32.h
+++ b/src/secp256k1/src/scalar_8x32.h
@@ -14,4 +14,6 @@ typedef struct {
uint32_t d[8];
} secp256k1_scalar_t;
+#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}
+
#endif
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index 915cbcddbe..22b31d4112 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -91,8 +91,9 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
}
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) {
+ uint64_t t;
VERIFY_CHECK(overflow <= 1);
- uint64_t t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0;
+ t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0;
r->d[0] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1;
r->d[1] = t & 0xFFFFFFFFUL; t >>= 32;
@@ -112,6 +113,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3
}
static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+ int overflow;
uint64_t t = (uint64_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[1] + b->d[1];
@@ -128,15 +130,16 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[7] + b->d[7];
r->d[7] = t & 0xFFFFFFFFULL; t >>= 32;
- int overflow = t + secp256k1_scalar_check_overflow(r);
+ overflow = t + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
+ uint64_t t;
VERIFY_CHECK(bit < 256);
- uint64_t t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
+ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;
@@ -159,6 +162,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
}
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
+ int over;
r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;
r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;
r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24;
@@ -167,7 +171,7 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char
r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24;
r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24;
r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24;
- int over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
+ over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
}
@@ -263,16 +267,16 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd2(a,b) { \
- uint32_t tl, th; \
+ uint32_t tl, th, th2, tl2; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
- uint32_t th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
+ th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
- uint32_t tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
+ tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \
@@ -285,8 +289,9 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
+ unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
- unsigned int over = (c0 < (a)) ? 1 : 0; \
+ over = (c0 < (a)) ? 1 : 0; \
c1 += over; /* overflow is handled on the next line */ \
c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \
}
@@ -316,7 +321,10 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
}
static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) {
+ uint64_t c;
uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15];
+ uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12;
+ uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8;
/* 96 bit accumulator. */
uint32_t c0, c1, c2;
@@ -325,115 +333,115 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l
/* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */
c0 = l[0]; c1 = 0; c2 = 0;
muladd_fast(n0, SECP256K1_N_C_0);
- uint32_t m0; extract_fast(m0);
+ extract_fast(m0);
sumadd_fast(l[1]);
muladd(n1, SECP256K1_N_C_0);
muladd(n0, SECP256K1_N_C_1);
- uint32_t m1; extract(m1);
+ extract(m1);
sumadd(l[2]);
muladd(n2, SECP256K1_N_C_0);
muladd(n1, SECP256K1_N_C_1);
muladd(n0, SECP256K1_N_C_2);
- uint32_t m2; extract(m2);
+ extract(m2);
sumadd(l[3]);
muladd(n3, SECP256K1_N_C_0);
muladd(n2, SECP256K1_N_C_1);
muladd(n1, SECP256K1_N_C_2);
muladd(n0, SECP256K1_N_C_3);
- uint32_t m3; extract(m3);
+ extract(m3);
sumadd(l[4]);
muladd(n4, SECP256K1_N_C_0);
muladd(n3, SECP256K1_N_C_1);
muladd(n2, SECP256K1_N_C_2);
muladd(n1, SECP256K1_N_C_3);
sumadd(n0);
- uint32_t m4; extract(m4);
+ extract(m4);
sumadd(l[5]);
muladd(n5, SECP256K1_N_C_0);
muladd(n4, SECP256K1_N_C_1);
muladd(n3, SECP256K1_N_C_2);
muladd(n2, SECP256K1_N_C_3);
sumadd(n1);
- uint32_t m5; extract(m5);
+ extract(m5);
sumadd(l[6]);
muladd(n6, SECP256K1_N_C_0);
muladd(n5, SECP256K1_N_C_1);
muladd(n4, SECP256K1_N_C_2);
muladd(n3, SECP256K1_N_C_3);
sumadd(n2);
- uint32_t m6; extract(m6);
+ extract(m6);
sumadd(l[7]);
muladd(n7, SECP256K1_N_C_0);
muladd(n6, SECP256K1_N_C_1);
muladd(n5, SECP256K1_N_C_2);
muladd(n4, SECP256K1_N_C_3);
sumadd(n3);
- uint32_t m7; extract(m7);
+ extract(m7);
muladd(n7, SECP256K1_N_C_1);
muladd(n6, SECP256K1_N_C_2);
muladd(n5, SECP256K1_N_C_3);
sumadd(n4);
- uint32_t m8; extract(m8);
+ extract(m8);
muladd(n7, SECP256K1_N_C_2);
muladd(n6, SECP256K1_N_C_3);
sumadd(n5);
- uint32_t m9; extract(m9);
+ extract(m9);
muladd(n7, SECP256K1_N_C_3);
sumadd(n6);
- uint32_t m10; extract(m10);
+ extract(m10);
sumadd_fast(n7);
- uint32_t m11; extract_fast(m11);
+ extract_fast(m11);
VERIFY_CHECK(c0 <= 1);
- uint32_t m12 = c0;
+ m12 = c0;
/* Reduce 385 bits into 258. */
/* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */
c0 = m0; c1 = 0; c2 = 0;
muladd_fast(m8, SECP256K1_N_C_0);
- uint32_t p0; extract_fast(p0);
+ extract_fast(p0);
sumadd_fast(m1);
muladd(m9, SECP256K1_N_C_0);
muladd(m8, SECP256K1_N_C_1);
- uint32_t p1; extract(p1);
+ extract(p1);
sumadd(m2);
muladd(m10, SECP256K1_N_C_0);
muladd(m9, SECP256K1_N_C_1);
muladd(m8, SECP256K1_N_C_2);
- uint32_t p2; extract(p2);
+ extract(p2);
sumadd(m3);
muladd(m11, SECP256K1_N_C_0);
muladd(m10, SECP256K1_N_C_1);
muladd(m9, SECP256K1_N_C_2);
muladd(m8, SECP256K1_N_C_3);
- uint32_t p3; extract(p3);
+ extract(p3);
sumadd(m4);
muladd(m12, SECP256K1_N_C_0);
muladd(m11, SECP256K1_N_C_1);
muladd(m10, SECP256K1_N_C_2);
muladd(m9, SECP256K1_N_C_3);
sumadd(m8);
- uint32_t p4; extract(p4);
+ extract(p4);
sumadd(m5);
muladd(m12, SECP256K1_N_C_1);
muladd(m11, SECP256K1_N_C_2);
muladd(m10, SECP256K1_N_C_3);
sumadd(m9);
- uint32_t p5; extract(p5);
+ extract(p5);
sumadd(m6);
muladd(m12, SECP256K1_N_C_2);
muladd(m11, SECP256K1_N_C_3);
sumadd(m10);
- uint32_t p6; extract(p6);
+ extract(p6);
sumadd_fast(m7);
muladd_fast(m12, SECP256K1_N_C_3);
sumadd_fast(m11);
- uint32_t p7; extract_fast(p7);
- uint32_t p8 = c0 + m12;
+ extract_fast(p7);
+ p8 = c0 + m12;
VERIFY_CHECK(p8 <= 2);
/* Reduce 258 bits into 256. */
/* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */
- uint64_t c = p0 + (uint64_t)SECP256K1_N_C_0 * p8;
+ c = p0 + (uint64_t)SECP256K1_N_C_0 * p8;
r->d[0] = c & 0xFFFFFFFFUL; c >>= 32;
c += p1 + (uint64_t)SECP256K1_N_C_1 * p8;
r->d[1] = c & 0xFFFFFFFFUL; c >>= 32;
@@ -454,7 +462,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
-static void secp256k1_scalar_mul_512(uint32_t l[16], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
+static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
@@ -542,7 +550,7 @@ static void secp256k1_scalar_mul_512(uint32_t l[16], const secp256k1_scalar_t *a
l[15] = c0;
}
-static void secp256k1_scalar_sqr_512(uint32_t l[16], const secp256k1_scalar_t *a) {
+static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
@@ -622,6 +630,7 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
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) {
r1->d[0] = a->d[0];
r1->d[1] = a->d[1];
@@ -640,18 +649,22 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_
r2->d[6] = 0;
r2->d[7] = 0;
}
+#endif
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
}
SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
- VERIFY_CHECK(shift >= 256);
uint32_t l[16];
+ unsigned int shiftlimbs;
+ unsigned int shiftlow;
+ unsigned int shifthigh;
+ VERIFY_CHECK(shift >= 256);
secp256k1_scalar_mul_512(l, a, b);
- unsigned int shiftlimbs = shift >> 5;
- unsigned int shiftlow = shift & 0x1F;
- unsigned int shifthigh = 32 - shiftlow;
+ shiftlimbs = shift >> 5;
+ shiftlow = shift & 0x1F;
+ shifthigh = 32 - shiftlow;
r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 4408cce2d8..3acbe264ae 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -24,121 +24,6 @@
#error "Please select scalar implementation"
#endif
-typedef struct {
-#ifndef USE_NUM_NONE
- secp256k1_num_t order;
-#endif
-#ifdef USE_ENDOMORPHISM
- secp256k1_scalar_t minus_lambda, minus_b1, minus_b2, g1, g2;
-#endif
-} secp256k1_scalar_consts_t;
-
-static const secp256k1_scalar_consts_t *secp256k1_scalar_consts = NULL;
-
-static void secp256k1_scalar_start(void) {
- if (secp256k1_scalar_consts != NULL)
- return;
-
- /* Allocate. */
- secp256k1_scalar_consts_t *ret = (secp256k1_scalar_consts_t*)checked_malloc(sizeof(secp256k1_scalar_consts_t));
-
-#ifndef USE_NUM_NONE
- static const unsigned char secp256k1_scalar_consts_order[] = {
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
- 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
- 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
- };
- secp256k1_num_set_bin(&ret->order, secp256k1_scalar_consts_order, sizeof(secp256k1_scalar_consts_order));
-#endif
-#ifdef USE_ENDOMORPHISM
- /**
- * Lambda is a scalar which has the property for secp256k1 that point multiplication by
- * it is efficiently computable (see secp256k1_gej_mul_lambda). */
- static const unsigned char secp256k1_scalar_consts_lambda[32] = {
- 0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
- 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
- 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
- 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72
- };
- /**
- * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm
- * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1
- * and k2 have a small size.
- * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are:
- *
- * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
- * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}
- * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}
- * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
- *
- * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives
- * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and
- * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2.
- *
- * g1, g2 are precomputed constants used to replace division with a rounded multiplication
- * when decomposing the scalar for an endomorphism-based point multiplication.
- *
- * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
- * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
- *
- * The derivation is described in the paper "Efficient Software Implementation of Public-Key
- * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
- * Section 4.3 (here we use a somewhat higher-precision estimate):
- * d = a1*b2 - b1*a2
- * g1 = round((2^272)*b2/d)
- * g2 = round((2^272)*b1/d)
- *
- * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
- * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
- */
- static const unsigned char secp256k1_scalar_consts_minus_b1[32] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
- 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
- };
- static const unsigned char secp256k1_scalar_consts_b2[32] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
- 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
- };
- static const unsigned char secp256k1_scalar_consts_g1[32] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x86,
- 0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,
- 0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab
- };
- static const unsigned char secp256k1_scalar_consts_g2[32] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x43,
- 0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,
- 0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12
- };
-
- secp256k1_scalar_set_b32(&ret->minus_lambda, secp256k1_scalar_consts_lambda, NULL);
- secp256k1_scalar_negate(&ret->minus_lambda, &ret->minus_lambda);
- secp256k1_scalar_set_b32(&ret->minus_b1, secp256k1_scalar_consts_minus_b1, NULL);
- secp256k1_scalar_set_b32(&ret->minus_b2, secp256k1_scalar_consts_b2, NULL);
- secp256k1_scalar_negate(&ret->minus_b2, &ret->minus_b2);
- secp256k1_scalar_set_b32(&ret->g1, secp256k1_scalar_consts_g1, NULL);
- secp256k1_scalar_set_b32(&ret->g2, secp256k1_scalar_consts_g2, NULL);
-#endif
-
- /* Set the global pointer. */
- secp256k1_scalar_consts = ret;
-}
-
-static void secp256k1_scalar_stop(void) {
- if (secp256k1_scalar_consts == NULL)
- return;
-
- secp256k1_scalar_consts_t *c = (secp256k1_scalar_consts_t*)secp256k1_scalar_consts;
- secp256k1_scalar_consts = NULL;
- free(c);
-}
-
#ifndef USE_NUM_NONE
static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) {
unsigned char c[32];
@@ -146,12 +31,21 @@ static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_
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) {
- *r = secp256k1_scalar_consts->order;
+ static const unsigned char order[32] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
+ 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
+ };
+ secp256k1_num_set_bin(r, order, 32);
}
#endif
static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
+ secp256k1_scalar_t *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;
@@ -175,129 +69,129 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal
secp256k1_scalar_mul(&x8, &x8, x);
secp256k1_scalar_sqr(&x15, &x8);
- for (int i=0; i<6; i++)
+ for (i = 0; i < 6; i++)
secp256k1_scalar_sqr(&x15, &x15);
secp256k1_scalar_mul(&x15, &x15, &x7);
secp256k1_scalar_sqr(&x30, &x15);
- for (int i=0; i<14; i++)
+ for (i = 0; i < 14; i++)
secp256k1_scalar_sqr(&x30, &x30);
secp256k1_scalar_mul(&x30, &x30, &x15);
secp256k1_scalar_sqr(&x60, &x30);
- for (int i=0; i<29; i++)
+ for (i = 0; i < 29; i++)
secp256k1_scalar_sqr(&x60, &x60);
secp256k1_scalar_mul(&x60, &x60, &x30);
secp256k1_scalar_sqr(&x120, &x60);
- for (int i=0; i<59; i++)
+ for (i = 0; i < 59; i++)
secp256k1_scalar_sqr(&x120, &x120);
secp256k1_scalar_mul(&x120, &x120, &x60);
secp256k1_scalar_sqr(&x127, &x120);
- for (int i=0; i<6; i++)
+ for (i = 0; i < 6; i++)
secp256k1_scalar_sqr(&x127, &x127);
secp256k1_scalar_mul(&x127, &x127, &x7);
/* Then accumulate the final result (t starts at x127). */
- secp256k1_scalar_t *t = &x127;
- for (int i=0; i<2; i++) /* 0 */
+ t = &x127;
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<4; i++) /* 0 */
+ for (i = 0; i < 4; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<4; i++) /* 0 */
+ for (i = 0; i < 4; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (int i=0; i<3; i++) /* 0 */
+ for (i = 0; i < 3; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (int i=0; i<4; i++) /* 0 */
+ for (i = 0; i < 4; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (int i=0; i<5; i++) /* 00 */
+ for (i = 0; i < 5; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (int i=0; i<4; i++) /* 00 */
+ for (i = 0; i < 4; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<5; i++) /* 0 */
+ for (i = 0; i < 5; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x4); /* 1111 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<3; i++) /* 00 */
+ for (i = 0; i < 3; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<4; i++) /* 000 */
+ for (i = 0; i < 4; i++) /* 000 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<10; i++) /* 0000000 */
+ for (i = 0; i < 10; i++) /* 0000000 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (int i=0; i<4; i++) /* 0 */
+ for (i = 0; i < 4; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (int i=0; i<9; i++) /* 0 */
+ for (i = 0; i < 9; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x8); /* 11111111 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<3; i++) /* 00 */
+ for (i = 0; i < 3; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<3; i++) /* 00 */
+ for (i = 0; i < 3; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<5; i++) /* 0 */
+ for (i = 0; i < 5; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x4); /* 1111 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<5; i++) /* 000 */
+ for (i = 0; i < 5; i++) /* 000 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (int i=0; i<4; i++) /* 00 */
+ for (i = 0; i < 4; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (int i=0; i<2; i++) /* 0 */
+ for (i = 0; i < 2; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<8; i++) /* 000000 */
+ for (i = 0; i < 8; i++) /* 000000 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (int i=0; i<3; i++) /* 0 */
+ for (i = 0; i < 3; i++) /* 0 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (int i=0; i<3; i++) /* 00 */
+ for (i = 0; i < 3; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<6; i++) /* 00000 */
+ for (i = 0; i < 6; i++) /* 00000 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(t, t, x); /* 1 */
- for (int i=0; i<8; i++) /* 00 */
+ for (i = 0; i < 8; i++) /* 00 */
secp256k1_scalar_sqr(t, t);
secp256k1_scalar_mul(r, t, &x6); /* 111111 */
}
@@ -307,10 +201,11 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_
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_t n;
secp256k1_num_set_bin(&n, b, 32);
- secp256k1_num_mod_inverse(&n, &n, &secp256k1_scalar_consts->order);
+ secp256k1_scalar_order_get_num(&m);
+ secp256k1_num_mod_inverse(&n, &n, &m);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_scalar_set_b32(r, b, NULL);
#else
@@ -319,16 +214,74 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_
}
#ifdef USE_ENDOMORPHISM
+/**
+ * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where
+ * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
+ * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72}
+ *
+ * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm
+ * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1
+ * and k2 have a small size.
+ * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are:
+ *
+ * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
+ * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}
+ * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}
+ * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
+ *
+ * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives
+ * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and
+ * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2.
+ *
+ * g1, g2 are precomputed constants used to replace division with a rounded multiplication
+ * when decomposing the scalar for an endomorphism-based point multiplication.
+ *
+ * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
+ * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
+ *
+ * The derivation is described in the paper "Efficient Software Implementation of Public-Key
+ * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
+ * Section 4.3 (here we use a somewhat higher-precision estimate):
+ * d = a1*b2 - b1*a2
+ * g1 = round((2^272)*b2/d)
+ * g2 = round((2^272)*b1/d)
+ *
+ * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
+ * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
+ *
+ * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order).
+ */
+
static void secp256k1_scalar_split_lambda_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(
+ 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL,
+ 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL
+ );
+ static const secp256k1_scalar_t minus_b1 = SECP256K1_SCALAR_CONST(
+ 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL,
+ 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL
+ );
+ static const secp256k1_scalar_t minus_b2 = SECP256K1_SCALAR_CONST(
+ 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
+ 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL
+ );
+ static const secp256k1_scalar_t g1 = SECP256K1_SCALAR_CONST(
+ 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL,
+ 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL
+ );
+ static const secp256k1_scalar_t g2 = SECP256K1_SCALAR_CONST(
+ 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL,
+ 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL
+ );
VERIFY_CHECK(r1 != a);
VERIFY_CHECK(r2 != a);
- secp256k1_scalar_t c1, c2;
- secp256k1_scalar_mul_shift_var(&c1, a, &secp256k1_scalar_consts->g1, 272);
- secp256k1_scalar_mul_shift_var(&c2, a, &secp256k1_scalar_consts->g2, 272);
- secp256k1_scalar_mul(&c1, &c1, &secp256k1_scalar_consts->minus_b1);
- secp256k1_scalar_mul(&c2, &c2, &secp256k1_scalar_consts->minus_b2);
+ secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272);
+ secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272);
+ secp256k1_scalar_mul(&c1, &c1, &minus_b1);
+ secp256k1_scalar_mul(&c2, &c2, &minus_b2);
secp256k1_scalar_add(r2, &c1, &c2);
- secp256k1_scalar_mul(r1, r2, &secp256k1_scalar_consts->minus_lambda);
+ secp256k1_scalar_mul(r1, r2, &minus_lambda);
secp256k1_scalar_add(r1, r1, a);
}
#endif
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 58bcd8d009..8c4eca4b62 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -20,10 +20,6 @@
#include "hash_impl.h"
void secp256k1_start(unsigned int flags) {
- secp256k1_fe_start();
- secp256k1_ge_start();
- secp256k1_scalar_start();
- secp256k1_ecdsa_start();
if (flags & SECP256K1_START_SIGN) {
secp256k1_ecmult_gen_start();
}
@@ -35,46 +31,43 @@ void secp256k1_start(unsigned int flags) {
void secp256k1_stop(void) {
secp256k1_ecmult_stop();
secp256k1_ecmult_gen_stop();
- secp256k1_ecdsa_stop();
- secp256k1_scalar_stop();
- secp256k1_ge_stop();
- secp256k1_fe_stop();
}
int secp256k1_ecdsa_verify(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(secp256k1_ecmult_consts != NULL);
DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(sig != NULL);
DEBUG_CHECK(pubkey != NULL);
- int ret = -3;
- secp256k1_scalar_t m;
- secp256k1_ecdsa_sig_t s;
- secp256k1_ge_t q;
secp256k1_scalar_set_b32(&m, msg32, NULL);
- if (!secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) {
+ if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) {
+ if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
+ if (secp256k1_ecdsa_sig_verify(&s, &q, &m)) {
+ /* success is 1, all other values are fail */
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ } else {
+ ret = -2;
+ }
+ } else {
ret = -1;
- goto end;
- }
- if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
- ret = -2;
- goto end;
}
- if (!secp256k1_ecdsa_sig_verify(&s, &q, &m)) {
- ret = 0;
- goto end;
- }
- ret = 1;
-end:
+
return ret;
}
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
- (void)data;
secp256k1_rfc6979_hmac_sha256_t rng;
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32);
- for (unsigned int i = 0; i <= counter; i++) {
+ unsigned int i;
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, 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);
@@ -85,6 +78,11 @@ const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_functi
const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979;
int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_scalar_t sec, non, msg;
+ int ret = 0;
+ int overflow = 0;
+ unsigned int count = 0;
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(signature != NULL);
@@ -94,38 +92,44 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i
noncefp = secp256k1_nonce_function_default;
}
- secp256k1_scalar_t sec, non, msg;
- secp256k1_scalar_set_b32(&sec, seckey, NULL);
- secp256k1_scalar_set_b32(&msg, msg32, NULL);
- int overflow = 0;
- int ret = 0;
- unsigned int count = 0;
- secp256k1_ecdsa_sig_t sig;
- while (1) {
- unsigned char nonce32[32];
- ret = noncefp(nonce32, msg32, seckey, count, noncedata);
- if (!ret) {
- break;
- }
- secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- memset(nonce32, 0, 32);
- if (!secp256k1_scalar_is_zero(&non) && !overflow) {
- if (secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL)) {
+ 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(&sig, &sec, &msg, &non, NULL)) {
+ break;
+ }
+ }
+ count++;
+ }
+ if (ret) {
+ ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
}
- count++;
+ secp256k1_scalar_clear(&msg);
+ secp256k1_scalar_clear(&non);
+ secp256k1_scalar_clear(&sec);
}
- if (ret) {
- ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
+ if (!ret) {
+ *signaturelen = 0;
}
- secp256k1_scalar_clear(&msg);
- secp256k1_scalar_clear(&non);
- secp256k1_scalar_clear(&sec);
return ret;
}
int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) {
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_scalar_t sec, non, msg;
+ int ret = 0;
+ int overflow = 0;
+ unsigned int count = 0;
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(sig64 != NULL);
@@ -134,39 +138,45 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig6
noncefp = secp256k1_nonce_function_default;
}
- secp256k1_scalar_t sec, non, msg;
- secp256k1_scalar_set_b32(&sec, seckey, NULL);
- secp256k1_scalar_set_b32(&msg, msg32, NULL);
- int overflow = 0;
- int ret = 0;
- unsigned int count = 0;
- secp256k1_ecdsa_sig_t sig;
- while (1) {
- unsigned char nonce32[32];
- ret = noncefp(nonce32, msg32, seckey, count, noncedata);
- if (!ret) {
- break;
- }
- secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- memset(nonce32, 0, 32);
- if (!secp256k1_scalar_is_zero(&non) && !overflow) {
- if (secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid)) {
+ 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(&sig, &sec, &msg, &non, recid)) {
+ break;
+ }
+ }
+ count++;
+ }
+ if (ret) {
+ secp256k1_scalar_get_b32(sig64, &sig.r);
+ secp256k1_scalar_get_b32(sig64 + 32, &sig.s);
}
- count++;
+ secp256k1_scalar_clear(&msg);
+ secp256k1_scalar_clear(&non);
+ secp256k1_scalar_clear(&sec);
}
- if (ret) {
- secp256k1_scalar_get_b32(sig64, &sig.r);
- secp256k1_scalar_get_b32(sig64 + 32, &sig.s);
+ if (!ret) {
+ memset(sig64, 0, 64);
}
- secp256k1_scalar_clear(&msg);
- secp256k1_scalar_clear(&non);
- secp256k1_scalar_clear(&sec);
return ret;
}
int secp256k1_ecdsa_recover_compact(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(secp256k1_ecmult_consts != NULL);
DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(sig64 != NULL);
@@ -174,82 +184,87 @@ int secp256k1_ecdsa_recover_compact(const unsigned char *msg32, const unsigned c
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(recid >= 0 && recid <= 3);
- int ret = 0;
- secp256k1_scalar_t m;
- secp256k1_ecdsa_sig_t sig;
- int overflow = 0;
secp256k1_scalar_set_b32(&sig.r, sig64, &overflow);
- if (overflow) {
- return 0;
- }
- secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow);
- if (overflow) {
- return 0;
- }
- secp256k1_scalar_set_b32(&m, msg32, NULL);
+ if (!overflow) {
+ secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow);
+ if (!overflow) {
+ secp256k1_scalar_set_b32(&m, msg32, NULL);
- secp256k1_ge_t q;
- if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
- ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
+ if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
+ ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
+ }
+ }
}
return ret;
}
int secp256k1_ec_seckey_verify(const unsigned char *seckey) {
- DEBUG_CHECK(seckey != NULL);
-
secp256k1_scalar_t sec;
+ int ret;
int overflow;
+ DEBUG_CHECK(seckey != NULL);
+
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
- int ret = !secp256k1_scalar_is_zero(&sec) && !overflow;
+ ret = !secp256k1_scalar_is_zero(&sec) && !overflow;
secp256k1_scalar_clear(&sec);
return ret;
}
int secp256k1_ec_pubkey_verify(const unsigned char *pubkey, int pubkeylen) {
+ secp256k1_ge_t q;
DEBUG_CHECK(pubkey != NULL);
- secp256k1_ge_t q;
return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen);
}
int secp256k1_ec_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
+ secp256k1_gej_t pj;
+ secp256k1_ge_t p;
+ secp256k1_scalar_t sec;
+ int overflow;
+ int ret = 0;
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(seckey != NULL);
- secp256k1_scalar_t sec;
- secp256k1_scalar_set_b32(&sec, seckey, NULL);
- secp256k1_gej_t pj;
- secp256k1_ecmult_gen(&pj, &sec);
- secp256k1_scalar_clear(&sec);
- secp256k1_ge_t p;
- secp256k1_ge_set_gej(&p, &pj);
- return secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
+ secp256k1_scalar_set_b32(&sec, seckey, &overflow);
+ if (!overflow) {
+ secp256k1_ecmult_gen(&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(unsigned char *pubkey, int *pubkeylen) {
+ secp256k1_ge_t p;
+ int ret = 0;
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
- secp256k1_ge_t p;
- if (!secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen))
- return 0;
- return secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0);
+ if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) {
+ ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0);
+ }
+ return ret;
}
int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) {
+ secp256k1_scalar_t term;
+ secp256k1_scalar_t sec;
+ int ret = 0;
+ int overflow = 0;
DEBUG_CHECK(seckey != NULL);
DEBUG_CHECK(tweak != NULL);
- secp256k1_scalar_t term;
- int overflow = 0;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
- secp256k1_scalar_t sec;
secp256k1_scalar_set_b32(&sec, seckey, NULL);
- int ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow;
+ ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow;
if (ret) {
secp256k1_scalar_get_b32(seckey, &sec);
}
@@ -260,40 +275,41 @@ int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *t
}
int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
+ secp256k1_ge_t p;
+ secp256k1_scalar_t term;
+ int ret = 0;
+ int overflow = 0;
DEBUG_CHECK(secp256k1_ecmult_consts != NULL);
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(tweak != NULL);
- secp256k1_scalar_t term;
- int overflow = 0;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
- if (overflow) {
- return 0;
- }
- secp256k1_ge_t p;
- int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
- if (ret) {
- ret = secp256k1_eckey_pubkey_tweak_add(&p, &term);
- }
- if (ret) {
- int oldlen = pubkeylen;
- ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
- VERIFY_CHECK(pubkeylen == oldlen);
+ if (!overflow) {
+ ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
+ if (ret) {
+ ret = secp256k1_eckey_pubkey_tweak_add(&p, &term);
+ }
+ if (ret) {
+ int oldlen = pubkeylen;
+ ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
+ VERIFY_CHECK(pubkeylen == oldlen);
+ }
}
return ret;
}
int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) {
+ secp256k1_scalar_t factor;
+ secp256k1_scalar_t sec;
+ int ret = 0;
+ int overflow = 0;
DEBUG_CHECK(seckey != NULL);
DEBUG_CHECK(tweak != NULL);
- secp256k1_scalar_t factor;
- int overflow = 0;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
- secp256k1_scalar_t sec;
secp256k1_scalar_set_b32(&sec, seckey, NULL);
- int ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow;
+ ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow;
if (ret) {
secp256k1_scalar_get_b32(seckey, &sec);
}
@@ -304,50 +320,53 @@ int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *t
}
int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
+ secp256k1_ge_t p;
+ secp256k1_scalar_t factor;
+ int ret = 0;
+ int overflow = 0;
DEBUG_CHECK(secp256k1_ecmult_consts != NULL);
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(tweak != NULL);
- secp256k1_scalar_t factor;
- int overflow = 0;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
- if (overflow) {
- return 0;
- }
- secp256k1_ge_t p;
- int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
- if (ret) {
- ret = secp256k1_eckey_pubkey_tweak_mul(&p, &factor);
- }
- if (ret) {
- int oldlen = pubkeylen;
- ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
- VERIFY_CHECK(pubkeylen == oldlen);
+ if (!overflow) {
+ ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
+ if (ret) {
+ ret = secp256k1_eckey_pubkey_tweak_mul(&p, &factor);
+ }
+ if (ret) {
+ int oldlen = pubkeylen;
+ ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
+ VERIFY_CHECK(pubkeylen == oldlen);
+ }
}
return ret;
}
int secp256k1_ec_privkey_export(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);
- secp256k1_scalar_t key;
secp256k1_scalar_set_b32(&key, seckey, NULL);
- int ret = secp256k1_eckey_privkey_serialize(privkey, privkeylen, &key, compressed);
+ ret = secp256k1_eckey_privkey_serialize(privkey, privkeylen, &key, compressed);
secp256k1_scalar_clear(&key);
return ret;
}
int secp256k1_ec_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) {
+ secp256k1_scalar_t key;
+ int ret = 0;
DEBUG_CHECK(seckey != NULL);
DEBUG_CHECK(privkey != NULL);
- secp256k1_scalar_t key;
- int ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen);
- if (ret)
+ ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen);
+ if (ret) {
secp256k1_scalar_get_b32(seckey, &key);
+ }
secp256k1_scalar_clear(&key);
return ret;
}
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index 018b65cd53..041bb92c47 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -11,8 +11,10 @@
#include "libsecp256k1-config.h"
#endif
-/** Seed the pseudorandom number generator. */
-SECP256K1_INLINE static void secp256k1_rand_seed(uint64_t v);
+/* A non-cryptographic RNG used only for test infrastructure. */
+
+/** Seed the pseudorandom number generator for testing. */
+SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16);
/** Generate a pseudorandom 32-bit number. */
static uint32_t secp256k1_rand32(void);
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index 677c4b9a0e..21c69f1c51 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -11,44 +11,44 @@
#include <string.h>
#include "testrand.h"
+#include "hash.h"
-static uint32_t secp256k1_Rz = 11, secp256k1_Rw = 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;
-SECP256K1_INLINE static void secp256k1_rand_seed(uint64_t v) {
- secp256k1_Rz = v >> 32;
- secp256k1_Rw = v;
-
- if (secp256k1_Rz == 0 || secp256k1_Rz == 0x9068ffffU) {
- secp256k1_Rz = 111;
- }
- if (secp256k1_Rw == 0 || secp256k1_Rw == 0x464fffffU) {
- secp256k1_Rw = 111;
- }
+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_INLINE static uint32_t secp256k1_rand32(void) {
- secp256k1_Rz = 36969 * (secp256k1_Rz & 0xFFFF) + (secp256k1_Rz >> 16);
- secp256k1_Rw = 18000 * (secp256k1_Rw & 0xFFFF) + (secp256k1_Rw >> 16);
- return (secp256k1_Rw << 16) + (secp256k1_Rw >> 16) + secp256k1_Rz;
+ if (secp256k1_test_rng_precomputed_used == 8) {
+ secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed));
+ secp256k1_test_rng_precomputed_used = 0;
+ }
+ return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++];
}
static void secp256k1_rand256(unsigned char *b32) {
- for (int i=0; i<8; i++) {
- uint32_t r = secp256k1_rand32();
- b32[i*4 + 0] = (r >> 0) & 0xFF;
- b32[i*4 + 1] = (r >> 8) & 0xFF;
- b32[i*4 + 2] = (r >> 16) & 0xFF;
- b32[i*4 + 3] = (r >> 24) & 0xFF;
- }
+ secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32);
}
static void secp256k1_rand256_test(unsigned char *b32) {
int bits=0;
+ uint64_t ent = 0;
+ int entleft = 0;
memset(b32, 0, 32);
while (bits < 256) {
- uint32_t ent = secp256k1_rand32();
- int now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31;
- uint32_t val = 1 & (ent >> 11);
+ 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--;
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index cff32f1d06..f7f1acac64 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -36,12 +36,12 @@ void random_field_element_test(secp256k1_fe_t *fe) {
}
void random_field_element_magnitude(secp256k1_fe_t *fe) {
+ secp256k1_fe_t zero;
int n = secp256k1_rand32() % 9;
secp256k1_fe_normalize(fe);
if (n == 0) {
return;
}
- secp256k1_fe_t zero;
secp256k1_fe_clear(&zero);
secp256k1_fe_negate(&zero, &zero, 0);
secp256k1_fe_mul_int(&zero, n - 1);
@@ -61,14 +61,15 @@ void random_group_element_test(secp256k1_ge_t *ge) {
}
void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) {
+ secp256k1_fe_t z2, z3;
do {
random_field_element_test(&gej->z);
if (!secp256k1_fe_is_zero(&gej->z)) {
break;
}
} while(1);
- secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &gej->z);
- secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &z2, &gej->z);
+ secp256k1_fe_sqr(&z2, &gej->z);
+ secp256k1_fe_mul(&z3, &z2, &gej->z);
secp256k1_fe_mul(&gej->x, &ge->x, &z2);
secp256k1_fe_mul(&gej->y, &ge->y, &z3);
gej->infinity = ge->infinity;
@@ -77,8 +78,8 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge
void random_scalar_order_test(secp256k1_scalar_t *num) {
do {
unsigned char b32[32];
- secp256k1_rand256_test(b32);
int overflow = 0;
+ secp256k1_rand256_test(b32);
secp256k1_scalar_set_b32(num, b32, &overflow);
if (overflow || secp256k1_scalar_is_zero(num))
continue;
@@ -89,8 +90,8 @@ void random_scalar_order_test(secp256k1_scalar_t *num) {
void random_scalar_order(secp256k1_scalar_t *num) {
do {
unsigned char b32[32];
- secp256k1_rand256(b32);
int overflow = 0;
+ secp256k1_rand256(b32);
secp256k1_scalar_set_b32(num, b32, &overflow);
if (overflow || secp256k1_scalar_is_zero(num))
continue;
@@ -117,16 +118,17 @@ void run_sha256_tests(void) {
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}
};
- for (int i = 0; i < 8; i++) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ unsigned char out[32];
secp256k1_sha256_t hasher;
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
- unsigned char out[32];
secp256k1_sha256_finalize(&hasher, out);
CHECK(memcmp(out, outputs[i], 32) == 0);
if (strlen(inputs[i]) > 0) {
- secp256k1_sha256_initialize(&hasher);
int split = secp256k1_rand32() % strlen(inputs[i]);
+ secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
secp256k1_sha256_finalize(&hasher, out);
@@ -160,16 +162,17 @@ void run_hmac_sha256_tests(void) {
{0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54},
{0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2}
};
- for (int i = 0; i < 6; i++) {
+ int i;
+ for (i = 0; i < 6; i++) {
secp256k1_hmac_sha256_t hasher;
+ unsigned char out[32];
secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
- unsigned char out[32];
secp256k1_hmac_sha256_finalize(&hasher, out);
CHECK(memcmp(out, outputs[i], 32) == 0);
if (strlen(inputs[i]) > 0) {
- secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
int split = secp256k1_rand32() % strlen(inputs[i]);
+ secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
secp256k1_hmac_sha256_finalize(&hasher, out);
@@ -197,16 +200,25 @@ 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);
- for (int i = 0; i < 3; i++) {
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1);
+ 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);
- for (int i = 0; i < 3; i++) {
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, zero, 1);
+ 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);
+ for (i = 0; i < 3; i++) {
secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
CHECK(memcmp(out, out2[i], 32) == 0);
}
@@ -254,9 +266,10 @@ void test_num_negate(void) {
}
void test_num_add_sub(void) {
- int r = secp256k1_rand32();
secp256k1_num_t n1;
secp256k1_num_t n2;
+ secp256k1_num_t n1p2, n2p1, n1m2, n2m1;
+ int r = secp256k1_rand32();
random_num_order_test(&n1); /* n1 = R1 */
if (r & 1) {
random_num_negate(&n1);
@@ -265,7 +278,6 @@ void test_num_add_sub(void) {
if (r & 2) {
random_num_negate(&n2);
}
- secp256k1_num_t n1p2, n2p1, n1m2, n2m1;
secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */
secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */
secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */
@@ -283,7 +295,8 @@ void test_num_add_sub(void) {
}
void run_num_smalltests(void) {
- for (int i=0; i<100*count; i++) {
+ int i;
+ for (i = 0; i < 100*count; i++) {
test_num_negate();
test_num_add_sub();
}
@@ -293,41 +306,45 @@ void run_num_smalltests(void) {
/***** SCALAR TESTS *****/
void scalar_test(void) {
+ secp256k1_scalar_t s;
+ secp256k1_scalar_t s1;
+ secp256k1_scalar_t s2;
+#ifndef USE_NUM_NONE
+ secp256k1_num_t snum, s1num, s2num;
+ secp256k1_num_t order, half_order;
+#endif
unsigned char c[32];
/* Set 's' to a random scalar, with value 'snum'. */
- secp256k1_scalar_t s;
random_scalar_order_test(&s);
/* Set 's1' to a random scalar, with value 's1num'. */
- secp256k1_scalar_t s1;
random_scalar_order_test(&s1);
/* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */
- secp256k1_scalar_t s2;
random_scalar_order_test(&s2);
secp256k1_scalar_get_b32(c, &s2);
#ifndef USE_NUM_NONE
- secp256k1_num_t snum, s1num, s2num;
secp256k1_scalar_get_num(&snum, &s);
secp256k1_scalar_get_num(&s1num, &s1);
secp256k1_scalar_get_num(&s2num, &s2);
- secp256k1_num_t order;
secp256k1_scalar_order_get_num(&order);
- secp256k1_num_t half_order = order;
+ half_order = order;
secp256k1_num_shift(&half_order, 1);
#endif
{
+ int i;
/* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */
secp256k1_scalar_t n;
secp256k1_scalar_set_int(&n, 0);
- for (int i = 0; i < 256; i += 4) {
+ for (i = 0; i < 256; i += 4) {
secp256k1_scalar_t t;
+ int j;
secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));
- for (int j = 0; j < 4; j++) {
+ for (j = 0; j < 4; j++) {
secp256k1_scalar_add(&n, &n, &n);
}
secp256k1_scalar_add(&n, &n, &t);
@@ -338,16 +355,17 @@ void scalar_test(void) {
{
/* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */
secp256k1_scalar_t n;
- secp256k1_scalar_set_int(&n, 0);
int i = 0;
+ secp256k1_scalar_set_int(&n, 0);
while (i < 256) {
+ secp256k1_scalar_t t;
+ int j;
int now = (secp256k1_rand32() % 15) + 1;
if (now + i > 256) {
now = 256 - i;
}
- secp256k1_scalar_t t;
secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now));
- for (int j = 0; j < now; j++) {
+ for (j = 0; j < now; j++) {
secp256k1_scalar_add(&n, &n, &n);
}
secp256k1_scalar_add(&n, &n, &t);
@@ -360,23 +378,23 @@ void scalar_test(void) {
{
/* 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_add(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &order);
- secp256k1_scalar_t r;
secp256k1_scalar_add(&r, &s, &s2);
- secp256k1_num_t r2num;
secp256k1_scalar_get_num(&r2num, &r);
CHECK(secp256k1_num_eq(&rnum, &r2num));
}
{
/* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */
+ secp256k1_scalar_t r;
+ secp256k1_num_t r2num;
secp256k1_num_t rnum;
secp256k1_num_mul(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &order);
- secp256k1_scalar_t r;
secp256k1_scalar_mul(&r, &s, &s2);
- secp256k1_num_t r2num;
secp256k1_scalar_get_num(&r2num, &r);
CHECK(secp256k1_num_eq(&rnum, &r2num));
/* The result can only be zero if at least one of the factors was zero. */
@@ -387,20 +405,20 @@ void scalar_test(void) {
}
{
+ secp256k1_scalar_t neg;
+ secp256k1_num_t negnum;
+ secp256k1_num_t negnum2;
/* Check that comparison with zero matches comparison with zero on the number. */
CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s));
/* Check that comparison with the half order is equal to testing for high scalar. */
CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0));
- secp256k1_scalar_t neg;
secp256k1_scalar_negate(&neg, &s);
- secp256k1_num_t negnum;
secp256k1_num_sub(&negnum, &order, &snum);
secp256k1_num_mod(&negnum, &order);
/* Check that comparison with the half order is equal to testing for high scalar after negation. */
CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0));
/* Negating should change the high property, unless the value was already zero. */
CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s));
- secp256k1_num_t negnum2;
secp256k1_scalar_get_num(&negnum2, &neg);
/* Negating a scalar should be equal to (order - n) mod order on the number. */
CHECK(secp256k1_num_eq(&negnum, &negnum2));
@@ -415,17 +433,17 @@ 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;
+ unsigned char cone[1] = {0x01};
unsigned int shift = 256 + (secp256k1_rand32() % 257);
secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift);
- secp256k1_num_t rnum;
secp256k1_num_mul(&rnum, &s1num, &s2num);
secp256k1_num_shift(&rnum, shift - 1);
- secp256k1_num_t one;
- unsigned char cone[1] = {0x01};
secp256k1_num_set_bin(&one, cone, 1);
secp256k1_num_add(&rnum, &rnum, &one);
secp256k1_num_shift(&rnum, 1);
- secp256k1_num_t rnum2;
secp256k1_scalar_get_num(&rnum2, &r);
CHECK(secp256k1_num_eq(&rnum, &rnum2));
}
@@ -435,11 +453,13 @@ void scalar_test(void) {
/* Test that scalar inverses are equal to the inverse of their number modulo the order. */
if (!secp256k1_scalar_is_zero(&s)) {
secp256k1_scalar_t inv;
- secp256k1_scalar_inverse(&inv, &s);
#ifndef USE_NUM_NONE
secp256k1_num_t invnum;
- secp256k1_num_mod_inverse(&invnum, &snum, &order);
secp256k1_num_t invnum2;
+#endif
+ secp256k1_scalar_inverse(&inv, &s);
+#ifndef USE_NUM_NONE
+ secp256k1_num_mod_inverse(&invnum, &snum, &order);
secp256k1_scalar_get_num(&invnum2, &inv);
CHECK(secp256k1_num_eq(&invnum, &invnum2));
#endif
@@ -461,15 +481,18 @@ void scalar_test(void) {
}
{
+ secp256k1_scalar_t r1, r2;
+ secp256k1_scalar_t b;
+ int i;
/* Test add_bit. */
int bit = secp256k1_rand32() % 256;
- secp256k1_scalar_t b;
secp256k1_scalar_set_int(&b, 1);
CHECK(secp256k1_scalar_is_one(&b));
- for (int i = 0; i < bit; i++) {
+ for (i = 0; i < bit; i++) {
secp256k1_scalar_add(&b, &b, &b);
}
- secp256k1_scalar_t r1 = s1, r2 = s1;
+ r1 = s1;
+ r2 = s1;
if (!secp256k1_scalar_add(&r1, &r1, &b)) {
/* No overflow happened. */
secp256k1_scalar_add_bit(&r2, bit);
@@ -551,7 +574,8 @@ void scalar_test(void) {
}
void run_scalar_tests(void) {
- for (int i = 0; i < 128 * count; i++) {
+ int i;
+ for (i = 0; i < 128 * count; i++) {
scalar_test();
}
@@ -571,11 +595,11 @@ void run_scalar_tests(void) {
{
/* A scalar with value of the curve order should be 0. */
secp256k1_num_t order;
- secp256k1_scalar_order_get_num(&order);
- unsigned char bin[32];
- secp256k1_num_get_bin(bin, 32, &order);
secp256k1_scalar_t zero;
+ unsigned char bin[32];
int overflow = 0;
+ secp256k1_scalar_order_get_num(&order);
+ secp256k1_num_get_bin(bin, 32, &order);
secp256k1_scalar_set_b32(&zero, bin, &overflow);
CHECK(overflow == 1);
CHECK(secp256k1_scalar_is_zero(&zero));
@@ -608,39 +632,67 @@ void random_fe_non_zero(secp256k1_fe_t *nz) {
}
void random_fe_non_square(secp256k1_fe_t *ns) {
- random_fe_non_zero(ns);
secp256k1_fe_t 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_normalize_weak(&an);
- secp256k1_fe_t bn = *b; secp256k1_fe_normalize_var(&bn);
+ secp256k1_fe_t an = *a;
+ secp256k1_fe_t bn = *b;
+ secp256k1_fe_normalize_weak(&an);
+ secp256k1_fe_normalize_var(&bn);
return secp256k1_fe_equal_var(&an, &bn);
}
int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) {
- secp256k1_fe_t x; secp256k1_fe_mul(&x, a, ai);
- secp256k1_fe_t one; secp256k1_fe_set_int(&one, 1);
+ secp256k1_fe_t x;
+ secp256k1_fe_t one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+ secp256k1_fe_mul(&x, a, ai);
return check_fe_equal(&x, &one);
}
-void run_field_misc(void) {
- const unsigned char f32_5[32] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+void run_field_convert(void) {
+ static const unsigned char b32[32] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40
};
+ static const secp256k1_fe_storage_t fes = SECP256K1_FE_STORAGE_CONST(
+ 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL,
+ 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL
+ );
+ static const secp256k1_fe_t fe = SECP256K1_FE_CONST(
+ 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL,
+ 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL
+ );
+ secp256k1_fe_t fe2;
+ unsigned char b322[32];
+ secp256k1_fe_storage_t fes2;
+ /* Check conversions to fe. */
+ CHECK(secp256k1_fe_set_b32(&fe2, b32));
+ CHECK(secp256k1_fe_equal_var(&fe, &fe2));
+ secp256k1_fe_from_storage(&fe2, &fes);
+ CHECK(secp256k1_fe_equal_var(&fe, &fe2));
+ /* Check conversion from fe. */
+ secp256k1_fe_get_b32(b322, &fe);
+ CHECK(memcmp(b322, b32, 32) == 0);
+ secp256k1_fe_to_storage(&fes2, &fe);
+ CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0);
+}
+
+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;
- CHECK(secp256k1_fe_set_b32(&fe5, f32_5));
- for (int i=0; i<5*count; i++) {
+ secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
+ int i;
+ for (i = 0; i < 5*count; i++) {
+ secp256k1_fe_storage_t xs, ys, zs;
random_fe(&x);
random_fe_non_zero(&y);
/* Test the fe equality and comparison operations. */
@@ -649,12 +701,17 @@ void run_field_misc(void) {
z = x;
secp256k1_fe_add(&z,&y);
secp256k1_fe_normalize(&z);
- /* Test the conditional move. */
- secp256k1_fe_cmov(&z, &x, 0);
- CHECK(secp256k1_fe_equal_var(&x, &z) == 0);
- CHECK(secp256k1_fe_cmp_var(&x, &z) != 0);
- secp256k1_fe_cmov(&y, &x, 1);
- CHECK(secp256k1_fe_equal_var(&x, &y));
+ /* Test storage conversion and conditional moves. */
+ secp256k1_fe_to_storage(&xs, &x);
+ secp256k1_fe_to_storage(&ys, &y);
+ secp256k1_fe_to_storage(&zs, &z);
+ secp256k1_fe_storage_cmov(&zs, &xs, 0);
+ CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0);
+ secp256k1_fe_storage_cmov(&ys, &xs, 1);
+ CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0);
+ secp256k1_fe_from_storage(&x, &xs);
+ secp256k1_fe_from_storage(&y, &ys);
+ secp256k1_fe_from_storage(&z, &zs);
/* Test that mul_int, mul, and add agree. */
secp256k1_fe_add(&y, &x);
secp256k1_fe_add(&y, &x);
@@ -678,7 +735,8 @@ void run_field_misc(void) {
void run_field_inv(void) {
secp256k1_fe_t x, xi, xii;
- for (int i=0; i<10*count; i++) {
+ int i;
+ for (i = 0; i < 10*count; i++) {
random_fe_non_zero(&x);
secp256k1_fe_inv(&xi, &x);
CHECK(check_fe_inverse(&x, &xi));
@@ -689,7 +747,8 @@ void run_field_inv(void) {
void run_field_inv_var(void) {
secp256k1_fe_t x, xi, xii;
- for (int i=0; i<10*count; i++) {
+ int i;
+ for (i = 0; i < 10*count; i++) {
random_fe_non_zero(&x);
secp256k1_fe_inv_var(&xi, &x);
CHECK(check_fe_inverse(&x, &xi));
@@ -700,17 +759,19 @@ void run_field_inv_var(void) {
void run_field_inv_all_var(void) {
secp256k1_fe_t 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 (int i=0; i<count; i++) {
+ for (i = 0; i < count; i++) {
+ size_t j;
size_t len = (secp256k1_rand32() & 15) + 1;
- for (size_t j=0; j<len; j++)
+ for (j = 0; j < len; j++)
random_fe_non_zero(&x[j]);
secp256k1_fe_inv_all_var(len, xi, x);
- for (size_t j=0; j<len; j++)
+ for (j = 0; j < len; j++)
CHECK(check_fe_inverse(&x[j], &xi[j]));
secp256k1_fe_inv_all_var(len, xii, xi);
- for (size_t j=0; j<len; j++)
+ for (j = 0; j < len; j++)
CHECK(check_fe_equal(&x[j], &xii[j]));
}
}
@@ -719,10 +780,11 @@ void run_sqr(void) {
secp256k1_fe_t x, s;
{
+ int i;
secp256k1_fe_set_int(&x, 1);
secp256k1_fe_negate(&x, &x, 1);
- for (int i=1; i<=512; ++i) {
+ for (i = 1; i <= 512; ++i) {
secp256k1_fe_mul_int(&x, 2);
secp256k1_fe_normalize(&x);
secp256k1_fe_sqr(&s, &x);
@@ -746,6 +808,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;
+ int i;
/* Check sqrt(0) is 0 */
secp256k1_fe_set_int(&x, 0);
@@ -753,7 +816,7 @@ void run_sqrt(void) {
test_sqrt(&s, &x);
/* Check sqrt of small squares (and their negatives) */
- for (int i=1; i<=100; i++) {
+ for (i = 1; i <= 100; i++) {
secp256k1_fe_set_int(&x, i);
secp256k1_fe_sqr(&s, &x);
test_sqrt(&s, &x);
@@ -762,9 +825,10 @@ void run_sqrt(void) {
}
/* Consistency checks for large random values */
- for (int i=0; i<10; i++) {
+ for (i = 0; i < 10; i++) {
+ int j;
random_fe_non_square(&ns);
- for (int j=0; j<count; j++) {
+ for (j = 0; j < count; j++) {
random_fe(&x);
secp256k1_fe_sqr(&s, &x);
test_sqrt(&s, &x);
@@ -787,13 +851,13 @@ void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) {
}
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;
CHECK(a->infinity == b->infinity);
if (a->infinity)
return;
/* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
- secp256k1_fe_t z2s;
secp256k1_fe_sqr(&z2s, &b->z);
- secp256k1_fe_t u1, u2, s1, s2;
secp256k1_fe_mul(&u1, &a->x, &z2s);
u2 = b->x; secp256k1_fe_normalize_weak(&u2);
secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
@@ -803,6 +867,7 @@ void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) {
}
void test_ge(void) {
+ int i, i1;
int runs = 4;
/* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4).
* The second in each pair of identical points uses a random Z coordinate in the Jacobian form.
@@ -814,7 +879,8 @@ void test_ge(void) {
secp256k1_gej_set_infinity(&gej[0]);
secp256k1_ge_clear(&ge[0]);
secp256k1_ge_set_gej_var(&ge[0], &gej[0]);
- for (int i = 0; i < runs; i++) {
+ for (i = 0; i < runs; i++) {
+ int j;
secp256k1_ge_t g;
random_group_element_test(&g);
ge[1 + 4 * i] = g;
@@ -825,7 +891,7 @@ void test_ge(void) {
random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]);
secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]);
random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]);
- for (int j = 0; j < 4; j++) {
+ for (j = 0; j < 4; j++) {
random_field_element_magnitude(&ge[1 + j + 4 * i].x);
random_field_element_magnitude(&ge[1 + j + 4 * i].y);
random_field_element_magnitude(&gej[1 + j + 4 * i].x);
@@ -834,8 +900,9 @@ void test_ge(void) {
}
}
- for (int i1 = 0; i1 < 1 + 4 * runs; i1++) {
- for (int i2 = 0; i2 < 1 + 4 * runs; i2++) {
+ 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;
@@ -883,11 +950,12 @@ 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 = malloc((4 * runs + 1) * sizeof(secp256k1_gej_t));
- for (int i = 0; i < 4 * runs + 1; i++) {
+ for (i = 0; i < 4 * runs + 1; i++) {
gej_shuffled[i] = gej[i];
}
- for (int i = 0; i < 4 * runs + 1; i++) {
+ for (i = 0; i < 4 * runs + 1; i++) {
int swap = i + secp256k1_rand32() % (4 * runs + 1 - i);
if (swap != i) {
secp256k1_gej_t t = gej_shuffled[i];
@@ -895,9 +963,7 @@ void test_ge(void) {
gej_shuffled[swap] = t;
}
}
- secp256k1_gej_t sum;
- secp256k1_gej_set_infinity(&sum);
- for (int i = 0; i < 4 * runs + 1; i++) {
+ for (i = 0; i < 4 * runs + 1; i++) {
secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i]);
}
CHECK(secp256k1_gej_is_infinity(&sum));
@@ -908,7 +974,7 @@ void test_ge(void) {
{
secp256k1_ge_t *ge_set_all = malloc((4 * runs + 1) * sizeof(secp256k1_ge_t));
secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej);
- for (int i = 0; i < 4 * runs + 1; i++) {
+ for (i = 0; i < 4 * runs + 1; i++) {
ge_equals_gej(&ge_set_all[i], &gej[i]);
}
free(ge_set_all);
@@ -919,7 +985,8 @@ void test_ge(void) {
}
void run_ge(void) {
- for (int i = 0; i < count * 32; i++) {
+ int i;
+ for (i = 0; i < count * 32; i++) {
test_ge();
}
}
@@ -928,41 +995,35 @@ void run_ge(void) {
void run_ecmult_chain(void) {
/* random starting point A (on the curve) */
- secp256k1_fe_t ax; VERIFY_CHECK(secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64));
- secp256k1_fe_t ay; VERIFY_CHECK(secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64));
- secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay);
+ secp256k1_gej_t 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 */
- static const unsigned char xni[32] = {
- 0x84, 0xcc, 0x54, 0x52, 0xf7, 0xfd, 0xe1, 0xed,
- 0xb4, 0xd3, 0x8a, 0x8c, 0xe9, 0xb1, 0xb8, 0x4c,
- 0xce, 0xf3, 0x1f, 0x14, 0x6e, 0x56, 0x9b, 0xe9,
- 0x70, 0x5d, 0x35, 0x7a, 0x42, 0x98, 0x54, 0x07
- };
- secp256k1_scalar_t xn;
- secp256k1_scalar_set_b32(&xn, xni, NULL);
- static const unsigned char gni[32] = {
- 0xa1, 0xe5, 0x8d, 0x22, 0x55, 0x3d, 0xcd, 0x42,
- 0xb2, 0x39, 0x80, 0x62, 0x5d, 0x4c, 0x57, 0xa9,
- 0x6e, 0x93, 0x23, 0xd4, 0x2b, 0x31, 0x52, 0xe5,
- 0xca, 0x2c, 0x39, 0x90, 0xed, 0xc7, 0xc9, 0xde
- };
- secp256k1_scalar_t gn;
- secp256k1_scalar_set_b32(&gn, gni, NULL);
+ secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST(
+ 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c,
+ 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407
+ );
+ secp256k1_scalar_t 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 unsigned char xfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x13,0x37};
- secp256k1_scalar_t xf;
- secp256k1_scalar_set_b32(&xf, xfi, NULL);
- static const unsigned char gfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x71,0x13};
- secp256k1_scalar_t gf;
- secp256k1_scalar_set_b32(&gf, gfi, NULL);
+ 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);
/* accumulators with the resulting coefficients to A and G */
- secp256k1_scalar_t ae;
- secp256k1_scalar_set_int(&ae, 1);
- secp256k1_scalar_t ge;
- secp256k1_scalar_set_int(&ge, 0);
- /* the point being computed */
+ secp256k1_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);
+ /* actual points */
secp256k1_gej_t x = a;
- for (int i=0; i<200*count; i++) {
+ secp256k1_gej_t x2;
+ int i;
+
+ /* the point being computed */
+ x = a;
+ for (i = 0; i < 200*count; i++) {
/* in each iteration, compute X = xn*X + gn*G; */
secp256k1_ecmult(&x, &x, &xn, &gn);
/* also compute ae and ge: the actual accumulated factors for A and G */
@@ -976,78 +1037,84 @@ void run_ecmult_chain(void) {
/* verify */
if (i == 19999) {
- char res[132]; int resl = 132;
- secp256k1_gej_get_hex(res, &resl, &x);
- CHECK(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0);
+ /* expected result after 19999 iterations */
+ secp256k1_gej_t rp = SECP256K1_GEJ_CONST(
+ 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE,
+ 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830,
+ 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D,
+ 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88
+ );
+
+ secp256k1_gej_neg(&rp, &rp);
+ secp256k1_gej_add_var(&rp, &rp, &x);
+ CHECK(secp256k1_gej_is_infinity(&rp));
}
}
/* redo the computation, but directly with the resulting ae and ge coefficients: */
- secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge);
- char res[132]; int resl = 132;
- char res2[132]; int resl2 = 132;
- secp256k1_gej_get_hex(res, &resl, &x);
- secp256k1_gej_get_hex(res2, &resl2, &x2);
- CHECK(strcmp(res, res2) == 0);
- CHECK(strlen(res) == 131);
+ secp256k1_ecmult(&x2, &a, &ae, &ge);
+ secp256k1_gej_neg(&x2, &x2);
+ secp256k1_gej_add_var(&x2, &x2, &x);
+ CHECK(secp256k1_gej_is_infinity(&x2));
}
void test_point_times_order(const secp256k1_gej_t *point) {
- unsigned char pub[65];
/* X * (point + G) + (order-X) * (pointer + G) = 0 */
secp256k1_scalar_t x;
- random_scalar_order_test(&x);
secp256k1_scalar_t nx;
- secp256k1_scalar_negate(&nx, &x);
secp256k1_gej_t res1, res2;
+ secp256k1_ge_t res3;
+ unsigned char pub[65];
+ int psize = 65;
+ random_scalar_order_test(&x);
+ secp256k1_scalar_negate(&nx, &x);
secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */
secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */
secp256k1_gej_add_var(&res1, &res1, &res2);
CHECK(secp256k1_gej_is_infinity(&res1));
CHECK(secp256k1_gej_is_valid_var(&res1) == 0);
- secp256k1_ge_t res3;
secp256k1_ge_set_gej(&res3, &res1);
CHECK(secp256k1_ge_is_infinity(&res3));
CHECK(secp256k1_ge_is_valid_var(&res3) == 0);
- int psize = 65;
CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0);
psize = 65;
CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0);
}
void run_point_times_order(void) {
- secp256k1_fe_t x; VERIFY_CHECK(secp256k1_fe_set_hex(&x, "02", 2));
- for (int i=0; i<500; i++) {
+ 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(
+ 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C,
+ 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45
+ );
+ for (i = 0; i < 500; i++) {
secp256k1_ge_t p;
if (secp256k1_ge_set_xo_var(&p, &x, 1)) {
- CHECK(secp256k1_ge_is_valid_var(&p));
secp256k1_gej_t j;
+ CHECK(secp256k1_ge_is_valid_var(&p));
secp256k1_gej_set_ge(&j, &p);
CHECK(secp256k1_gej_is_valid_var(&j));
test_point_times_order(&j);
}
secp256k1_fe_sqr(&x, &x);
}
- char c[65];
- int cl = 1;
- c[1] = 123;
- secp256k1_fe_get_hex(c, &cl, &x); /* Check that fe_get_hex handles a too short input. */
- CHECK(c[1] == 123);
- cl = 65;
- secp256k1_fe_get_hex(c, &cl, &x);
- CHECK(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
+ secp256k1_fe_normalize_var(&x);
+ CHECK(secp256k1_fe_equal_var(&x, &xr));
}
void test_wnaf(const secp256k1_scalar_t *number, int w) {
secp256k1_scalar_t x, two, t;
+ int wnaf[256];
+ int zeroes = -1;
+ int i;
+ int bits;
secp256k1_scalar_set_int(&x, 0);
secp256k1_scalar_set_int(&two, 2);
- int wnaf[256];
- int bits = secp256k1_ecmult_wnaf(wnaf, number, w);
+ bits = secp256k1_ecmult_wnaf(wnaf, number, w);
CHECK(bits <= 256);
- int zeroes = -1;
- for (int i=bits-1; i>=0; i--) {
- secp256k1_scalar_mul(&x, &x, &two);
+ for (i = bits-1; i >= 0; i--) {
int v = wnaf[i];
+ secp256k1_scalar_mul(&x, &x, &two);
if (v) {
CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */
zeroes=0;
@@ -1070,8 +1137,9 @@ void test_wnaf(const secp256k1_scalar_t *number, int w) {
}
void run_wnaf(void) {
+ int i;
secp256k1_scalar_t n;
- for (int i=0; i<count; i++) {
+ for (i = 0; i < count; i++) {
random_scalar_order(&n);
if (i % 1)
secp256k1_scalar_negate(&n, &n);
@@ -1087,26 +1155,29 @@ void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, cons
}
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;
int recid;
int getrec;
- secp256k1_scalar_t msg, key;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
- secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key);
- secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj);
- secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecmult_gen(&pubj, &key);
+ secp256k1_ge_set_gej(&pub, &pubj);
getrec = secp256k1_rand32()&1;
random_sign(&sig, &key, &msg, getrec?&recid:NULL);
if (getrec) CHECK(recid >= 0 && recid < 4);
CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
- secp256k1_scalar_t one;
secp256k1_scalar_set_int(&one, 1);
secp256k1_scalar_add(&msg, &msg, &one);
CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
}
void run_ecdsa_sign_verify(void) {
- for (int i=0; i<10*count; i++) {
+ int i;
+ for (i = 0; i < 10*count; i++) {
test_ecdsa_sign_verify();
}
}
@@ -1149,9 +1220,32 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data);
}
+int is_empty_compact_signature(const unsigned char *sig64) {
+ static const unsigned char res[64] = {0};
+ return memcmp(sig64, res, 64) == 0;
+}
+
void test_ecdsa_end_to_end(void) {
+ unsigned char extra[32] = {0x00};
unsigned char privkey[32];
unsigned char message[32];
+ unsigned char privkey2[32];
+ 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];
+ 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;
/* Generate a random key and message. */
{
@@ -1164,7 +1258,6 @@ void test_ecdsa_end_to_end(void) {
/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(privkey) == 1);
- unsigned char pubkey[65]; int pubkeylen = 65;
CHECK(secp256k1_ec_pubkey_create(pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1);
if (secp256k1_rand32() & 1) {
CHECK(secp256k1_ec_pubkey_decompress(pubkey, &pubkeylen));
@@ -1172,52 +1265,73 @@ void test_ecdsa_end_to_end(void) {
CHECK(secp256k1_ec_pubkey_verify(pubkey, pubkeylen));
/* Verify private key import and export. */
- unsigned char seckey[300]; int seckeylen = 300;
CHECK(secp256k1_ec_privkey_export(privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1);
- unsigned char privkey2[32];
CHECK(secp256k1_ec_privkey_import(privkey2, seckey, seckeylen) == 1);
CHECK(memcmp(privkey, privkey2, 32) == 0);
/* Optionally tweak the keys using addition. */
if (secp256k1_rand32() % 3 == 0) {
+ int ret1;
+ int ret2;
unsigned char rnd[32];
+ unsigned char pubkey2[65];
+ int pubkeylen2 = 65;
secp256k1_rand256_test(rnd);
- int ret1 = secp256k1_ec_privkey_tweak_add(privkey, rnd);
- int ret2 = secp256k1_ec_pubkey_tweak_add(pubkey, pubkeylen, rnd);
+ ret1 = secp256k1_ec_privkey_tweak_add(privkey, rnd);
+ ret2 = secp256k1_ec_pubkey_tweak_add(pubkey, pubkeylen, rnd);
CHECK(ret1 == ret2);
if (ret1 == 0) return;
- unsigned char pubkey2[65]; int pubkeylen2 = 65;
CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1);
CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0);
}
/* Optionally tweak the keys using multiplication. */
if (secp256k1_rand32() % 3 == 0) {
+ int ret1;
+ int ret2;
unsigned char rnd[32];
+ unsigned char pubkey2[65];
+ int pubkeylen2 = 65;
secp256k1_rand256_test(rnd);
- int ret1 = secp256k1_ec_privkey_tweak_mul(privkey, rnd);
- int ret2 = secp256k1_ec_pubkey_tweak_mul(pubkey, pubkeylen, rnd);
+ ret1 = secp256k1_ec_privkey_tweak_mul(privkey, rnd);
+ ret2 = secp256k1_ec_pubkey_tweak_mul(pubkey, pubkeylen, rnd);
CHECK(ret1 == ret2);
if (ret1 == 0) return;
- unsigned char pubkey2[65]; int pubkeylen2 = 65;
CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1);
CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0);
}
/* Sign. */
- unsigned char signature[72]; int signaturelen = 72;
CHECK(secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, NULL, NULL) == 1);
+ CHECK(signaturelen > 0);
+ CHECK(secp256k1_ecdsa_sign(message, signature2, &signaturelen2, privkey, NULL, extra) == 1);
+ CHECK(signaturelen2 > 0);
+ extra[31] = 1;
+ CHECK(secp256k1_ecdsa_sign(message, signature3, &signaturelen3, privkey, NULL, extra) == 1);
+ CHECK(signaturelen3 > 0);
+ extra[31] = 0;
+ extra[0] = 1;
+ CHECK(secp256k1_ecdsa_sign(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));
/* Verify. */
CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) == 1);
+ CHECK(secp256k1_ecdsa_verify(message, signature2, signaturelen2, pubkey, pubkeylen) == 1);
+ CHECK(secp256k1_ecdsa_verify(message, signature3, signaturelen3, pubkey, pubkeylen) == 1);
+ CHECK(secp256k1_ecdsa_verify(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(message, signature, signaturelen, pubkey, pubkeylen) != 1);
/* Compact sign. */
- unsigned char csignature[64]; int recid = 0;
CHECK(secp256k1_ecdsa_sign_compact(message, csignature, privkey, NULL, NULL, &recid) == 1);
+ CHECK(!is_empty_compact_signature(csignature));
/* Recover. */
- unsigned char recpubkey[65]; int recpubkeylen = 0;
CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1);
CHECK(recpubkeylen == pubkeylen);
CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0);
@@ -1230,6 +1344,8 @@ void test_ecdsa_end_to_end(void) {
}
void test_random_pubkeys(void) {
+ secp256k1_ge_t elem;
+ secp256k1_ge_t elem2;
unsigned char in[65];
/* Generate some randomly sized pubkeys. */
uint32_t r = secp256k1_rand32();
@@ -1247,8 +1363,6 @@ void test_random_pubkeys(void) {
r>>=11;
if (len > 1) secp256k1_rand256(&in[1]);
if (len > 33) secp256k1_rand256(&in[33]);
- secp256k1_ge_t elem;
- secp256k1_ge_t elem2;
if (secp256k1_eckey_pubkey_parse(&elem, in, len)) {
unsigned char out[65];
unsigned char firstb;
@@ -1282,13 +1396,15 @@ void test_random_pubkeys(void) {
}
void run_random_pubkeys(void) {
- for (int i=0; i<10*count; i++) {
+ int i;
+ for (i = 0; i < 10*count; i++) {
test_random_pubkeys();
}
}
void run_ecdsa_end_to_end(void) {
- for (int i=0; i<64*count; i++) {
+ int i;
+ for (i = 0; i < 64*count; i++) {
test_ecdsa_end_to_end();
}
}
@@ -1314,12 +1430,8 @@ void test_ecdsa_edge_cases(void) {
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
};
unsigned char pubkey[65];
+ int t;
int pubkeylen = 65;
- CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 0));
- CHECK(secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 1));
- CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 2));
- CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 3));
-
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
const unsigned char sigb64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1333,7 +1445,16 @@ void test_ecdsa_edge_cases(void) {
};
unsigned char pubkeyb[33];
int pubkeyblen = 33;
- for (int recid = 0; recid < 4; recid++) {
+ int recid;
+
+ CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 0));
+ CHECK(secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 1));
+ CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 2));
+ CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 3));
+
+ 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};
@@ -1376,7 +1497,7 @@ void test_ecdsa_edge_cases(void) {
};
CHECK(secp256k1_ecdsa_recover_compact(msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid));
CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1);
- for (int recid2 = 0; recid2 < 4; recid2++) {
+ for (recid2 = 0; recid2 < 4; recid2++) {
unsigned char pubkey2b[33];
int pubkey2blen = 33;
CHECK(secp256k1_ecdsa_recover_compact(msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2));
@@ -1402,10 +1523,11 @@ void test_ecdsa_edge_cases(void) {
sigbder[7]--;
CHECK(secp256k1_ecdsa_verify(msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2);
CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2);
- for(int i = 0; i<8; i++) {
+ for(i = 0; i < 8; i++) {
+ int c;
unsigned char orig = sigbder[i];
/*Try every single-byte change.*/
- for (int c=0; c<256; c++) {
+ for (c = 0; c < 256; c++) {
if (c == orig ) continue;
sigbder[i] = c;
CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) ==
@@ -1417,16 +1539,17 @@ void test_ecdsa_edge_cases(void) {
/* Test the case where ECDSA recomputes a point that is infinity. */
{
+ 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_gej_t keyj;
secp256k1_ecmult_gen(&keyj, &sig.r);
- secp256k1_ge_t key;
secp256k1_ge_set_gej(&key, &keyj);
- secp256k1_scalar_t msg = sig.s;
+ msg = sig.s;
CHECK(secp256k1_ecdsa_sig_verify(&sig, &key, &msg) == 0);
}
@@ -1489,69 +1612,97 @@ void test_ecdsa_edge_cases(void) {
unsigned char sig[72];
int siglen = 72;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0);
+ CHECK(siglen == 0);
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0);
+ CHECK(siglen == 0);
msg[31] = 0xaa;
siglen = 72;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1);
+ CHECK(siglen > 0);
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1);
+ CHECK(siglen > 0);
siglen = 10;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1);
+ CHECK(siglen == 0);
}
/* Nonce function corner cases. */
- {
+ for (t = 0; t < 2; t++) {
+ static const unsigned char zero[32] = {0x00};
+ int i;
unsigned char key[32];
unsigned char msg[32];
unsigned char sig[72];
- memset(key, 0, 32);
+ unsigned char sig2[72];
+ secp256k1_ecdsa_sig_t s[512];
+ int siglen = 72;
+ int siglen2 = 72;
+ int recid2;
+ const unsigned char *extra;
+ extra = t == 0 ? NULL : zero;
memset(msg, 0, 32);
- key[31] = 1;
msg[31] = 1;
- int siglen = 72;
- int recid;
+ /* High key results in signature failure. */
+ memset(key, 0xFF, 32);
+ CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, extra) == 0);
+ CHECK(siglen == 0);
+ /* Zero key results in signature failure. */
+ memset(key, 0, 32);
+ CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, extra) == 0);
+ CHECK(siglen == 0);
/* Nonce function failure results in signature failure. */
- CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_fail, NULL) == 0);
- CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_fail, NULL, &recid) == 0);
+ key[31] = 1;
+ CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0);
+ CHECK(siglen == 0);
+ CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_fail, extra, &recid) == 0);
+ CHECK(is_empty_compact_signature(sig));
/* The retry loop successfully makes its way to the first good value. */
- unsigned char sig2[72];
- int siglen2 = 72;
siglen = 72;
- CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_retry, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, nonce_function_rfc6979, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1);
+ CHECK(siglen > 0);
+ CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1);
+ CHECK(siglen > 0);
CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
- int recid2;
- CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_retry, NULL, &recid) == 1);
- CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, nonce_function_rfc6979, NULL, &recid2) == 1);
+ CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_retry, extra, &recid) == 1);
+ CHECK(!is_empty_compact_signature(sig));
+ CHECK(secp256k1_ecdsa_sign_compact(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(msg, sig, &siglen, key, NULL, NULL) == 1);
- CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, extra) == 1);
+ CHECK(siglen > 0);
+ CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, extra) == 1);
+ CHECK(siglen2 > 0);
CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
- CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, NULL, NULL, &recid) == 1);
- CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, NULL, NULL, &recid2) == 1);
+ CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, NULL, extra, &recid) == 1);
+ CHECK(!is_empty_compact_signature(sig));
+ CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, NULL, extra, &recid2) == 1);
+ CHECK(!is_empty_compact_signature(sig));
CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
/* The default nonce function changes output with different messages. */
- secp256k1_ecdsa_sig_t s[512];
- for(int i=0; i<256; i++) {
+ for(i = 0; i < 256; i++) {
+ int j;
siglen2 = 72;
msg[0] = i;
- CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, extra) == 1);
+ CHECK(!is_empty_compact_signature(sig));
CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2));
- for (int j=0; j<i; j++) {
+ for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r));
}
}
msg[0] = 0;
msg[31] = 2;
/* The default nonce function changes output with different keys. */
- for(int i=256; i<512; i++) {
+ for(i = 256; i < 512; i++) {
+ int j;
siglen2 = 72;
key[0] = i - 256;
- CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1);
+ CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, extra) == 1);
CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2));
- for (int j=0; j<i; j++) {
+ for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r));
}
}
@@ -1581,8 +1732,8 @@ void run_ecdsa_edge_cases(void) {
EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) {
unsigned char privkey[300];
int privkeylen;
- int compr = secp256k1_rand32() & 1;
const unsigned char* pbegin = privkey;
+ int compr = secp256k1_rand32() & 1;
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
CHECK(secp256k1_eckey_privkey_serialize(privkey, &privkeylen, key, compr));
CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
@@ -1591,31 +1742,32 @@ EC_KEY *get_openssl_key(const secp256k1_scalar_t *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;
+ EC_KEY *ec_key;
+ unsigned int sigsize = 80;
+ int secp_sigsize = 80;
unsigned char message[32];
+ unsigned char signature[80];
secp256k1_rand256_test(message);
secp256k1_scalar_set_b32(&msg, message, NULL);
random_scalar_order_test(&key);
- secp256k1_gej_t qj;
secp256k1_ecmult_gen(&qj, &key);
- secp256k1_ge_t q;
secp256k1_ge_set_gej(&q, &qj);
- EC_KEY *ec_key = get_openssl_key(&key);
+ ec_key = get_openssl_key(&key);
CHECK(ec_key);
- unsigned char signature[80];
- unsigned int sigsize = 80;
CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
- secp256k1_ecdsa_sig_t sig;
CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
- secp256k1_scalar_t one;
secp256k1_scalar_set_int(&one, 1);
- secp256k1_scalar_t msg2;
secp256k1_scalar_add(&msg2, &msg, &one);
CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg2));
random_sign(&sig, &key, &msg, NULL);
- int secp_sigsize = 80;
CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig));
CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1);
@@ -1623,33 +1775,54 @@ void test_ecdsa_openssl(void) {
}
void run_ecdsa_openssl(void) {
- for (int i=0; i<10*count; i++) {
+ int i;
+ for (i = 0; i < 10*count; i++) {
test_ecdsa_openssl();
}
}
#endif
int main(int argc, char **argv) {
+ unsigned char seed16[16] = {0};
+ unsigned char run32[32] = {0};
/* find iteration count */
if (argc > 1) {
count = strtol(argv[1], NULL, 0);
}
/* find random seed */
- uint64_t seed;
if (argc > 2) {
- seed = strtoull(argv[2], NULL, 0);
+ int pos = 0;
+ const char* ch = argv[2];
+ while (pos < 16 && ch[0] != 0 && ch[1] != 0) {
+ unsigned short sh;
+ if (sscanf(ch, "%2hx", &sh)) {
+ seed16[pos] = sh;
+ } else {
+ break;
+ }
+ ch += 2;
+ pos++;
+ }
} else {
FILE *frand = fopen("/dev/urandom", "r");
- if (!frand || !fread(&seed, sizeof(seed), 1, frand)) {
- seed = time(NULL) * 1337;
+ if (!frand || !fread(&seed16, sizeof(seed16), 1, frand)) {
+ uint64_t t = time(NULL) * (uint64_t)1337;
+ seed16[0] ^= t;
+ seed16[1] ^= t >> 8;
+ seed16[2] ^= t >> 16;
+ seed16[3] ^= t >> 24;
+ seed16[4] ^= t >> 32;
+ seed16[5] ^= t >> 40;
+ seed16[6] ^= t >> 48;
+ seed16[7] ^= t >> 56;
}
fclose(frand);
}
- secp256k1_rand_seed(seed);
+ secp256k1_rand_seed(seed16);
printf("test count = %i\n", count);
- printf("random seed = %llu\n", (unsigned long long)seed);
+ printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]);
/* initialize */
secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY);
@@ -1657,12 +1830,6 @@ int main(int argc, char **argv) {
/* initializing a second time shouldn't cause any harm or memory leaks. */
secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY);
- /* Likewise, re-running the internal init functions should be harmless. */
- secp256k1_fe_start();
- secp256k1_ge_start();
- secp256k1_scalar_start();
- secp256k1_ecdsa_start();
-
run_sha256_tests();
run_hmac_sha256_tests();
run_rfc6979_hmac_sha256_tests();
@@ -1680,6 +1847,7 @@ int main(int argc, char **argv) {
run_field_inv_var();
run_field_inv_all_var();
run_field_misc();
+ run_field_convert();
run_sqr();
run_sqrt();
@@ -1700,18 +1868,13 @@ int main(int argc, char **argv) {
run_ecdsa_openssl();
#endif
- printf("random run = %llu\n", (unsigned long long)secp256k1_rand32() + ((unsigned long long)secp256k1_rand32() << 32));
+ 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_stop();
/* shutting down twice shouldn't cause any double frees. */
secp256k1_stop();
-
- /* Same for the internal shutdown functions. */
- secp256k1_fe_stop();
- secp256k1_ge_stop();
- secp256k1_scalar_stop();
- secp256k1_ecdsa_stop();
return 0;
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index c3a8f3a42b..ae98639f7c 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -27,7 +27,7 @@
} while(0)
#endif
-#ifndef HAVE_BUILTIN_EXPECT
+#ifdef HAVE_BUILTIN_EXPECT
#define EXPECT(x,c) __builtin_expect((x),(c))
#else
#define EXPECT(x,c) (x)
@@ -61,7 +61,7 @@
#define VERIFY_CHECK(cond) do { (void)(cond); } while(0)
#endif
-static inline void *checked_malloc(size_t size) {
+static SECP256K1_INLINE void *checked_malloc(size_t size) {
void *ret = malloc(size);
CHECK(ret != NULL);
return ret;
@@ -84,4 +84,21 @@ static inline void *checked_malloc(size_t size) {
# endif
#endif
+#if defined(_WIN32)
+# define I64FORMAT "I64d"
+# define I64uFORMAT "I64u"
+#else
+# define I64FORMAT "lld"
+# define I64uFORMAT "llu"
+#endif
+
+#if defined(HAVE___INT128)
+# if defined(__GNUC__)
+# define SECP256K1_GNUC_EXT __extension__
+# else
+# define SECP256K1_GNUC_EXT
+# endif
+SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
+#endif
+
#endif
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 5e1f5f0294..6b6df5199a 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -10,6 +10,7 @@
#include "clientversion.h"
#include "data/alertTests.raw.h"
+#include "chainparams.h"
#include "serialize.h"
#include "streams.h"
#include "util.h"
@@ -119,10 +120,11 @@ BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
BOOST_AUTO_TEST_CASE(AlertApplies)
{
SetMockTime(11);
+ const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
BOOST_FOREACH(const CAlert& alert, alerts)
{
- BOOST_CHECK(alert.CheckSignature());
+ BOOST_CHECK(alert.CheckSignature(alertKey));
}
BOOST_CHECK(alerts.size() >= 3);
@@ -159,6 +161,7 @@ BOOST_AUTO_TEST_CASE(AlertApplies)
BOOST_AUTO_TEST_CASE(AlertNotify)
{
SetMockTime(11);
+ const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
boost::filesystem::path temp = GetTempPath() / "alertnotify.txt";
boost::filesystem::remove(temp);
@@ -166,7 +169,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
BOOST_FOREACH(CAlert alert, alerts)
- alert.ProcessAlert(false);
+ alert.ProcessAlert(alertKey, false);
std::vector<std::string> r = read_lines(temp);
BOOST_CHECK_EQUAL(r.size(), 4u);
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 3c52547a64..271bc70f73 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -522,13 +522,13 @@
["Automatically generated test cases"],
[
- "0x47 0x3044022053205076a7bb12d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
+ "0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
"P2PK, bad sig"
],
[
- "0x47 0x30440220151ea78fa148b59f399b23731b634645ebc142f299ee9838d46fb78cf7e0bc0102200d62327dcd54ac6bcfb1516b035b1bf8eaea438c52c62d3450d1f3a8f030e0de01 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
+ "0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
"DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG",
"",
"P2PKH, bad pubkey"
@@ -540,19 +540,19 @@
"P2PK anyonecanpay marked with normal hashtype"
],
[
- "0x47 0x304402202166fcd5e607de452d3c6f15e059505cf21654346592f9650ba906b9e8be88fa022005d976d28eb8de477102feba28807b3ad361e7fa24796d259c9d61452f7c318c01 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
"P2SH",
"P2SH(P2PK), bad redeemscript"
],
[
- "0x47 0x3044022064cc90ca89ad721384b231653b945579359a24b928ef8539b331172628c9cc6102203e238869ab5dac3fc293db53c12e7dd3079e86cfde9024b689efc7227e4d671001 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"P2SH",
"P2SH(P2PKH), bad sig"
],
[
- "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0",
+ "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3, 2 sigs"
@@ -564,13 +564,13 @@
"P2SH(2-of-3), 1 sig"
],
[
- "0x47 0x30440220001d6702bfa4f49c3a2542af9b1c2844a2eaac55f86f310f42d26a5dd17d6a8002202cdadbe608c00b50dd951c6ba0877d5b07a970f3e265c18697bc413a0a86f69901",
+ "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
"P2PK with too much R padding"
],
[
- "0x48 0x304502207d2b258e959605e2ea50b46fea1325b7391ffb0c14a5b58ef8ad3851da3644380221007e75136df5f2e38216c4338b31c97e8307102edb97d611e06914e1f8fba68ead01",
+ "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
"P2PK with too much S padding"
@@ -582,19 +582,19 @@
"P2PK with too little R padding"
],
[
- "0x47 0x30440220003040725f724b0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
+ "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"DERSIG",
"P2PK NOT with bad sig with too much R padding"
],
[
- "0x47 0x30440220003040725f724a0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
+ "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"",
"P2PK NOT with too much R padding but no DERSIG"
],
[
- "0x47 0x30440220003040725f724a0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
+ "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"DERSIG",
"P2PK NOT with too much R padding"
@@ -648,19 +648,19 @@
"BIP66 example 6, with DERSIG"
],
[
- "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x304402200b3d0b0375bb15c14620afa4aa10ae90a0d6a046ce217bc20fe0bc1ced68c1b802204b550acab90ae6d3478057c9ad24f9df743815b799b6449dd7e7f6d3bc6e274c01",
+ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"DERSIG",
"BIP66 example 7, with DERSIG"
],
[
- "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
+ "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"",
"BIP66 example 8, without DERSIG"
],
[
- "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
+ "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"DERSIG",
"BIP66 example 8, with DERSIG"
@@ -678,7 +678,7 @@
"BIP66 example 9, with DERSIG"
],
[
- "0 0 0x47 0x30440220afa76a8f60622f813b05711f051c6c3407e32d1b1b70b0576c1f01b54e4c05c702200d58e9df044fd1845cabfbeef6e624ba0401daf7d7e084736f9ff601c3783bf501",
+ "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"DERSIG",
"BIP66 example 10, with DERSIG"
@@ -708,37 +708,37 @@
"P2PK with high S"
],
[
- "0x47 0x30440220745d63eb70d45652128b450aa5ca7d9b513439963f261cb1c40a60f0785e7ee402204877785b38945ca9dbec78e1c1d4dd12148cc25c868bd27480023b49ae0f310501",
+ "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"STRICTENC",
"P2PK with hybrid pubkey"
],
[
- "0x47 0x30440220606f6f9f6cebc94ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
+ "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"",
"P2PK NOT with hybrid pubkey but no STRICTENC"
],
[
- "0x47 0x30440220606f6f9f6cebc94ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
+ "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"STRICTENC",
"P2PK NOT with hybrid pubkey"
],
[
- "0x47 0x30440220606f6f9f6cebc84ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
+ "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"STRICTENC",
"P2PK NOT with invalid hybrid pubkey"
],
[
- "0 0x47 0x304402203cdcf66792fe97e3955655ede5dad004950e58b369831ffa7743132c507b272c022031fbcfb4a72b3e00217abf2f5557585f1f9891f12827d2f0a2ae2978e7f9f11001",
+ "0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201",
"1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG",
"STRICTENC",
"1-of-2 with the first 1 hybrid pubkey"
],
[
- "0x47 0x304402201c215cb13e4954e60ce4f6de74941904c771f998de7b1d9627e82a1949fde517022031c2197455f3dbecbb78321201308d7b039424e38d480772d7cd4eb465a083f405",
+ "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"STRICTENC",
"P2PK with undefined hashtype"
@@ -750,7 +750,7 @@
"P2PK NOT with invalid sig and undefined hashtype"
],
[
- "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
+ "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"NULLDUMMY",
"3-of-3 with nonzero dummy"
@@ -762,7 +762,7 @@
"3-of-3 NOT with invalid sig with nonzero dummy"
],
[
- "0 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01 DUP",
+ "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"SIGPUSHONLY",
"2-of-2 with two identical keys and sigs pushed using OP_DUP"
@@ -780,7 +780,7 @@
"P2SH(P2PK) with non-push scriptSig"
],
[
- "11 0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
+ "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"CLEANSTACK,P2SH",
"P2PK with unnecessary input"
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index 34e2c8d61a..064dde8464 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -700,7 +700,7 @@
["Automatically generated test cases"],
[
- "0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
+ "0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
"P2PK"
@@ -718,37 +718,37 @@
"P2PK anyonecanpay"
],
[
- "0x47 0x304402202166fcd5e607de452d3c6f15e059505cf21654346592f9650ba906b9e8be88fa022005d976d28eb8de477102feba28807b3ad361e7fa24796d259c9d61452f7c318c01 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
"P2SH",
"P2SH(P2PK)"
],
[
- "0x47 0x3044022064cc90ca89ad721384b231653b945579359a24b928ef8539b331172628c9cc6102203e238869ab5dac3fc293db53c12e7dd3079e86cfde9024b689efc7227e4d671001 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"",
"P2SH(P2PKH), bad sig but no VERIFY_P2SH"
],
[
- "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
+ "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3"
],
[
- "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x304402204511cf05e85c2be07c6c176c5338a08ed3cb34212667f39613340881169986c002207cc48b27aa3691a20706a5773ec9923cadd20fedffd00c24457d85f83f0b51fe01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
"HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
"P2SH",
"P2SH(2-of-3)"
],
[
- "0x47 0x30440220001d6702bfa4f49c3a2542af9b1c2844a2eaac55f86f310f42d26a5dd17d6a8002202cdadbe608c00b50dd951c6ba0877d5b07a970f3e265c18697bc413a0a86f69901",
+ "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
"P2PK with too much R padding but no DERSIG"
],
[
- "0x48 0x304502207d2b258e959605e2ea50b46fea1325b7391ffb0c14a5b58ef8ad3851da3644380221007e75136df5f2e38216c4338b31c97e8307102edb97d611e06914e1f8fba68ead01",
+ "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
"P2PK with too much S padding but no DERSIG"
@@ -760,7 +760,7 @@
"P2PK with too little R padding but no DERSIG"
],
[
- "0x47 0x30440220003040725f724b0e2142fc44ac71f6e13161f6410aeb6dee477952ede3b6a6ca022041ff4940ee3d88116ad281d7cc556e1f2c9427d82290bd7974a25addbcd5bede01",
+ "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"",
"P2PK NOT with bad sig with too much R padding but no DERSIG"
@@ -790,25 +790,25 @@
"BIP66 example 6, without DERSIG"
],
[
- "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x304402200b3d0b0375bb15c14620afa4aa10ae90a0d6a046ce217bc20fe0bc1ced68c1b802204b550acab90ae6d3478057c9ad24f9df743815b799b6449dd7e7f6d3bc6e274c01",
+ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"",
"BIP66 example 7, without DERSIG"
],
[
- "0 0 0x47 0x30440220afa76a8f60622f813b05711f051c6c3407e32d1b1b70b0576c1f01b54e4c05c702200d58e9df044fd1845cabfbeef6e624ba0401daf7d7e084736f9ff601c3783bf501",
+ "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"",
"BIP66 example 10, without DERSIG"
],
[
- "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0",
+ "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"",
"BIP66 example 12, without DERSIG"
],
[
- "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0",
+ "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"DERSIG",
"BIP66 example 12, with DERSIG"
@@ -826,31 +826,31 @@
"P2PK with high S but no LOW_S"
],
[
- "0x47 0x30440220745d63eb70d45652128b450aa5ca7d9b513439963f261cb1c40a60f0785e7ee402204877785b38945ca9dbec78e1c1d4dd12148cc25c868bd27480023b49ae0f310501",
+ "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
"P2PK with hybrid pubkey but no STRICTENC"
],
[
- "0x47 0x30440220606f6f9f6cebc84ebfb6a4bff0b682bd99f05511295545ce9b275e98be3c946102206871d6a76f4e1b43d9763cfc5647844e4811682b1cab0325f060f44ddf44002201",
+ "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"",
"P2PK NOT with invalid hybrid pubkey but no STRICTENC"
],
[
- "0 0x47 0x304402203a5ee39032637c431af0a3ac42e32e0627390bd44f6f98c9c04e6d714635ad0202207b42fcd889c3ae8a1b515608f38535f1f9be815176ee8d1b65a27c767cf37aed01",
+ "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401",
"1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"",
"1-of-2 with the second 1 hybrid pubkey and no STRICTENC"
],
[
- "0 0x47 0x304402203a5ee39032637c431af0a3ac42e32e0627390bd44f6f98c9c04e6d714635ad0202207b42fcd889c3ae8a1b515608f38535f1f9be815176ee8d1b65a27c767cf37aed01",
+ "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401",
"1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"STRICTENC",
"1-of-2 with the second 1 hybrid pubkey"
],
[
- "0x47 0x304402201c215cb13e4954e60ce4f6de74941904c771f998de7b1d9627e82a1949fde517022031c2197455f3dbecbb78321201308d7b039424e38d480772d7cd4eb465a083f405",
+ "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"",
"P2PK with undefined hashtype but no STRICTENC"
@@ -862,7 +862,7 @@
"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"
],
[
- "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402206d32e6d6b131ef2fe77b6a9b90b120d74e3e238e79dcffb10523a6ec94f93d65022067ae8772632ddf4c389258c6b70ed0ff94f20ee8f60207aa192a52a2469cddd901 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
+ "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3 with nonzero dummy but no NULLDUMMY"
@@ -874,19 +874,19 @@
"3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
],
[
- "0 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01 DUP",
+ "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"",
"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"
],
[
- "0 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01 0x47 0x304402206cb053202e1501e6faa24e6e309bf46a2f9255aa9484ff4a26efb7434f78a58a0220132b10419c3b99601f154bf86cf12259aacd8c6f363a73dacb1d0b941680bb4c01",
+ "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"SIGPUSHONLY",
"2-of-2 with two identical keys and sigs pushed"
],
[
- "11 0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
+ "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"P2SH",
"P2PK with unnecessary input but no CLEANSTACK"
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
new file mode 100644
index 0000000000..0996e13c48
--- /dev/null
+++ b/src/test/mempool_tests.cpp
@@ -0,0 +1,104 @@
+// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "main.h"
+#include "txmempool.h"
+#include "util.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+#include <list>
+
+BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)
+
+BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
+{
+ // Test CTxMemPool::remove functionality
+
+ // Parent transaction with three children,
+ // and three grand-children:
+ CMutableTransaction txParent;
+ txParent.vin.resize(1);
+ txParent.vin[0].scriptSig = CScript() << OP_11;
+ txParent.vout.resize(3);
+ for (int i = 0; i < 3; i++)
+ {
+ txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ txParent.vout[i].nValue = 33000LL;
+ }
+ CMutableTransaction txChild[3];
+ for (int i = 0; i < 3; i++)
+ {
+ txChild[i].vin.resize(1);
+ txChild[i].vin[0].scriptSig = CScript() << OP_11;
+ txChild[i].vin[0].prevout.hash = txParent.GetHash();
+ txChild[i].vin[0].prevout.n = i;
+ txChild[i].vout.resize(1);
+ txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ txChild[i].vout[0].nValue = 11000LL;
+ }
+ CMutableTransaction txGrandChild[3];
+ for (int i = 0; i < 3; i++)
+ {
+ txGrandChild[i].vin.resize(1);
+ txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;
+ txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();
+ txGrandChild[i].vin[0].prevout.n = 0;
+ txGrandChild[i].vout.resize(1);
+ txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ txGrandChild[i].vout[0].nValue = 11000LL;
+ }
+
+
+ CTxMemPool testPool(CFeeRate(0));
+ std::list<CTransaction> removed;
+
+ // Nothing in pool, remove should do nothing:
+ testPool.remove(txParent, removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 0);
+
+ // Just the parent:
+ testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1));
+ testPool.remove(txParent, removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 1);
+ removed.clear();
+
+ // Parent, children, grandchildren:
+ testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1));
+ for (int i = 0; i < 3; i++)
+ {
+ testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1));
+ testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1));
+ }
+ // Remove Child[0], GrandChild[0] should be removed:
+ testPool.remove(txChild[0], removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 2);
+ removed.clear();
+ // ... make sure grandchild and child are gone:
+ testPool.remove(txGrandChild[0], removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 0);
+ testPool.remove(txChild[0], removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 0);
+ // Remove parent, all children/grandchildren should go:
+ testPool.remove(txParent, removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 5);
+ BOOST_CHECK_EQUAL(testPool.size(), 0);
+ removed.clear();
+
+ // Add children and grandchildren, but NOT the parent (simulate the parent being in a block)
+ for (int i = 0; i < 3; i++)
+ {
+ testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1));
+ testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1));
+ }
+ // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
+ // put into the mempool (maybe because it is non-standard):
+ testPool.remove(txParent, removed, true);
+ BOOST_CHECK_EQUAL(removed.size(), 6);
+ BOOST_CHECK_EQUAL(testPool.size(), 0);
+ removed.clear();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 5358e18668..a2cb78c989 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -30,6 +30,7 @@ BasicTestingSetup::BasicTestingSetup()
{
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
+ fCheckBlockIndex = true;
SelectParams(CBaseChainParams::MAIN);
}
BasicTestingSetup::~BasicTestingSetup()
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 0d50660327..85ea3f77b5 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -444,6 +444,18 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
LOCK(cs);
std::deque<uint256> txToRemove;
txToRemove.push_back(origTx.GetHash());
+ if (fRecursive && !mapTx.count(origTx.GetHash())) {
+ // If recursively removing but origTx isn't in the mempool
+ // be sure to remove any children that are in the pool. This can
+ // happen during chain re-orgs if origTx isn't re-accepted into
+ // the mempool for any reason.
+ for (unsigned int i = 0; i < origTx.vout.size(); i++) {
+ std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i));
+ if (it == mapNextTx.end())
+ continue;
+ txToRemove.push_back(it->second.ptx->GetHash());
+ }
+ }
while (!txToRemove.empty())
{
uint256 hash = txToRemove.front();