aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.qt.include6
-rw-r--r--src/Makefile.test.include3
-rw-r--r--src/bitcoin-tx.cpp6
-rw-r--r--src/blockencodings.cpp2
-rw-r--r--src/blockencodings.h8
-rw-r--r--src/chain.h10
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/consensus/validation.h6
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/httprpc.cpp2
-rw-r--r--src/httpserver.cpp18
-rw-r--r--src/httpserver.h2
-rw-r--r--src/init.cpp27
-rw-r--r--src/main.cpp72
-rw-r--r--src/main.h13
-rw-r--r--src/net.cpp63
-rw-r--r--src/net.h5
-rw-r--r--src/primitives/transaction.cpp2
-rw-r--r--src/protocol.h3
-rw-r--r--src/qt/bitcoin.cpp3
-rw-r--r--src/qt/bitcoin.qrc2
-rw-r--r--src/qt/bitcoingui.cpp32
-rw-r--r--src/qt/bitcoingui.h9
-rw-r--r--src/qt/coincontroldialog.cpp90
-rw-r--r--src/qt/coincontroldialog.h8
-rw-r--r--src/qt/forms/coincontroldialog.ui61
-rw-r--r--src/qt/forms/sendcoinsdialog.ui39
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/intro.cpp10
-rw-r--r--src/qt/intro.h5
-rw-r--r--src/qt/optionsmodel.cpp14
-rw-r--r--src/qt/res/icons/hd_disabled.pngbin0 -> 4328 bytes
-rw-r--r--src/qt/res/icons/hd_enabled.pngbin0 -> 1889 bytes
-rw-r--r--src/qt/res/src/hd_disabled.svg26
-rw-r--r--src/qt/res/src/hd_enabled.svg13
-rw-r--r--src/qt/sendcoinsdialog.cpp9
-rw-r--r--src/qt/sendcoinsdialog.h1
-rw-r--r--src/qt/walletmodel.cpp5
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/qt/walletview.cpp6
-rw-r--r--src/qt/walletview.h2
-rw-r--r--src/rest.cpp14
-rw-r--r--src/rpc/blockchain.cpp6
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp11
-rw-r--r--src/rpc/misc.cpp4
-rw-r--r--src/rpc/net.cpp17
-rw-r--r--src/rpc/protocol.h54
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/rpc/register.h12
-rw-r--r--src/script/bitcoinconsensus.cpp4
-rw-r--r--src/script/interpreter.cpp54
-rw-r--r--src/script/interpreter.h13
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.h2
-rw-r--r--src/secp256k1/.gitignore19
-rw-r--r--src/secp256k1/.travis.yml19
-rw-r--r--src/secp256k1/Makefile.am72
-rw-r--r--src/secp256k1/README.md2
-rw-r--r--src/secp256k1/build-aux/m4/ax_jni_include_dir.m4140
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m44
-rw-r--r--src/secp256k1/configure.ac146
-rw-r--r--src/secp256k1/libsecp256k1.pc.in2
-rw-r--r--src/secp256k1/sage/group_prover.sage322
-rw-r--r--src/secp256k1/sage/secp256k1.sage306
-rw-r--r--src/secp256k1/sage/weierstrass_prover.sage264
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s919
-rw-r--r--src/secp256k1/src/bench_ecdh.c3
-rw-r--r--src/secp256k1/src/bench_internal.c34
-rw-r--r--src/secp256k1/src/bench_verify.c44
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h67
-rw-r--r--src/secp256k1/src/ecmult_impl.h2
-rw-r--r--src/secp256k1/src/field.h8
-rw-r--r--src/secp256k1/src/field_10x26_impl.h12
-rw-r--r--src/secp256k1/src/field_5x52_impl.h1
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h4
-rw-r--r--src/secp256k1/src/field_impl.h36
-rw-r--r--src/secp256k1/src/group.h5
-rw-r--r--src/secp256k1/src/group_impl.h36
-rw-r--r--src/secp256k1/src/hash.h2
-rw-r--r--src/secp256k1/src/hash_impl.h10
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java472
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java247
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java45
-rw-r--r--src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java51
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c412
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h112
-rw-r--r--src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c15
-rw-r--r--src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h22
-rw-r--r--src/secp256k1/src/modules/ecdh/Makefile.am.include2
-rw-r--r--src/secp256k1/src/modules/recovery/Makefile.am.include2
-rw-r--r--src/secp256k1/src/modules/schnorr/Makefile.am.include2
-rw-r--r--src/secp256k1/src/num.h6
-rw-r--r--src/secp256k1/src/num_gmp_impl.h26
-rw-r--r--src/secp256k1/src/scalar_impl.h2
-rw-r--r--src/secp256k1/src/secp256k1.c15
-rw-r--r--src/secp256k1/src/tests.c190
-rw-r--r--src/serialize.h4
-rw-r--r--src/sync.h5
-rw-r--r--src/test/base58_tests.cpp3
-rwxr-xr-xsrc/test/bitcoin-util-test.py2
-rw-r--r--src/test/blockencodings_tests.cpp1
-rw-r--r--src/test/buildenv.py.in2
-rw-r--r--src/test/dbwrapper_tests.cpp6
-rw-r--r--src/test/net_tests.cpp22
-rw-r--r--src/test/pmt_tests.cpp1
-rw-r--r--src/test/rpc_tests.cpp12
-rw-r--r--src/test/script_P2SH_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp87
-rw-r--r--src/test/util_tests.cpp9
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp1
-rw-r--r--src/util.cpp9
-rw-r--r--src/wallet/db.cpp10
-rw-r--r--src/wallet/db.h10
-rw-r--r--src/wallet/rpcdump.cpp7
-rw-r--r--src/wallet/rpcwallet.cpp16
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/rpc_wallet_tests.cpp229
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp4
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp64
-rw-r--r--src/wallet/wallet.h18
-rw-r--r--src/wallet/walletdb.cpp31
-rw-r--r--src/zmq/zmqpublishnotifier.h2
126 files changed, 4536 insertions, 927 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 7730aba375..8947aeaca0 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -257,6 +257,8 @@ RES_ICONS = \
qt/res/icons/filesave.png \
qt/res/icons/fontbigger.png \
qt/res/icons/fontsmaller.png \
+ qt/res/icons/hd_disabled.png \
+ qt/res/icons/hd_enabled.png \
qt/res/icons/history.png \
qt/res/icons/info.png \
qt/res/icons/key.png \
@@ -271,14 +273,14 @@ RES_ICONS = \
qt/res/icons/synced.png \
qt/res/icons/transaction0.png \
qt/res/icons/transaction2.png \
+ qt/res/icons/transaction_abandoned.png \
qt/res/icons/transaction_conflicted.png \
qt/res/icons/tx_inout.png \
qt/res/icons/tx_input.png \
qt/res/icons/tx_output.png \
qt/res/icons/tx_mined.png \
qt/res/icons/warning.png \
- qt/res/icons/verify.png \
- qt/res/icons/transaction_abandoned.png
+ qt/res/icons/verify.png
BITCOIN_QT_CPP = \
qt/bantablemodel.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 27e7694748..0748d1a39d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -97,8 +97,7 @@ BITCOIN_TESTS += \
wallet/test/wallet_test_fixture.h \
wallet/test/accounting_tests.cpp \
wallet/test/wallet_tests.cpp \
- wallet/test/crypto_tests.cpp \
- wallet/test/rpc_wallet_tests.cpp
+ wallet/test/crypto_tests.cpp
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 8e8ac47455..cb863bda19 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -395,10 +395,8 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
if (!registers.count("privatekeys"))
throw runtime_error("privatekeys register variable must be set.");
- bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
- fGivenKeys = true;
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
@@ -454,7 +452,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
- if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
+ if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
@@ -517,7 +515,7 @@ public:
static void MutateTx(CMutableTransaction& tx, const string& command,
const string& commandVal)
{
- boost::scoped_ptr<Secp256k1Init> ecc;
+ std::unique_ptr<Secp256k1Init> ecc;
if (command == "nversion")
MutateTxVersion(tx, commandVal);
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 5c4c3bd274..df237f8f26 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -75,7 +75,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
}
prefilled_count = cmpctblock.prefilledtxn.size();
- // Calculate map of txids -> positions and check mempool to see what we have (or dont)
+ // Calculate map of txids -> positions and check mempool to see what we have (or don't)
// Because well-formed cmpctblock messages will have a (relatively) uniform distribution
// of short IDs, any highly-uneven distribution of elements can be safely treated as a
// READ_STATUS_FAILED.
diff --git a/src/blockencodings.h b/src/blockencodings.h
index b980e9e286..349fcbd50f 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -53,11 +53,11 @@ public:
}
uint16_t offset = 0;
- for (size_t i = 0; i < indexes.size(); i++) {
- if (uint64_t(indexes[i]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
+ for (size_t j = 0; j < indexes.size(); j++) {
+ if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("indexes overflowed 16 bits");
- indexes[i] = indexes[i] + offset;
- offset = indexes[i] + 1;
+ indexes[j] = indexes[j] + offset;
+ offset = indexes[j] + 1;
}
} else {
for (size_t i = 0; i < indexes.size(); i++) {
diff --git a/src/chain.h b/src/chain.h
index 76a774c123..6588e8f57d 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -137,15 +137,15 @@ enum BlockStatus: uint32_t {
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
- BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat
- BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat
+ BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat
+ BLOCK_HAVE_UNDO = 16, //!< undo data available in rev*.dat
BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,
- BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
- BLOCK_FAILED_CHILD = 64, //! descends from failed block
+ BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed
+ BLOCK_FAILED_CHILD = 64, //!< descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
- BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client
+ BLOCK_OPT_WITNESS = 128, //!< block data in blk*.data was received with a witness-enforcing client
};
/** The block chain is a tree shaped structure starting with the
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index ea6e3aada2..e6be1b5d5b 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -118,7 +118,7 @@ public:
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Christian Decker
vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch")); // Jonas Schnelli
+ vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 000b197270..3e24294a64 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -22,9 +22,9 @@ static const unsigned char REJECT_CHECKPOINT = 0x43;
class CValidationState {
private:
enum mode_state {
- MODE_VALID, //! everything ok
- MODE_INVALID, //! network rule violation (DoS value may be set)
- MODE_ERROR, //! run-time error
+ MODE_VALID, //!< everything ok
+ MODE_INVALID, //!< network rule violation (DoS value may be set)
+ MODE_ERROR, //!< run-time error
} mode;
int nDoS;
std::string strRejectReason;
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 09c68fbe55..4fa06135d2 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -117,7 +117,7 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
bool CDBWrapper::IsEmpty()
{
- boost::scoped_ptr<CDBIterator> it(NewIterator());
+ std::unique_ptr<CDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 04d3386e9a..6a6c5276cc 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -45,7 +45,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* base) : base(base)
+ HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name()
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index f921305fcc..b296b28503 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -42,8 +42,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func):
- req(std::move(req)), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
+ req(std::move(_req)), path(_path), func(_func)
{
}
void operator()()
@@ -92,8 +92,8 @@ private:
};
public:
- WorkQueue(size_t maxDepth) : running(true),
- maxDepth(maxDepth),
+ WorkQueue(size_t _maxDepth) : running(true),
+ maxDepth(_maxDepth),
numThreads(0)
{
}
@@ -158,8 +158,8 @@ public:
struct HTTPPathHandler
{
HTTPPathHandler() {}
- HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
- prefix(prefix), exactMatch(exactMatch), handler(handler)
+ HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
+ prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
{
}
std::string prefix;
@@ -522,8 +522,8 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data)
delete self;
}
-HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler):
- deleteWhenTriggered(deleteWhenTriggered), handler(handler)
+HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):
+ deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
{
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
@@ -539,7 +539,7 @@ void HTTPEvent::trigger(struct timeval* tv)
else
evtimer_add(ev, tv); // trigger after timeval passed
}
-HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
+HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
replySent(false)
{
}
diff --git a/src/httpserver.h b/src/httpserver.h
index 0e30e666a6..49d67f4b88 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -33,7 +33,7 @@ void InterruptHTTPServer();
void StopHTTPServer();
/** Handler for requests to a certain HTTP path */
-typedef std::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
+typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
/** Register handler for prefix.
* If multiple handlers match a prefix, the first-registered one will
* be invoked.
diff --git a/src/init.cpp b/src/init.cpp
index 51784fe06b..27843fa882 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -162,7 +162,7 @@ public:
static CCoinsViewDB *pcoinsdbview = NULL;
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
-static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
+static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
{
@@ -380,7 +380,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
- strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
+ strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
@@ -483,7 +483,7 @@ std::string LicenseInfo()
{
const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>";
const std::string URL_WEBSITE = "<https://bitcoincore.org>";
- // todo: remove urls from translations on next change
+
return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" +
"\n" +
strprintf(_("Please contribute if you find %s useful. "
@@ -495,9 +495,9 @@ std::string LicenseInfo()
"\n" +
"\n" +
_("This is experimental software.") + "\n" +
- _("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.") + "\n" +
+ strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" +
"\n" +
- _("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.") +
+ strprintf(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard."), "<https://www.openssl.org>") +
"\n";
}
@@ -1067,7 +1067,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Using data directory %s\n", strDataDir);
LogPrintf("Using config file %s\n", GetConfigFile().string());
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
- std::ostringstream strErrors;
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
@@ -1184,8 +1183,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
- bool fBound = false;
if (fListen) {
+ bool fBound = false;
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
CService addrBind;
@@ -1271,7 +1270,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// cache size calculations
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
- nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
+ nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
int64_t nBlockTreeDBCache = nTotalCache / 8;
nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);
nTotalCache -= nBlockTreeDBCache;
@@ -1492,18 +1491,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 11: start node
- if (!strErrors.str().empty())
- return InitError(strErrors.str());
-
//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
-#ifdef ENABLE_WALLET
- LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0);
- LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
- LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
-#endif
-
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
@@ -1516,9 +1506,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifdef ENABLE_WALLET
if (pwalletMain) {
- // Add wallet transactions that aren't already in a block to mapTransactions
- pwalletMain->ReacceptWalletTransactions();
-
// Run a thread to flush wallet periodically
threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
}
diff --git a/src/main.cpp b/src/main.cpp
index db457f6f53..aed9591f99 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -196,7 +196,7 @@ namespace {
*
* Memory used: 1.3 MB
*/
- boost::scoped_ptr<CRollingBloomFilter> recentRejects;
+ std::unique_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
@@ -532,7 +532,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
-void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
+void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
if (count == 0)
return;
@@ -589,6 +589,10 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
// We consider the chain that this peer is on invalid.
return;
}
+ if (!State(nodeid)->fHaveWitness && IsWitnessEnabled(pindex->pprev, consensusParams)) {
+ // We wouldn't download this block or its descendants from this peer.
+ return;
+ }
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
if (pindex->nChainTx)
state->pindexLastCommonBlock = pindex;
@@ -1174,7 +1178,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// nSequence >= maxint-1 on all inputs.
//
// maxint-1 is picked to still allow use of nLockTime by
- // non-replacable transactions. All inputs rather than just one
+ // non-replaceable transactions. All inputs rather than just one
// is for the sake of multi-party protocols, where we don't
// want a single party to be able to disable replacement.
//
@@ -1492,12 +1496,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) {
+ PrecomputedTransactionData txdata(tx);
+ if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
- if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) {
+ if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
+ !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
// Only the witness is wrong, so the transaction itself may be fine.
state.SetCorruptionPossible();
}
@@ -1513,7 +1518,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
{
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -1910,7 +1915,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
return false;
}
return true;
@@ -1969,7 +1974,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}// namespace Consensus
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1988,7 +1993,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// is safe because block merkle hashes are still computed and checked,
// and any change will be caught at the next checkpoint. Of course, if
// the checkpoint is for a chain that's invalid due to false scriptSigs
- // this optimisation would allow an invalid chain to be accepted.
+ // this optimization would allow an invalid chain to be accepted.
if (fScriptChecks) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
@@ -1996,7 +2001,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -2009,7 +2014,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
@@ -2405,6 +2410,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
+ std::vector<PrecomputedTransactionData> txdata;
+ txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const CTransaction &tx = block.vtx[i];
@@ -2451,13 +2458,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
+ txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -3942,7 +3950,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
- throw runtime_error("LoadBlockIndex(): new CBlockIndex failed");
+ throw runtime_error(std::string(__func__) + ": new CBlockIndex failed");
mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
@@ -4633,6 +4641,7 @@ std::string GetWarnings(const std::string& strFor)
string strStatusBar;
string strRPC;
string strGUI;
+ const string uiAlertSeperator = "<hr />";
if (!CLIENT_VERSION_IS_RELEASE) {
strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications";
@@ -4645,18 +4654,19 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
- strStatusBar = strGUI = strMiscWarning;
+ strStatusBar = strMiscWarning;
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
}
if (fLargeWorkForkFound)
{
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
- strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
+ strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
else if (fLargeWorkInvalidChainFound)
{
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
- strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
+ strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
if (strFor == "gui")
@@ -4801,7 +4811,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
{
// If a peer is asking for old blocks, we're almost guaranteed
// they wont have a useful mempool to match against a compact block,
- // and we dont feel like constructing the object for them, so
+ // and we don't feel like constructing the object for them, so
// instead we respond with the full, non-compact block.
if (mi->second->nHeight >= chainActive.Height() - 10) {
CBlockHeaderAndShortTxIDs cmpctblock(block);
@@ -4903,6 +4913,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (strCommand == NetMsgType::VERSION)
{
+ // Feeler connections exist only to verify if address is online.
+ if (pfrom->fFeeler) {
+ assert(pfrom->fInbound == false);
+ pfrom->fDisconnect = true;
+ }
+
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@@ -5005,11 +5021,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
{
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
}
}
@@ -5387,7 +5403,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
- LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
+ LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->id);
for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
@@ -6705,15 +6721,13 @@ bool SendMessages(CNode* pto)
if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
vector<CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
- if (State(pto->GetId())->fHaveWitness || !IsWitnessEnabled(pindex->pprev, consensusParams)) {
- uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
- vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
- LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
- pindex->nHeight, pto->id);
- }
+ uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
+ LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
+ pindex->nHeight, pto->id);
}
if (state.nBlocksInFlight == 0 && staller != -1) {
if (State(staller)->nStallingSince == 0) {
diff --git a/src/main.h b/src/main.h
index d4d70c0180..7a2d432628 100644
--- a/src/main.h
+++ b/src/main.h
@@ -38,6 +38,7 @@ class CScriptCheck;
class CTxMemPool;
class CValidationInterface;
class CValidationState;
+class PrecomputedTransactionData;
struct CNodeStateStats;
struct LockPoints;
@@ -191,7 +192,7 @@ extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
-static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP;
+static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
@@ -214,7 +215,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
*
- * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
+ * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganization; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
@@ -347,7 +348,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
* instead of being performed inline.
*/
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
- unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
+ unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
@@ -421,12 +422,13 @@ private:
unsigned int nFlags;
bool cacheStore;
ScriptError error;
+ PrecomputedTransactionData *txdata;
public:
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
- CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
+ CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
@@ -438,6 +440,7 @@ public:
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
+ std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
diff --git a/src/net.cpp b/src/net.cpp
index 8fbd8fd192..c5b080f794 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -43,6 +43,9 @@
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
+// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
+#define FEELER_SLEEP_WINDOW 1
+
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -61,6 +64,7 @@
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8;
+ const int MAX_FEELER_CONNECTIONS = 1;
struct ListenSocket {
SOCKET socket;
@@ -217,7 +221,7 @@ void AdvertiseLocal(CNode *pnode)
}
if (addrLocal.IsRoutable())
{
- LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
+ LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
pnode->PushAddress(addrLocal);
}
}
@@ -1017,7 +1021,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
- int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
+ int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS);
+ assert(nMaxInbound > 0);
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@@ -1613,6 +1618,9 @@ void ThreadOpenConnections()
// Initiate network connections
int64_t nStart = GetTime();
+
+ // Minimum time before next feeler connection (in microseconds).
+ int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (true)
{
ProcessOneShot();
@@ -1652,13 +1660,36 @@ void ThreadOpenConnections()
}
}
}
+ assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS));
- int64_t nANow = GetAdjustedTime();
+ // Feeler Connections
+ //
+ // Design goals:
+ // * Increase the number of connectable addresses in the tried table.
+ //
+ // Method:
+ // * Choose a random address from new and attempt to connect to it if we can connect
+ // successfully it is added to tried.
+ // * Start attempting feeler connections only after node finishes making outbound
+ // connections.
+ // * Only make a feeler connection once every few minutes.
+ //
+ bool fFeeler = false;
+ if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) {
+ int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
+ if (nTime > nNextFeeler) {
+ nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
+ fFeeler = true;
+ } else {
+ continue;
+ }
+ }
+ int64_t nANow = GetAdjustedTime();
int nTries = 0;
while (true)
{
- CAddrInfo addr = addrman.Select();
+ CAddrInfo addr = addrman.Select(fFeeler);
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
@@ -1682,7 +1713,7 @@ void ThreadOpenConnections()
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
- // only consider nodes missing relevant services after 40 failed attemps
+ // only consider nodes missing relevant services after 40 failed attempts
if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40)
continue;
@@ -1694,8 +1725,17 @@ void ThreadOpenConnections()
break;
}
- if (addrConnect.IsValid())
- OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
+ if (addrConnect.IsValid()) {
+
+ if (fFeeler) {
+ // Add small amount of random noise before connection to avoid synchronization.
+ int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
+ MilliSleep(randsleep);
+ LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString());
+ }
+
+ OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler);
+ }
}
}
@@ -1777,7 +1817,7 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{
//
// Initiate outbound network connection
@@ -1801,6 +1841,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem
pnode->fNetworkNode = true;
if (fOneShot)
pnode->fOneShot = true;
+ if (fFeeler)
+ pnode->fFeeler = true;
return true;
}
@@ -2062,7 +2104,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (semOutbound == NULL) {
// initialize semaphore
- int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
+ int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}
@@ -2107,7 +2149,7 @@ bool StopNode()
LogPrintf("StopNode()\n");
MapPort(false);
if (semOutbound)
- for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
+ for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++)
semOutbound->post();
if (fAddressesInitialized)
@@ -2448,6 +2490,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fWhitelisted = false;
fOneShot = false;
fClient = false; // set by version message
+ fFeeler = false;
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
diff --git a/src/net.h b/src/net.h
index b5ebe66ce0..b9cc81e4e9 100644
--- a/src/net.h
+++ b/src/net.h
@@ -41,6 +41,8 @@ namespace boost {
static const int PING_INTERVAL = 2 * 60;
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
static const int TIMEOUT_INTERVAL = 20 * 60;
+/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/
+static const int FEELER_INTERVAL = 120;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** The maximum number of new addresses to accumulate before announcing. */
@@ -89,7 +91,7 @@ CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
CNode* FindNode(const NodeId id); //TODO: Remove this
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
@@ -350,6 +352,7 @@ public:
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer, cleanSubVer;
bool fWhitelisted; // This peer can bypass DoS banning.
+ bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool fClient;
bool fInbound;
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 8d63805643..2fdc59ea07 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -100,7 +100,7 @@ CAmount CTransaction::GetValueOut() const
{
nValueOut += it->nValue;
if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nValueOut;
}
diff --git a/src/protocol.h b/src/protocol.h
index 015215b2a6..9b474ec79c 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -267,6 +267,9 @@ enum ServiceFlags : uint64_t {
// Indicates that a node can be asked for blocks and transactions including
// witness data.
NODE_WITNESS = (1 << 3),
+ // NODE_XTHIN means the node supports Xtreme Thinblocks
+ // If this is turned off then the node will not service nor make xthin requests
+ NODE_XTHIN = (1 << 4),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 64b5c83d72..430e6dd0e8 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -578,7 +578,8 @@ int main(int argc, char *argv[])
/// 5. Now that settings and translations are available, ask user for data directory
// User language is set up: pick a data directory
- Intro::pickDataDirectory();
+ if (!Intro::pickDataDirectory())
+ return 0;
/// 6. Determine availability of data directory and parse bitcoin.conf
/// - Do not call GetDataDir(true) before this step finishes
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index 24b0bae3ec..ca5b1fa673 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -50,6 +50,8 @@
<file alias="fontsmaller">res/icons/fontsmaller.png</file>
<file alias="prompticon">res/icons/chevron.png</file>
<file alias="transaction_abandoned">res/icons/transaction_abandoned.png</file>
+ <file alias="hd_enabled">res/icons/hd_enabled.png</file>
+ <file alias="hd_disabled">res/icons/hd_disabled.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="spinner-000">res/movies/spinner-000.png</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2afefb733e..272df3fdae 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -80,7 +80,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
clientModel(0),
walletFrame(0),
unitDisplayControl(0),
- labelEncryptionIcon(0),
+ labelWalletEncryptionIcon(0),
+ labelWalletHDStatusIcon(0),
labelConnectionsIcon(0),
labelBlocksIcon(0),
progressBarLabel(0),
@@ -194,7 +195,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
- labelEncryptionIcon = new QLabel();
+ labelWalletEncryptionIcon = new QLabel();
+ labelWalletHDStatusIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
if(enableWallet)
@@ -202,7 +204,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(unitDisplayControl);
frameBlocksLayout->addStretch();
- frameBlocksLayout->addWidget(labelEncryptionIcon);
+ frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
+ frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
}
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
@@ -988,28 +991,37 @@ bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
return false;
}
+void BitcoinGUI::setHDStatus(int hdEnabled)
+{
+ labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletHDStatusIcon->setToolTip(hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
+
+ // eventually disable the QLabel to set its opacity to 50%
+ labelWalletHDStatusIcon->setEnabled(hdEnabled);
+}
+
void BitcoinGUI::setEncryptionStatus(int status)
{
switch(status)
{
case WalletModel::Unencrypted:
- labelEncryptionIcon->hide();
+ labelWalletEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
changePassphraseAction->setEnabled(false);
encryptWalletAction->setEnabled(true);
break;
case WalletModel::Unlocked:
- labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
+ labelWalletEncryptionIcon->show();
+ labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
case WalletModel::Locked:
- labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
+ labelWalletEncryptionIcon->show();
+ labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 12e7702ed8..41770929b4 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -82,7 +82,8 @@ private:
WalletFrame *walletFrame;
UnitDisplayStatusBarControl *unitDisplayControl;
- QLabel *labelEncryptionIcon;
+ QLabel *labelWalletEncryptionIcon;
+ QLabel *labelWalletHDStatusIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
@@ -169,6 +170,12 @@ public Q_SLOTS:
*/
void setEncryptionStatus(int status);
+ /** Set the hd-enabled status as shown in the UI.
+ @param[in] status current hd enabled status
+ @see WalletModel::EncryptionStatus
+ */
+ void setHDStatus(int hdEnabled);
+
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
/** Show incoming transaction notification for new transactions. */
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 837f8ba6c1..f53242100c 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -76,7 +76,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
- QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
@@ -85,7 +84,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
- connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority()));
connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
@@ -94,7 +92,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->labelCoinControlFee->addAction(clipboardFeeAction);
ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
ui->labelCoinControlBytes->addAction(clipboardBytesAction);
- ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
ui->labelCoinControlChange->addAction(clipboardChangeAction);
@@ -124,16 +121,14 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
- ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
- ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
- ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290);
- ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
- ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
- ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
+ ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110);
+ ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190);
+ ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 320);
+ ui->treeWidget->setColumnWidth(COLUMN_DATE, 130);
+ ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110);
ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it
// default view is sorted by amount desc
@@ -325,12 +320,6 @@ void CoinControlDialog::clipboardBytes()
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}
-// copy label "Priority" to clipboard
-void CoinControlDialog::clipboardPriority()
-{
- GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
-}
-
// copy label "Dust" to clipboard
void CoinControlDialog::clipboardLowOutput()
{
@@ -419,25 +408,6 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
#endif
}
-// return human readable label for priority number
-QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEstimatePriority)
-{
- double dPriorityMedium = mempoolEstimatePriority;
-
- if (dPriorityMedium <= 0)
- dPriorityMedium = AllowFreeThreshold(); // not enough data, back to hard-coded
-
- if (dPriority / 1000000 > dPriorityMedium) return tr("highest");
- else if (dPriority / 100000 > dPriorityMedium) return tr("higher");
- else if (dPriority / 10000 > dPriorityMedium) return tr("high");
- else if (dPriority / 1000 > dPriorityMedium) return tr("medium-high");
- else if (dPriority > dPriorityMedium) return tr("medium");
- else if (dPriority * 10 > dPriorityMedium) return tr("low-medium");
- else if (dPriority * 100 > dPriorityMedium) return tr("low");
- else if (dPriority * 1000 > dPriorityMedium) return tr("lower");
- else return tr("lowest");
-}
-
// shows count of locked unspent outputs
void CoinControlDialog::updateLabelLocked()
{
@@ -473,7 +443,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
}
}
- QString sPriorityLabel = tr("none");
CAmount nAmount = 0;
CAmount nPayFee = 0;
CAmount nAfterFee = 0;
@@ -551,11 +520,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.
}
- // Priority
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
- dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
- sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority);
-
// in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate
if (CoinControlDialog::fSubtractFeeFromAmount)
if (nAmount - nPayAmount == 0)
@@ -568,6 +532,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Allow free? (require at least hard-coded threshold and default to that if no estimate)
+ double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
+ dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
fAllowFree = (dPriority >= dPriorityNeeded);
@@ -617,7 +583,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee");
QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee");
QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes");
- QLabel *l6 = dialog->findChild<QLabel *>("labelCoinControlPriority");
QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
@@ -633,7 +598,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes
- l6->setText(sPriorityLabel); // Priority
l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee))
@@ -644,21 +608,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l8->setText(ASYMP_UTF8 + l8->text());
}
- // turn labels "red"
- l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000
- l6->setStyleSheet((dPriority > 0 && !fAllowFree) ? "color:red;" : ""); // Priority < "medium"
- l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes"
+ // turn label red when dust
+ l7->setStyleSheet((fDust) ? "color:red;" : "");
// tool tips
- QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
- toolTip1 += tr("Can vary +/- 1 byte per input.");
-
- QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
- toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
-
- QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
+ QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
double dFeeVary;
@@ -671,14 +625,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l3->setToolTip(toolTip4);
l4->setToolTip(toolTip4);
- l5->setToolTip(toolTip1);
- l6->setToolTip(toolTip2);
- l7->setToolTip(toolTip3);
+ l7->setToolTip(toolTipDust);
l8->setToolTip(toolTip4);
dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip());
dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip());
dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
- dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
@@ -702,7 +653,6 @@ void CoinControlDialog::updateView()
QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
std::map<QString, std::vector<COutput> > mapCoins;
model->listCoins(mapCoins);
@@ -731,11 +681,8 @@ void CoinControlDialog::updateView()
}
CAmount nSum = 0;
- double dPrioritySum = 0;
int nChildren = 0;
- int nInputSum = 0;
BOOST_FOREACH(const COutput& out, coins.second) {
- int nInputSize = 0;
nSum += out.tx->vout[out.i].nValue;
nChildren++;
@@ -755,11 +702,6 @@ void CoinControlDialog::updateView()
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
itemOutput->setText(COLUMN_ADDRESS, sAddress);
-
- CPubKey pubkey;
- CKeyID *keyid = boost::get<CKeyID>(&outputAddress);
- if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed())
- nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes)
}
// label
@@ -788,13 +730,6 @@ void CoinControlDialog::updateView()
// confirmations
itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
- // priority
- double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
- itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority));
- itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
- dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
- nInputSum += nInputSize;
-
// transaction hash
uint256 txhash = out.tx->GetHash();
itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex()));
@@ -819,12 +754,9 @@ void CoinControlDialog::updateView()
// amount
if (treeMode)
{
- dPrioritySum = dPrioritySum / (nInputSum + 78);
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
- itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority));
- itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
}
}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 1a467eb2ff..7d73421e3a 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -40,7 +40,6 @@ public:
// static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*);
- static QString getPriorityLabel(double dPriority, double mempoolEstimatePriority);
static QList<CAmount> payAmounts;
static CCoinControl *coinControl;
@@ -72,11 +71,9 @@ private:
COLUMN_ADDRESS,
COLUMN_DATE,
COLUMN_CONFIRMATIONS,
- COLUMN_PRIORITY,
COLUMN_TXHASH,
COLUMN_VOUT_INDEX,
COLUMN_AMOUNT_INT64,
- COLUMN_PRIORITY_INT64,
COLUMN_DATE_INT64
};
@@ -87,8 +84,6 @@ private:
{
if (column == COLUMN_AMOUNT_INT64)
return COLUMN_AMOUNT;
- else if (column == COLUMN_PRIORITY_INT64)
- return COLUMN_PRIORITY;
else if (column == COLUMN_DATE_INT64)
return COLUMN_DATE;
}
@@ -96,8 +91,6 @@ private:
{
if (column == COLUMN_AMOUNT)
return COLUMN_AMOUNT_INT64;
- else if (column == COLUMN_PRIORITY)
- return COLUMN_PRIORITY_INT64;
else if (column == COLUMN_DATE)
return COLUMN_DATE_INT64;
}
@@ -118,7 +111,6 @@ private Q_SLOTS:
void clipboardFee();
void clipboardAfterFee();
void clipboardBytes();
- void clipboardPriority();
void clipboardLowOutput();
void clipboardChange();
void radioTreeMode(bool);
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index c1fef6b9b1..1ea00eb5c3 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -140,7 +140,10 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlPriorityText">
+ <widget class="QLabel" name="labelCoinControlLowOutputText">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="font">
<font>
<weight>75</weight>
@@ -148,12 +151,15 @@
</font>
</property>
<property name="text">
- <string>Priority:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlPriority">
+ <widget class="QLabel" name="labelCoinControlLowOutput">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -161,7 +167,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string notr="true">medium</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -213,41 +219,6 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Dust:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="contextMenuPolicy">
- <enum>Qt::ActionsContextMenu</enum>
- </property>
- <property name="text">
- <string notr="true">no</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
</layout>
</item>
<item>
@@ -431,7 +402,7 @@
<bool>false</bool>
</property>
<property name="columnCount">
- <number>12</number>
+ <number>10</number>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
@@ -474,16 +445,6 @@
</column>
<column>
<property name="text">
- <string>Priority</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string/>
- </property>
- </column>
- <column>
- <property name="text">
<string/>
</property>
</column>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 12d6a62c08..06e09074d1 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -332,7 +332,7 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlPriorityText">
+ <widget class="QLabel" name="labelCoinControlLowOutputText">
<property name="font">
<font>
<weight>75</weight>
@@ -340,12 +340,12 @@
</font>
</property>
<property name="text">
- <string>Priority:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlPriority">
+ <widget class="QLabel" name="labelCoinControlLowOutput">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -353,7 +353,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string notr="true">medium</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -411,36 +411,7 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Dust:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="contextMenuPolicy">
- <enum>Qt::ActionsContextMenu</enum>
- </property>
- <property name="text">
- <string notr="true">no</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- </layout>
+ </layout>
</item>
<item>
<layout class="QFormLayout" name="formLayoutCoinControl4">
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 947a4c6821..c00f5e8591 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -930,6 +930,9 @@ QString formatServicesStr(quint64 mask)
case NODE_WITNESS:
strList.append("WITNESS");
break;
+ case NODE_XTHIN:
+ strList.append("XTHIN");
+ break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 6d6af54290..1a241ae0f0 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -165,20 +165,20 @@ QString Intro::getDefaultDataDirectory()
return GUIUtil::boostPathToQString(GetDefaultDataDir());
}
-void Intro::pickDataDirectory()
+bool Intro::pickDataDirectory()
{
namespace fs = boost::filesystem;
QSettings settings;
/* If data directory provided on command line, no need to look at settings
or show a picking dialog */
if(!GetArg("-datadir", "").empty())
- return;
+ return true;
/* 1) Default data directory for operating system */
QString dataDir = getDefaultDataDirectory();
/* 2) Allow QSettings to override default dir */
dataDir = settings.value("strDataDir", dataDir).toString();
- if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR))
+ if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false))
{
/* If current default data directory does not exist, let the user choose one */
Intro intro;
@@ -190,7 +190,7 @@ void Intro::pickDataDirectory()
if(!intro.exec())
{
/* Cancel clicked */
- exit(0);
+ return false;
}
dataDir = intro.getDataDirectory();
try {
@@ -204,6 +204,7 @@ void Intro::pickDataDirectory()
}
settings.setValue("strDataDir", dataDir);
+ settings.setValue("fReset", false);
}
/* Only override -datadir if different from the default, to make it possible to
* override -datadir in the bitcoin.conf file in the default data directory
@@ -211,6 +212,7 @@ void Intro::pickDataDirectory()
*/
if(dataDir != getDefaultDataDirectory())
SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ return true;
}
void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
diff --git a/src/qt/intro.h b/src/qt/intro.h
index 9e2e96dc9e..ee768a7ad8 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -35,10 +35,13 @@ public:
/**
* Determine data directory. Let the user choose if the current one doesn't exist.
*
+ * @returns true if a data directory was selected, false if the user cancelled the selection
+ * dialog.
+ *
* @note do NOT call global GetDataDir() before calling this function, this
* will cause the wrong path to be cached.
*/
- static void pickDataDirectory();
+ static bool pickDataDirectory();
/**
* Determine default data directory for operating system.
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d33ab68277..f82e153b67 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -17,6 +17,7 @@
#include "net.h"
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
+#include "intro.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -99,6 +100,9 @@ void OptionsModel::Init(bool resetSettings)
if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
addOverriddenOption("-par");
+ if (!settings.contains("strDataDir"))
+ settings.setValue("strDataDir", Intro::getDefaultDataDirectory());
+
// Wallet
#ifdef ENABLE_WALLET
if (!settings.contains("bSpendZeroConfChange"))
@@ -151,9 +155,19 @@ void OptionsModel::Reset()
{
QSettings settings;
+ // Save the strDataDir setting
+ QString dataDir = Intro::getDefaultDataDirectory();
+ dataDir = settings.value("strDataDir", dataDir).toString();
+
// Remove all entries from our QSettings object
settings.clear();
+ // Set strDataDir
+ settings.setValue("strDataDir", dataDir);
+
+ // Set that this was reset
+ settings.setValue("fReset", true);
+
// default setting for OptionsModel::StartAtStartup - disabled
if (GUIUtil::GetStartOnSystemStartup())
GUIUtil::SetStartOnSystemStartup(false);
diff --git a/src/qt/res/icons/hd_disabled.png b/src/qt/res/icons/hd_disabled.png
new file mode 100644
index 0000000000..687b6d2e38
--- /dev/null
+++ b/src/qt/res/icons/hd_disabled.png
Binary files differ
diff --git a/src/qt/res/icons/hd_enabled.png b/src/qt/res/icons/hd_enabled.png
new file mode 100644
index 0000000000..568dde1cd1
--- /dev/null
+++ b/src/qt/res/icons/hd_enabled.png
Binary files differ
diff --git a/src/qt/res/src/hd_disabled.svg b/src/qt/res/src/hd_disabled.svg
new file mode 100644
index 0000000000..035f4431c7
--- /dev/null
+++ b/src/qt/res/src/hd_disabled.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
+<g>
+ <path d="M81.3,336.5v66.8h70.4v-66.8H190v174h-38.3v-75.1H81.3v75.1H43v-174H81.3z"/>
+ <path d="M298.7,336.5c11.2,0,21.6,1.8,31.3,5.4c9.7,3.6,18,8.9,25.1,16.1c7.1,7.2,12.6,16.1,16.6,26.8c4,10.7,6,23.3,6,37.8
+ c0,12.7-1.6,24.4-4.9,35.1c-3.3,10.7-8.2,20-14.7,27.8c-6.6,7.8-14.8,13.9-24.6,18.4c-9.8,4.5-21.4,6.7-34.7,6.7h-75.1v-174H298.7z
+ M296,478.3c5.5,0,10.9-0.9,16.1-2.7c5.2-1.8,9.8-4.8,13.9-8.9c4.1-4.1,7.3-9.5,9.7-16.2c2.4-6.7,3.7-14.8,3.7-24.4
+ c0-8.8-0.9-16.7-2.6-23.8s-4.5-13.1-8.4-18.2c-3.9-5-9.1-8.9-15.5-11.6c-6.4-2.7-14.3-4-23.8-4h-27.3v109.7H296z"/>
+</g>
+<g>
+ <g>
+ <line x1="32" y1="555.9" x2="358" y2="293.9"/>
+ </g>
+ <g>
+ <path fill="#FFFFFF" d="M32,580.9c-7.3,0-14.6-3.2-19.5-9.3c-8.6-10.8-6.9-26.5,3.8-35.1l326-262c10.8-8.6,26.5-6.9,35.1,3.8
+ c8.6,10.8,6.9,26.5-3.8,35.1l-326,262C43,579.1,37.5,580.9,32,580.9z"/>
+ </g>
+ <g>
+ <path d="M32,573.9c-5.3,0-10.5-2.3-14-6.7c-6.2-7.7-5-19.1,2.8-25.3l326-262c7.8-6.2,19.1-5,25.3,2.8c6.2,7.7,5,19.1-2.8,25.3
+ l-326,262C40,572.6,36,573.9,32,573.9z"/>
+ </g>
+</g>
+</svg>
diff --git a/src/qt/res/src/hd_enabled.svg b/src/qt/res/src/hd_enabled.svg
new file mode 100644
index 0000000000..cbaa16f8f0
--- /dev/null
+++ b/src/qt/res/src/hd_enabled.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
+<g>
+ <path d="M81.3,336.5v66.8h70.4v-66.8H190v174h-38.3v-75.1H81.3v75.1H43v-174H81.3z"/>
+ <path d="M298.7,336.5c11.2,0,21.6,1.8,31.3,5.4c9.7,3.6,18,8.9,25.1,16.1c7.1,7.2,12.6,16.1,16.6,26.8c4,10.7,6,23.3,6,37.8
+ c0,12.7-1.6,24.4-4.9,35.1c-3.3,10.7-8.2,20-14.7,27.8c-6.6,7.8-14.8,13.9-24.6,18.4c-9.8,4.5-21.4,6.7-34.7,6.7h-75.1v-174H298.7z
+ M296,478.3c5.5,0,10.9-0.9,16.1-2.7c5.2-1.8,9.8-4.8,13.9-8.9c4.1-4.1,7.3-9.5,9.7-16.2c2.4-6.7,3.7-14.8,3.7-24.4
+ c0-8.8-0.9-16.7-2.6-23.8s-4.5-13.1-8.4-18.2c-3.9-5-9.1-8.9-15.5-11.6c-6.4-2.7-14.3-4-23.8-4h-27.3v109.7H296z"/>
+</g>
+</svg>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 6d50be56ec..3e96bb18c3 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -69,7 +69,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
- QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity()));
@@ -77,7 +76,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee()));
connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee()));
connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes()));
- connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority()));
connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput()));
connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange()));
ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
@@ -85,7 +83,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
ui->labelCoinControlFee->addAction(clipboardFeeAction);
ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
ui->labelCoinControlBytes->addAction(clipboardBytesAction);
- ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
ui->labelCoinControlChange->addAction(clipboardChangeAction);
@@ -681,12 +678,6 @@ void SendCoinsDialog::coinControlClipboardBytes()
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}
-// Coin Control: copy label "Priority" to clipboard
-void SendCoinsDialog::coinControlClipboardPriority()
-{
- GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
-}
-
// Coin Control: copy label "Dust" to clipboard
void SendCoinsDialog::coinControlClipboardLowOutput()
{
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index be4f2ee44b..83dac0bd11 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -88,7 +88,6 @@ private Q_SLOTS:
void coinControlClipboardFee();
void coinControlClipboardAfterFee();
void coinControlClipboardBytes();
- void coinControlClipboardPriority();
void coinControlClipboardLowOutput();
void coinControlClipboardChange();
void setMinimumFee();
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3867310cd6..ae7efc7a0d 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -683,3 +683,8 @@ bool WalletModel::abandonTransaction(uint256 hash) const
LOCK2(cs_main, wallet->cs_wallet);
return wallet->AbandonTransaction(hash);
}
+
+bool WalletModel::hdEnabled() const
+{
+ return wallet->IsHDEnabled();
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index e5470bf618..a15ecf899b 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -203,6 +203,8 @@ public:
bool transactionCanBeAbandoned(uint256 hash) const;
bool abandonTransaction(uint256 hash) const;
+ bool hdEnabled() const;
+
private:
CWallet *wallet;
bool fHaveWatchOnly;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 6ce98ef160..495ebfd834 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -98,6 +98,9 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui)
// Pass through transaction notifications
connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString)));
+
+ // Connect HD enabled state signal
+ connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int)));
}
}
@@ -130,6 +133,9 @@ void WalletView::setWalletModel(WalletModel *walletModel)
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int)));
updateEncryptionStatus();
+ // update HD status
+ Q_EMIT hdEnabledStatusChanged(walletModel->hdEnabled());
+
// Balloon pop-up for new transaction
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(processNewTransaction(QModelIndex,int,int)));
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index dbb289f425..2045605954 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -117,6 +117,8 @@ Q_SIGNALS:
void message(const QString &title, const QString &message, unsigned int style);
/** Encryption status of wallet changed */
void encryptionStatusChanged(int status);
+ /** HD-Enabled status of wallet changed (only possible during startup) */
+ void hdEnabledStatusChanged(int hdEnabled);
/** Notify that a new transaction appeared */
void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label);
};
diff --git a/src/rest.cpp b/src/rest.cpp
index 2dff8d7dad..c815592124 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -420,7 +420,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// throw exception in case of a empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
bool fInputParsed = false;
bool fCheckMemPool = false;
@@ -444,7 +444,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1);
if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
txid.SetHex(strTxid);
vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
@@ -453,7 +453,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (vOutPoints.size() > 0)
fInputParsed = true;
else
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
}
switch (rf) {
@@ -469,7 +469,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (strRequestMutable.size() > 0)
{
if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
oss << strRequestMutable;
@@ -478,14 +478,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
}
} catch (const std::ios_base::failure& e) {
// abort in case of unreadable binary data
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
}
break;
}
case RF_JSON: {
if (!fInputParsed)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
break;
}
default: {
@@ -495,7 +495,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// limit max outpoints
if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
+ return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
// check spentness and form a bitmap (as well as a JSON capable human-readable string representation)
vector<unsigned char> bitmap;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index e3c32d905a..b90410017b 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -632,7 +632,7 @@ struct CCoinsStats
//! Calculate statistics about the unspent transaction output set
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
- boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -1205,8 +1205,8 @@ static const CRPCCommand commands[] =
{ "hidden", "reconsiderblock", &reconsiderblock, true },
};
-void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
+void RegisterBlockchainRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index d0675fdb49..3003ea3452 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -26,7 +26,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{
{ "stop", 0 },
{ "setmocktime", 0 },
- { "getaddednodeinfo", 0 },
{ "generate", 0 },
{ "generate", 1 },
{ "generatetoaddress", 0 },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 2479e5d595..14183c8e82 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -227,10 +227,11 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
" \"currentblockweight\": nnn, (numeric) The last block weight\n"
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
- " \"errors\": \"...\" (string) Current errors\n"
+ " \"errors\": \"...\" (string) Current errors\n"
+ " \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mem pool\n"
" \"testnet\": true|false (boolean) If using testnet or not\n"
- " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -650,7 +651,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (nMaxVersionPreVB >= 2) {
// If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here
- // Because BIP 34 changed how the generation transaction is serialised, we can only use version/force back to v2 blocks
+ // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks
// This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated
// Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated
aMutable.push_back("version/force");
@@ -918,8 +919,8 @@ static const CRPCCommand commands[] =
{ "util", "estimatesmartpriority", &estimatesmartpriority, true },
};
-void RegisterMiningRPCCommands(CRPCTable &tableRPC)
+void RegisterMiningRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index a8c5bcd177..e96feaa864 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -498,8 +498,8 @@ static const CRPCCommand commands[] =
{ "hidden", "setmocktime", &setmocktime, true },
};
-void RegisterMiscRPCCommands(CRPCTable &tableRPC)
+void RegisterMiscRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 58cf4a56e0..840bfd5a24 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -269,14 +269,13 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (fHelp || params.size() > 1)
throw runtime_error(
- "getaddednodeinfo dummy ( \"node\" )\n"
+ "getaddednodeinfo ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n"
"\nArguments:\n"
- "1. dummy (boolean, required) Kept for historical purposes but ignored\n"
- "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
+ "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
"\nResult:\n"
"[\n"
" {\n"
@@ -299,10 +298,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
- if (params.size() == 2) {
+ if (params.size() == 1) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
- if (info.strAddedNode == params[1].get_str()) {
+ if (info.strAddedNode == params[0].get_str()) {
vInfo.assign(1, info);
found = true;
break;
@@ -484,7 +483,7 @@ UniValue setban(const UniValue& params, bool fHelp)
"\nExamples:\n"
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
- + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400")
+ + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
);
CSubNet subNet;
@@ -590,8 +589,8 @@ static const CRPCCommand commands[] =
{ "network", "clearbanned", &clearbanned, true },
};
-void RegisterNetRPCCommands(CRPCTable &tableRPC)
+void RegisterNetRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 55d0aac68b..988e0fc5fa 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -38,18 +38,18 @@ enum RPCErrorCode
RPC_PARSE_ERROR = -32700,
//! General application defined errors
- RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
- RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
- RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
- RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
- RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
- RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
- RPC_DATABASE_ERROR = -20, //! Database error
- RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
- RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
- RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules
- RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain
- RPC_IN_WARMUP = -28, //! Client still warming up
+ RPC_MISC_ERROR = -1, //!< std::exception thrown in command handling
+ RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode
+ RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter
+ RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key
+ RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation
+ RPC_INVALID_PARAMETER = -8, //!< Invalid, missing or duplicate parameter
+ RPC_DATABASE_ERROR = -20, //!< Database error
+ RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format
+ RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission
+ RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules
+ RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
+ RPC_IN_WARMUP = -28, //!< Client still warming up
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -57,23 +57,23 @@ enum RPCErrorCode
RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,
//! P2P client errors
- RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected
- RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
- RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
- RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
- RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
- RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
+ RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected
+ RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //!< Still downloading initial blocks
+ RPC_CLIENT_NODE_ALREADY_ADDED = -23, //!< Node is already added
+ RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before
+ RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
+ RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
//! Wallet errors
- RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
- RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
- RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
- RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
- RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
- RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
- RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
- RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet
- RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
+ RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
+ RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account
+ RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name
+ RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first
+ RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first
+ RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect
+ RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
+ RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet
+ RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
};
std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 3270cd384f..9461a7280c 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -910,8 +910,8 @@ static const CRPCCommand commands[] =
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true },
};
-void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC)
+void RegisterRawTransactionRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/register.h b/src/rpc/register.h
index 01aa58a25d..49aee2365f 100644
--- a/src/rpc/register.h
+++ b/src/rpc/register.h
@@ -20,13 +20,13 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
-static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
+static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{
- RegisterBlockchainRPCCommands(tableRPC);
- RegisterNetRPCCommands(tableRPC);
- RegisterMiscRPCCommands(tableRPC);
- RegisterMiningRPCCommands(tableRPC);
- RegisterRawTransactionRPCCommands(tableRPC);
+ RegisterBlockchainRPCCommands(t);
+ RegisterNetRPCCommands(t);
+ RegisterMiscRPCCommands(t);
+ RegisterMiningRPCCommands(t);
+ RegisterRawTransactionRPCCommands(t);
}
#endif
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 62fd9031f8..b629f4278b 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -84,8 +84,8 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
// Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK);
-
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount), NULL);
+ PrecomputedTransactionData txdata(tx);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index bc027e9f0c..47ea261e31 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1108,9 +1108,40 @@ public:
}
};
+uint256 GetPrevoutHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].prevout;
+ }
+ return ss.GetHash();
+}
+
+uint256 GetSequenceHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].nSequence;
+ }
+ return ss.GetHash();
+}
+
+uint256 GetOutputsHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vout.size(); n++) {
+ ss << txTo.vout[n];
+ }
+ return ss.GetHash();
+}
+
} // anon namespace
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion)
+PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
+{
+ hashPrevouts = GetPrevoutHash(txTo);
+ hashSequence = GetSequenceHash(txTo);
+ hashOutputs = GetOutputsHash(txTo);
+}
+
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
@@ -1118,27 +1149,16 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
uint256 hashOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].prevout;
- }
- hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].nSequence;
- }
- hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
}
+
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vout.size(); n++) {
- ss << txTo.vout[n];
- }
- hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
@@ -1209,7 +1229,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
int nHashType = vchSig.back();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index bd2f211663..e5d7865cd3 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -98,13 +98,20 @@ enum
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
+struct PrecomputedTransactionData
+{
+ uint256 hashPrevouts, hashSequence, hashOutputs;
+
+ PrecomputedTransactionData(const CTransaction& tx);
+};
+
enum SigVersion
{
SIGVERSION_BASE = 0,
SIGVERSION_WITNESS_V0 = 1,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion);
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker
{
@@ -133,12 +140,14 @@ private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
+ const PrecomputedTransactionData* txdata;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckSequence(const CScriptNum& nSequence) const;
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 050bf8cc42..44551ec2bc 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -22,7 +22,7 @@ private:
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, nInIn, amount), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
diff --git a/src/script/sign.h b/src/script/sign.h
index 6404b4523e..f9aa6fca27 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -51,7 +51,7 @@ public:
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
-/** A signature creator that just produces 72-byte empty signatyres. */
+/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index e0b7b7a48a..efb277d347 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -25,17 +25,24 @@ config.status
libtool
.deps/
.dirstamp
-build-aux/
*.lo
*.o
*~
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h
-m4/libtool.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
-m4/lt~obsolete.m4
+build-aux/config.guess
+build-aux/config.sub
+build-aux/depcomp
+build-aux/install-sh
+build-aux/ltmain.sh
+build-aux/m4/libtool.m4
+build-aux/m4/lt~obsolete.m4
+build-aux/m4/ltoptions.m4
+build-aux/m4/ltsugar.m4
+build-aux/m4/ltversion.m4
+build-aux/missing
+build-aux/compile
+build-aux/test-driver
src/stamp-h1
libsecp256k1.pc
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index 4e1e73c39f..2c5c63adad 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -6,26 +6,31 @@ addons:
compiler:
- clang
- gcc
+cache:
+ directories:
+ - src/java/guava/
env:
global:
- - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no
+ - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no
+ - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- SCALAR=32bit RECOVERY=yes
- - SCALAR=32bit FIELD=32bit ECDH=yes
+ - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- SCALAR=64bit
- FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
- - FIELD=64bit ENDOMORPHISM=yes ECDH=yes
+ - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- - FIELD=32bit SCHNORR=yes
+ - FIELD=32bit SCHNORR=yes EXPERIMENTAL=yes
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
+ - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes EXPERIMENTAL=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
+ - BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes
matrix:
fast_finish: true
include:
@@ -55,9 +60,11 @@ matrix:
packages:
- gcc-multilib
- libgmp-dev:i386
+before_install: mkdir -p `dirname $GUAVA_JAR`
+install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
+ - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 7772a4e9d2..3d130bdcbd 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -1,6 +1,12 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
lib_LTLIBRARIES = libsecp256k1.la
+if USE_JNI
+JNI_LIB = libsecp256k1_jni.la
+noinst_LTLIBRARIES = $(JNI_LIB)
+else
+JNI_LIB =
+endif
include_HEADERS = include/secp256k1.h
noinst_HEADERS =
noinst_HEADERS += src/scalar.h
@@ -32,6 +38,7 @@ noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
+noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
@@ -45,35 +52,80 @@ noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
+if USE_EXTERNAL_ASM
+COMMON_LIB = libsecp256k1_common.la
+noinst_LTLIBRARIES = $(COMMON_LIB)
+else
+COMMON_LIB =
+endif
+
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
+if USE_EXTERNAL_ASM
+if USE_ASM_ARM
+libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
+endif
+endif
+
libsecp256k1_la_SOURCES = src/secp256k1.c
-libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
-libsecp256k1_la_LIBADD = $(SECP_LIBS)
+libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
+libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
+libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
+libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench_verify bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
-bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_sign_SOURCES = src/bench_sign.c
-bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
-bench_internal_LDADD = $(SECP_LIBS)
-bench_internal_CPPFLAGS = $(SECP_INCLUDES)
+bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
endif
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
-tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
+tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
tests_LDFLAGS = -static
TESTS = tests
endif
+JAVAROOT=src/java
+JAVAORG=org/bitcoin
+JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
+CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
+JAVA_FILES= \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
+ $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
+
+if USE_JNI
+
+$(JAVA_GUAVA):
+ @echo Guava is missing. Fetch it via: \
+ wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
+ @false
+
+.stamp-java: $(JAVA_FILES)
+ @echo Compiling $^
+ $(AM_V_at)$(CLASSPATH_ENV) javac $^
+ @touch $@
+
+if USE_TESTS
+
+check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
+ $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
+
+endif
+endif
+
if USE_ECMULT_STATIC_PRECOMPUTATION
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
@@ -93,10 +145,10 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h
src/ecmult_static_context.h: $(gen_context_BIN)
./$(gen_context_BIN)
-CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
+CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
endif
-EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
+EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 6095db4220..8cd344ea81 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -1,7 +1,7 @@
libsecp256k1
============
-[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1)
+[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
Optimized C library for EC operations on curve secp256k1.
diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
new file mode 100644
index 0000000000..1fc3627614
--- /dev/null
+++ b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
@@ -0,0 +1,140 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_JNI_INCLUDE_DIR
+#
+# DESCRIPTION
+#
+# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
+# programs using the JNI interface.
+#
+# JNI include directories are usually in the Java distribution. This is
+# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
+# that order. When this macro completes, a list of directories is left in
+# the variable JNI_INCLUDE_DIRS.
+#
+# Example usage follows:
+#
+# AX_JNI_INCLUDE_DIR
+#
+# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
+# do
+# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
+# done
+#
+# If you want to force a specific compiler:
+#
+# - at the configure.in level, set JAVAC=yourcompiler before calling
+# AX_JNI_INCLUDE_DIR
+#
+# - at the configure level, setenv JAVAC
+#
+# Note: This macro can work with the autoconf M4 macros for Java programs.
+# This particular macro is not part of the original set of macros.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 10
+
+AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
+AC_DEFUN([AX_JNI_INCLUDE_DIR],[
+
+JNI_INCLUDE_DIRS=""
+
+if test "x$JAVA_HOME" != x; then
+ _JTOPDIR="$JAVA_HOME"
+else
+ if test "x$JAVAC" = x; then
+ JAVAC=javac
+ fi
+ AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
+ if test "x$_ACJNI_JAVAC" = xno; then
+ AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
+ fi
+ _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
+ _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
+fi
+
+case "$host_os" in
+ darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ _JINC="$_JTOPDIR/Headers";;
+ *) _JINC="$_JTOPDIR/include";;
+esac
+_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
+_AS_ECHO_LOG([_JINC=$_JINC])
+
+# On Mac OS X 10.6.4, jni.h is a symlink:
+# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
+# -> ../../CurrentJDK/Headers/jni.h.
+
+AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
+[
+if test -f "$_JINC/jni.h"; then
+ ac_cv_jni_header_path="$_JINC"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+else
+ _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ if test -f "$_JTOPDIR/include/jni.h"; then
+ ac_cv_jni_header_path="$_JTOPDIR/include"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+ else
+ ac_cv_jni_header_path=none
+ fi
+fi
+])
+
+
+
+# get the likely subdirectories for system specific java includes
+case "$host_os" in
+bsdi*) _JNI_INC_SUBDIRS="bsdos";;
+darwin*) _JNI_INC_SUBDIRS="darwin";;
+freebsd*) _JNI_INC_SUBDIRS="freebsd";;
+linux*) _JNI_INC_SUBDIRS="linux genunix";;
+osf*) _JNI_INC_SUBDIRS="alpha";;
+solaris*) _JNI_INC_SUBDIRS="solaris";;
+mingw*) _JNI_INC_SUBDIRS="win32";;
+cygwin*) _JNI_INC_SUBDIRS="win32";;
+*) _JNI_INC_SUBDIRS="genunix";;
+esac
+
+if test "x$ac_cv_jni_header_path" != "xnone"; then
+ # add any subdirectories that are present
+ for JINCSUBDIR in $_JNI_INC_SUBDIRS
+ do
+ if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
+ fi
+ done
+fi
+])
+
+# _ACJNI_FOLLOW_SYMLINKS <path>
+# Follows symbolic links on <path>,
+# finally setting variable _ACJNI_FOLLOWED
+# ----------------------------------------
+AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
+# find the include directory relative to the javac executable
+_cur="$1"
+while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
+ AC_MSG_CHECKING([symlink for $_cur])
+ _slink=`ls -ld "$_cur" | sed 's/.* -> //'`
+ case "$_slink" in
+ /*) _cur="$_slink";;
+ # 'X' avoids triggering unwanted echo options.
+ *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
+ esac
+ AC_MSG_RESULT([$_cur])
+done
+_ACJNI_FOLLOWED="$_cur"
+])# _ACJNI
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index d41bbb6487..b25d8adb92 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -3,13 +3,13 @@ AC_DEFUN([SECP_INT128_CHECK],[
has_int128=$ac_cv_type___int128
])
-dnl
+dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
- __asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
+ __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
AC_MSG_RESULT([$has_64bit_asm])
])
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 786d8dcfb9..0743c36690 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -29,6 +29,7 @@ AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
+AM_PROG_AS
case $host_os in
*darwin*)
@@ -93,23 +94,33 @@ AC_ARG_ENABLE(tests,
[use_tests=$enableval],
[use_tests=yes])
+AC_ARG_ENABLE(openssl_tests,
+ AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
+ [enable_openssl_tests=$enableval],
+ [enable_openssl_tests=auto])
+
+AC_ARG_ENABLE(experimental,
+ AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
+ [use_experimental=$enableval],
+ [use_experimental=no])
+
AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
-
+
AC_ARG_ENABLE(ecmult_static_precomputation,
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
[use_ecmult_static_precomputation=$enableval],
- [use_ecmult_static_precomputation=yes])
+ [use_ecmult_static_precomputation=auto])
AC_ARG_ENABLE(module_ecdh,
- AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]),
+ AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
[enable_module_ecdh=$enableval],
[enable_module_ecdh=no])
AC_ARG_ENABLE(module_schnorr,
- AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]),
+ AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]),
[enable_module_schnorr=$enableval],
[enable_module_schnorr=no])
@@ -118,6 +129,11 @@ AC_ARG_ENABLE(module_recovery,
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
+AC_ARG_ENABLE(jni,
+ AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
+ [use_jni=$enableval],
+ [use_jni=auto])
+
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
@@ -127,8 +143,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
-AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto]
-[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto])
+AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
+[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
AC_CHECK_TYPES([__int128])
@@ -138,6 +154,34 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([no])
])
+if test x"$use_ecmult_static_precomputation" != x"no"; then
+ save_cross_compiling=$cross_compiling
+ cross_compiling=no
+ TEMP_CC="$CC"
+ CC="$CC_FOR_BUILD"
+ AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([], [return 0])],
+ [working_native_cc=yes],
+ [working_native_cc=no],[dnl])
+ CC="$TEMP_CC"
+ cross_compiling=$save_cross_compiling
+
+ if test x"$working_native_cc" = x"no"; then
+ set_precomp=no
+ if test x"$use_ecmult_static_precomputation" = x"yes"; then
+ AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ else
+ AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ fi
+ else
+ AC_MSG_RESULT([ok])
+ set_precomp=yes
+ fi
+else
+ set_precomp=no
+fi
+
if test x"$req_asm" = x"auto"; then
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" = x"yes"; then
@@ -155,6 +199,8 @@ else
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
+ arm)
+ ;;
no)
;;
*)
@@ -247,10 +293,15 @@ else
fi
# select assembly optimization
+use_external_asm=no
+
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
+arm)
+ use_external_asm=yes
+ ;;
no)
;;
*)
@@ -305,16 +356,51 @@ esac
if test x"$use_tests" = x"yes"; then
SECP_OPENSSL_CHECK
if test x"$has_openssl_ec" = x"yes"; then
- AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
- SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
- SECP_TEST_LIBS="$CRYPTO_LIBS"
-
- case $host in
- *mingw*)
- SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
- ;;
- esac
+ if test x"$enable_openssl_tests" != x"no"; then
+ AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
+ SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
+ SECP_TEST_LIBS="$CRYPTO_LIBS"
+
+ case $host in
+ *mingw*)
+ SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
+ ;;
+ esac
+ fi
+ else
+ if test x"$enable_openssl_tests" = x"yes"; then
+ AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
+ fi
+ fi
+else
+ if test x"$enable_openssl_tests" = x"yes"; then
+ AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
+ fi
+fi
+if test x"$use_jni" != x"no"; then
+ AX_JNI_INCLUDE_DIR
+ have_jni_dependencies=yes
+ if test x"$enable_module_schnorr" = x"no"; then
+ have_jni_dependencies=no
+ fi
+ if test x"$enable_module_ecdh" = x"no"; then
+ have_jni_dependencies=no
+ fi
+ if test "x$JNI_INCLUDE_DIRS" = "x"; then
+ have_jni_dependencies=no
+ fi
+ if test "x$have_jni_dependencies" = "xno"; then
+ if test x"$use_jni" = x"yes"; then
+ AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.])
+ fi
+ AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
+ use_jni=no
+ else
+ use_jni=yes
+ for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
+ JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
+ done
fi
fi
@@ -345,18 +431,43 @@ fi
AC_C_BIGENDIAN()
+if test x"$use_external_asm" = x"yes"; then
+ AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
+fi
+
+AC_MSG_NOTICE([Using static precomputation: $set_precomp])
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
-
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
+AC_MSG_NOTICE([Using jni: $use_jni])
+
+if test x"$enable_experimental" = x"yes"; then
+ AC_MSG_NOTICE([******])
+ AC_MSG_NOTICE([WARNING: experimental build])
+ AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
+ AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
+ AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
+ AC_MSG_NOTICE([******])
+else
+ if test x"$enable_module_schnorr" = x"yes"; then
+ AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$enable_module_ecdh" = x"yes"; then
+ AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$set_asm" = x"arm"; then
+ AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
+ fi
+fi
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
+AC_SUBST(JNI_INCLUDES)
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
@@ -367,6 +478,9 @@ AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_pr
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
+AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
+AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
+AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in
index 1c72dd0003..a0d006f113 100644
--- a/src/secp256k1/libsecp256k1.pc.in
+++ b/src/secp256k1/libsecp256k1.pc.in
@@ -5,7 +5,7 @@ includedir=@includedir@
Name: libsecp256k1
Description: Optimized C library for EC operations on curve secp256k1
-URL: https://github.com/bitcoin/secp256k1
+URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs.private: @SECP_LIBS@
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
new file mode 100644
index 0000000000..ab580c5b23
--- /dev/null
+++ b/src/secp256k1/sage/group_prover.sage
@@ -0,0 +1,322 @@
+# This code supports verifying group implementations which have branches
+# or conditional statements (like cmovs), by allowing each execution path
+# to independently set assumptions on input or intermediary variables.
+#
+# The general approach is:
+# * A constraint is a tuple of two sets of of symbolic expressions:
+# the first of which are required to evaluate to zero, the second of which
+# are required to evaluate to nonzero.
+# - A constraint is said to be conflicting if any of its nonzero expressions
+# is in the ideal with basis the zero expressions (in other words: when the
+# zero expressions imply that one of the nonzero expressions are zero).
+# * There is a list of laws that describe the intended behaviour, including
+# laws for addition and doubling. Each law is called with the symbolic point
+# coordinates as arguments, and returns:
+# - A constraint describing the assumptions under which it is applicable,
+# called "assumeLaw"
+# - A constraint describing the requirements of the law, called "require"
+# * Implementations are transliterated into functions that operate as well on
+# algebraic input points, and are called once per combination of branches
+# exectured. Each execution returns:
+# - A constraint describing the assumptions this implementation requires
+# (such as Z1=1), called "assumeFormula"
+# - A constraint describing the assumptions this specific branch requires,
+# but which is by construction guaranteed to cover the entire space by
+# merging the results from all branches, called "assumeBranch"
+# - The result of the computation
+# * All combinations of laws with implementation branches are tried, and:
+# - If the combination of assumeLaw, assumeFormula, and assumeBranch results
+# in a conflict, it means this law does not apply to this branch, and it is
+# skipped.
+# - For others, we try to prove the require constraints hold, assuming the
+# information in assumeLaw + assumeFormula + assumeBranch, and if this does
+# not succeed, we fail.
+# + To prove an expression is zero, we check whether it belongs to the
+# ideal with the assumed zero expressions as basis. This test is exact.
+# + To prove an expression is nonzero, we check whether each of its
+# factors is contained in the set of nonzero assumptions' factors.
+# This test is not exact, so various combinations of original and
+# reduced expressions' factors are tried.
+# - If we succeed, we print out the assumptions from assumeFormula that
+# weren't implied by assumeLaw already. Those from assumeBranch are skipped,
+# as we assume that all constraints in it are complementary with each other.
+#
+# Based on the sage verification scripts used in the Explicit-Formulas Database
+# by Tanja Lange and others, see http://hyperelliptic.org/EFD
+
+class fastfrac:
+ """Fractions over rings."""
+
+ def __init__(self,R,top,bot=1):
+ """Construct a fractional, given a ring, a numerator, and denominator."""
+ self.R = R
+ if parent(top) == ZZ or parent(top) == R:
+ self.top = R(top)
+ self.bot = R(bot)
+ elif top.__class__ == fastfrac:
+ self.top = top.top
+ self.bot = top.bot * bot
+ else:
+ self.top = R(numerator(top))
+ self.bot = R(denominator(top)) * bot
+
+ def iszero(self,I):
+ """Return whether this fraction is zero given an ideal."""
+ return self.top in I and self.bot not in I
+
+ def reduce(self,assumeZero):
+ zero = self.R.ideal(map(numerator, assumeZero))
+ return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
+
+ def __add__(self,other):
+ """Add two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top + self.bot * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __sub__(self,other):
+ """Subtract two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top - self.bot * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __neg__(self):
+ """Return the negation of a fraction."""
+ return fastfrac(self.R,-self.top,self.bot)
+
+ def __mul__(self,other):
+ """Multiply two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __rmul__(self,other):
+ """Multiply something else with a fraction."""
+ return self.__mul__(other)
+
+ def __div__(self,other):
+ """Divide two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top,self.bot * other)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
+ return NotImplemented
+
+ def __pow__(self,other):
+ """Compute a power of a fraction."""
+ if parent(other) == ZZ:
+ if other < 0:
+ # Negative powers require flipping top and bottom
+ return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))
+ else:
+ return fastfrac(self.R,self.top ^ other,self.bot ^ other)
+ return NotImplemented
+
+ def __str__(self):
+ return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))"
+ def __repr__(self):
+ return "%s" % self
+
+ def numerator(self):
+ return self.top
+
+class constraints:
+ """A set of constraints, consisting of zero and nonzero expressions.
+
+ Constraints can either be used to express knowledge or a requirement.
+
+ Both the fields zero and nonzero are maps from expressions to description
+ strings. The expressions that are the keys in zero are required to be zero,
+ and the expressions that are the keys in nonzero are required to be nonzero.
+
+ Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in
+ nonzero could be multiplied into a single key. This is often much less
+ efficient to work with though, so we keep them separate inside the
+ constraints. This allows higher-level code to do fast checks on the individual
+ nonzero elements, or combine them if needed for stronger checks.
+
+ We can't multiply the different zero elements, as it would suffice for one of
+ the factors to be zero, instead of all of them. Instead, the zero elements are
+ typically combined into an ideal first.
+ """
+
+ def __init__(self, **kwargs):
+ if 'zero' in kwargs:
+ self.zero = dict(kwargs['zero'])
+ else:
+ self.zero = dict()
+ if 'nonzero' in kwargs:
+ self.nonzero = dict(kwargs['nonzero'])
+ else:
+ self.nonzero = dict()
+
+ def negate(self):
+ return constraints(zero=self.nonzero, nonzero=self.zero)
+
+ def __add__(self, other):
+ zero = self.zero.copy()
+ zero.update(other.zero)
+ nonzero = self.nonzero.copy()
+ nonzero.update(other.nonzero)
+ return constraints(zero=zero, nonzero=nonzero)
+
+ def __str__(self):
+ return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero)
+
+ def __repr__(self):
+ return "%s" % self
+
+
+def conflicts(R, con):
+ """Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
+ zero = R.ideal(map(numerator, con.zero))
+ if 1 in zero:
+ return True
+ # First a cheap check whether any of the individual nonzero terms conflict on
+ # their own.
+ for nonzero in con.nonzero:
+ if nonzero.iszero(zero):
+ return True
+ # It can be the case that entries in the nonzero set do not individually
+ # conflict with the zero set, but their combination does. For example, knowing
+ # that either x or y is zero is equivalent to having x*y in the zero set.
+ # Having x or y individually in the nonzero set is not a conflict, but both
+ # simultaneously is, so that is the right thing to check for.
+ if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):
+ return True
+ return False
+
+
+def get_nonzero_set(R, assume):
+ """Calculate a simple set of nonzero expressions"""
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = set()
+ for nz in map(numerator, assume.nonzero):
+ for (f,n) in nz.factor():
+ nonzero.add(f)
+ rnz = zero.reduce(nz)
+ for (f,n) in rnz.factor():
+ nonzero.add(f)
+ return nonzero
+
+
+def prove_nonzero(R, exprs, assume):
+ """Check whether an expression is provably nonzero, given assumptions"""
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = get_nonzero_set(R, assume)
+ expl = set()
+ ok = True
+ for expr in exprs:
+ if numerator(expr) in zero:
+ return (False, [exprs[expr]])
+ allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
+ for (f, n) in allexprs.factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for (f, n) in zero.reduce(numerator(allexprs)).factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for expr in exprs:
+ for (f,n) in numerator(expr).factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for expr in exprs:
+ for (f,n) in zero.reduce(numerator(expr)).factor():
+ if f not in nonzero:
+ expl.add(exprs[expr])
+ if expl:
+ return (False, list(expl))
+ else:
+ return (True, None)
+
+
+def prove_zero(R, exprs, assume):
+ """Check whether all of the passed expressions are provably zero, given assumptions"""
+ r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
+ if not r:
+ return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = prod(x for x in assume.nonzero)
+ expl = []
+ for expr in exprs:
+ if not expr.iszero(zero):
+ expl.append(exprs[expr])
+ if not expl:
+ return (True, None)
+ return (False, expl)
+
+
+def describe_extra(R, assume, assumeExtra):
+ """Describe what assumptions are added, given existing assumptions"""
+ zerox = assume.zero.copy()
+ zerox.update(assumeExtra.zero)
+ zero = R.ideal(map(numerator, assume.zero))
+ zeroextra = R.ideal(map(numerator, zerox))
+ nonzero = get_nonzero_set(R, assume)
+ ret = set()
+ # Iterate over the extra zero expressions
+ for base in assumeExtra.zero:
+ if base not in zero:
+ add = []
+ for (f, n) in numerator(base).factor():
+ if f not in nonzero:
+ add += ["%s" % f]
+ if add:
+ ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
+ # Iterate over the extra nonzero expressions
+ for nz in assumeExtra.nonzero:
+ nzr = zeroextra.reduce(numerator(nz))
+ if nzr not in zeroextra:
+ for (f,n) in nzr.factor():
+ if zeroextra.reduce(f) not in nonzero:
+ ret.add("%s != 0" % zeroextra.reduce(f))
+ return ", ".join(x for x in ret)
+
+
+def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
+ """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions"""
+ assume = assumeLaw + assumeAssert + assumeBranch
+
+ if conflicts(R, assume):
+ # This formula does not apply
+ return None
+
+ describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
+
+ ok, msg = prove_zero(R, require.zero, assume)
+ if not ok:
+ return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
+
+ res, expl = prove_nonzero(R, require.nonzero, assume)
+ if not res:
+ return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
+
+ if describe != "":
+ return "OK (assuming %s)" % describe
+ else:
+ return "OK"
+
+
+def concrete_verify(c):
+ for k in c.zero:
+ if k != 0:
+ return (False, c.zero[k])
+ for k in c.nonzero:
+ if k == 0:
+ return (False, c.nonzero[k])
+ return (True, None)
diff --git a/src/secp256k1/sage/secp256k1.sage b/src/secp256k1/sage/secp256k1.sage
new file mode 100644
index 0000000000..a97e732f7f
--- /dev/null
+++ b/src/secp256k1/sage/secp256k1.sage
@@ -0,0 +1,306 @@
+# Test libsecp256k1' group operation implementations using prover.sage
+
+import sys
+
+load("group_prover.sage")
+load("weierstrass_prover.sage")
+
+def formula_secp256k1_gej_double_var(a):
+ """libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
+ rz = a.Z * a.Y
+ rz = rz * 2
+ t1 = a.X^2
+ t1 = t1 * 3
+ t2 = t1^2
+ t3 = a.Y^2
+ t3 = t3 * 2
+ t4 = t3^2
+ t4 = t4 * 2
+ t3 = t3 * a.X
+ rx = t3
+ rx = rx * 4
+ rx = -rx
+ rx = rx + t2
+ t2 = -t2
+ t3 = t3 * 6
+ t3 = t3 + t2
+ ry = t1 * t3
+ t2 = -t4
+ ry = ry + t2
+ return jacobianpoint(rx, ry, rz)
+
+def formula_secp256k1_gej_add_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_var"""
+ if branch == 0:
+ return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
+ if branch == 1:
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
+ z22 = b.Z^2
+ z12 = a.Z^2
+ u1 = a.X * z22
+ u2 = b.X * z12
+ s1 = a.Y * z22
+ s1 = s1 * b.Z
+ s2 = b.Y * z12
+ s2 = s2 * a.Z
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if branch == 2:
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r)
+ if branch == 3:
+ return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h2 * h
+ h = h * b.Z
+ rz = a.Z * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1"""
+ if branch == 0:
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
+ if branch == 1:
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
+ z12 = a.Z^2
+ u1 = a.X
+ u2 = b.X * z12
+ s1 = a.Y
+ s2 = b.Y * z12
+ s2 = s2 * a.Z
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if (branch == 2):
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
+ if (branch == 3):
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h * h2
+ rz = a.Z * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_zinv_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_zinv_var"""
+ bzinv = b.Z^(-1)
+ if branch == 0:
+ return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)
+ if branch == 1:
+ bzinv2 = bzinv^2
+ bzinv3 = bzinv2 * bzinv
+ rx = b.X * bzinv2
+ ry = b.Y * bzinv3
+ rz = 1
+ return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz))
+ azz = a.Z * bzinv
+ z12 = azz^2
+ u1 = a.X
+ u2 = b.X * z12
+ s1 = a.Y
+ s2 = b.Y * z12
+ s2 = s2 * azz
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if branch == 2:
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
+ if branch == 3:
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h * h2
+ rz = a.Z
+ rz = rz * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_ge"""
+ zeroes = {}
+ nonzeroes = {}
+ a_infinity = False
+ if (branch & 4) != 0:
+ nonzeroes.update({a.Infinity : 'a_infinite'})
+ a_infinity = True
+ else:
+ zeroes.update({a.Infinity : 'a_finite'})
+ zz = a.Z^2
+ u1 = a.X
+ u2 = b.X * zz
+ s1 = a.Y
+ s2 = b.Y * zz
+ s2 = s2 * a.Z
+ t = u1
+ t = t + u2
+ m = s1
+ m = m + s2
+ rr = t^2
+ m_alt = -u2
+ tt = u1 * m_alt
+ rr = rr + tt
+ degenerate = (branch & 3) == 3
+ if (branch & 1) != 0:
+ zeroes.update({m : 'm_zero'})
+ else:
+ nonzeroes.update({m : 'm_nonzero'})
+ if (branch & 2) != 0:
+ zeroes.update({rr : 'rr_zero'})
+ else:
+ nonzeroes.update({rr : 'rr_nonzero'})
+ rr_alt = s1
+ rr_alt = rr_alt * 2
+ m_alt = m_alt + u1
+ if not degenerate:
+ rr_alt = rr
+ m_alt = m
+ n = m_alt^2
+ q = n * t
+ n = n^2
+ if degenerate:
+ n = m
+ t = rr_alt^2
+ rz = a.Z * m_alt
+ infinity = False
+ if (branch & 8) != 0:
+ if not a_infinity:
+ infinity = True
+ zeroes.update({rz : 'r.z=0'})
+ else:
+ nonzeroes.update({rz : 'r.z!=0'})
+ rz = rz * 2
+ q = -q
+ t = t + q
+ rx = t
+ t = t * 2
+ t = t + q
+ t = t * rr_alt
+ t = t + n
+ ry = -t
+ rx = rx * 4
+ ry = ry * 4
+ if a_infinity:
+ rx = b.X
+ ry = b.Y
+ rz = 1
+ if infinity:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge_old(branch, a, b):
+ """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx"""
+ a_infinity = (branch & 1) != 0
+ zero = {}
+ nonzero = {}
+ if a_infinity:
+ nonzero.update({a.Infinity : 'a_infinite'})
+ else:
+ zero.update({a.Infinity : 'a_finite'})
+ zz = a.Z^2
+ u1 = a.X
+ u2 = b.X * zz
+ s1 = a.Y
+ s2 = b.Y * zz
+ s2 = s2 * a.Z
+ z = a.Z
+ t = u1
+ t = t + u2
+ m = s1
+ m = m + s2
+ n = m^2
+ q = n * t
+ n = n^2
+ rr = t^2
+ t = u1 * u2
+ t = -t
+ rr = rr + t
+ t = rr^2
+ rz = m * z
+ infinity = False
+ if (branch & 2) != 0:
+ if not a_infinity:
+ infinity = True
+ else:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity())
+ zero.update({rz : 'r.z=0'})
+ else:
+ nonzero.update({rz : 'r.z!=0'})
+ rz = rz * (0 if a_infinity else 2)
+ rx = t
+ q = -q
+ rx = rx + q
+ q = q * 3
+ t = t * 2
+ t = t + q
+ t = t * rr
+ t = t + n
+ ry = -t
+ rx = rx * (0 if a_infinity else 4)
+ ry = ry * (0 if a_infinity else 4)
+ t = b.X
+ t = t * (1 if a_infinity else 0)
+ rx = rx + t
+ t = b.Y
+ t = t * (1 if a_infinity else 0)
+ ry = ry + t
+ t = (1 if a_infinity else 0)
+ rz = rz + t
+ if infinity:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity())
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
+
+if __name__ == "__main__":
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
+
+ if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage
new file mode 100644
index 0000000000..03ef2ec901
--- /dev/null
+++ b/src/secp256k1/sage/weierstrass_prover.sage
@@ -0,0 +1,264 @@
+# Prover implementation for Weierstrass curves of the form
+# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws
+# operating on affine and Jacobian coordinates, including the point at infinity
+# represented by a 4th variable in coordinates.
+
+load("group_prover.sage")
+
+
+class affinepoint:
+ def __init__(self, x, y, infinity=0):
+ self.x = x
+ self.y = y
+ self.infinity = infinity
+ def __str__(self):
+ return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity)
+
+
+class jacobianpoint:
+ def __init__(self, x, y, z, infinity=0):
+ self.X = x
+ self.Y = y
+ self.Z = z
+ self.Infinity = infinity
+ def __str__(self):
+ return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity)
+
+
+def point_at_infinity():
+ return jacobianpoint(1, 1, 1, 1)
+
+
+def negate(p):
+ if p.__class__ == affinepoint:
+ return affinepoint(p.x, -p.y)
+ if p.__class__ == jacobianpoint:
+ return jacobianpoint(p.X, -p.Y, p.Z)
+ assert(False)
+
+
+def on_weierstrass_curve(A, B, p):
+ """Return a set of zero-expressions for an affine point to be on the curve"""
+ return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})
+
+
+def tangential_to_weierstrass_curve(A, B, p12, p3):
+ """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)"""
+ return constraints(zero={
+ (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'
+ })
+
+
+def colinear(p1, p2, p3):
+ """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear"""
+ return constraints(zero={
+ (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',
+ (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',
+ (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'
+ })
+
+
+def good_affine_point(p):
+ return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})
+
+
+def good_jacobian_point(p):
+ return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})
+
+
+def good_point(p):
+ return constraints(nonzero={p.Z^6 : 'nonzero_X'})
+
+
+def finite(p, *affine_fns):
+ con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})
+ if p.Z != 0:
+ return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)
+ else:
+ return con
+
+def infinite(p):
+ return constraints(nonzero={p.Infinity : 'infinite_point'})
+
+
+def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):
+ """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions"""
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(nonzero={pa.x - pb.x : 'different_x'}))
+ require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
+ colinear(pa, pb, negate(pc))))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):
+ """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions"""
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))
+ require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
+ tangential_to_weierstrass_curve(A, B, pa, negate(pc))))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))
+ require = infinite(pC)
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pb) +
+ infinite(pA) +
+ finite(pB))
+ require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ infinite(pB) +
+ finite(pA))
+ require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ infinite(pA) +
+ infinite(pB))
+ require = infinite(pC)
+ return (assumeLaw, require)
+
+
+laws_jacobian_weierstrass = {
+ 'add': law_jacobian_weierstrass_add,
+ 'double': law_jacobian_weierstrass_double,
+ 'add_opposite': law_jacobian_weierstrass_add_opposites,
+ 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,
+ 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,
+ 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab
+}
+
+
+def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
+ """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
+ F = Integers(p)
+ print "Formula %s on Z%i:" % (name, p)
+ points = []
+ for x in xrange(0, p):
+ for y in xrange(0, p):
+ point = affinepoint(F(x), F(y))
+ r, e = concrete_verify(on_weierstrass_curve(A, B, point))
+ if r:
+ points.append(point)
+
+ for za in xrange(1, p):
+ for zb in xrange(1, p):
+ for pa in points:
+ for pb in points:
+ for ia in xrange(2):
+ for ib in xrange(2):
+ pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
+ pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
+ for branch in xrange(0, branches):
+ assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
+ pC.X = F(pC.X)
+ pC.Y = F(pC.Y)
+ pC.Z = F(pC.Z)
+ pC.Infinity = F(pC.Infinity)
+ r, e = concrete_verify(assumeAssert + assumeBranch)
+ if r:
+ match = False
+ for key in laws_jacobian_weierstrass:
+ assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)
+ r, e = concrete_verify(assumeLaw)
+ if r:
+ if match:
+ print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
+ else:
+ match = True
+ r, e = concrete_verify(require)
+ if not r:
+ print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)
+ print
+
+
+def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
+ assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)
+ return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)
+
+def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
+ """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically"""
+ R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
+ lift = lambda x: fastfrac(R,x)
+ ax = lift(ax)
+ ay = lift(ay)
+ Az = lift(Az)
+ bx = lift(bx)
+ by = lift(by)
+ Bz = lift(Bz)
+ Ai = lift(Ai)
+ Bi = lift(Bi)
+
+ pa = affinepoint(ax, ay, Ai)
+ pb = affinepoint(bx, by, Bi)
+ pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)
+ pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)
+
+ res = {}
+
+ for key in laws_jacobian_weierstrass:
+ res[key] = []
+
+ print ("Formula " + name + ":")
+ count = 0
+ for branch in xrange(branches):
+ assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
+ pC.X = lift(pC.X)
+ pC.Y = lift(pC.Y)
+ pC.Z = lift(pC.Z)
+ pC.Infinity = lift(pC.Infinity)
+
+ for key in laws_jacobian_weierstrass:
+ res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
+
+ for key in res:
+ print " %s:" % key
+ val = res[key]
+ for x in val:
+ if x[0] is not None:
+ print " branch %i: %s" % (x[1], x[0])
+
+ print
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
new file mode 100644
index 0000000000..5df561f2fc
--- /dev/null
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -0,0 +1,919 @@
+@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
+/**********************************************************************
+ * Copyright (c) 2014 Wladimir J. van der Laan *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+/*
+ARM implementation of field_10x26 inner loops.
+
+Note:
+
+- To avoid unnecessary loads and make use of available registers, two
+ 'passes' have every time been interleaved, with the odd passes accumulating c' and d'
+ which will be added to c and d respectively in the the even passes
+
+*/
+
+ .syntax unified
+ .arch armv7-a
+ @ eabi attributes - see readelf -A
+ .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
+ .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
+ .eabi_attribute 10, 0 @ Tag_FP_arch = none
+ .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
+ .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
+ .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
+ .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
+ .text
+
+ @ Field constants
+ .set field_R0, 0x3d10
+ .set field_R1, 0x400
+ .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff
+
+ .align 2
+ .global secp256k1_fe_mul_inner
+ .type secp256k1_fe_mul_inner, %function
+ @ Arguments:
+ @ r0 r Restrict: can overlap with a, not with b
+ @ r1 a
+ @ r2 b
+ @ Stack (total 4+10*4 = 44)
+ @ sp + #0 saved 'r' pointer
+ @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
+secp256k1_fe_mul_inner:
+ stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
+ sub sp, sp, #48 @ frame=44 + alignment
+ str r0, [sp, #0] @ save result address, we need it only at the end
+
+ /******************************************
+ * Main computation code.
+ ******************************************
+
+ Allocation:
+ r0,r14,r7,r8 scratch
+ r1 a (pointer)
+ r2 b (pointer)
+ r3:r4 c
+ r5:r6 d
+ r11:r12 c'
+ r9:r10 d'
+
+ Note: do not write to r[] here, it may overlap with a[]
+ */
+
+ /* A - interleaved with B */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #9*4] @ b[9]
+ ldr r0, [r1, #1*4] @ a[1]
+ umull r5, r6, r7, r8 @ d = a[0] * b[9]
+ ldr r14, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r8 @ d' = a[1] * b[9]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r5, r6, r0, r14 @ d += a[1] * b[8]
+ ldr r8, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r14 @ d' += a[2] * b[8]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r5, r6, r7, r8 @ d += a[2] * b[7]
+ ldr r14, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r8 @ d' += a[3] * b[7]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r5, r6, r0, r14 @ d += a[3] * b[6]
+ ldr r8, [r2, #5*4] @ b[5]
+ umlal r9, r10, r7, r14 @ d' += a[4] * b[6]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r5, r6, r7, r8 @ d += a[4] * b[5]
+ ldr r14, [r2, #4*4] @ b[4]
+ umlal r9, r10, r0, r8 @ d' += a[5] * b[5]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r5, r6, r0, r14 @ d += a[5] * b[4]
+ ldr r8, [r2, #3*4] @ b[3]
+ umlal r9, r10, r7, r14 @ d' += a[6] * b[4]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r8 @ d += a[6] * b[3]
+ ldr r14, [r2, #2*4] @ b[2]
+ umlal r9, r10, r0, r8 @ d' += a[7] * b[3]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r14 @ d += a[7] * b[2]
+ ldr r8, [r2, #1*4] @ b[1]
+ umlal r9, r10, r7, r14 @ d' += a[8] * b[2]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r8 @ d += a[8] * b[1]
+ ldr r14, [r2, #0*4] @ b[0]
+ umlal r9, r10, r0, r8 @ d' += a[9] * b[1]
+ ldr r7, [r1, #0*4] @ a[0]
+ umlal r5, r6, r0, r14 @ d += a[9] * b[0]
+ @ r7,r14 used in B
+
+ bic r0, r5, field_not_M @ t9 = d & M
+ str r0, [sp, #4 + 4*9]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ /* B */
+ umull r3, r4, r7, r14 @ c = a[0] * b[0]
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u0 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u0 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t0 = c & M
+ str r14, [sp, #4 + 0*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u0 * R1
+ umlal r3, r4, r0, r14
+
+ /* C - interleaved with D */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #2*4] @ b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[2]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[1]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[0]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r5, r6, r7, r14 @ d += a[2] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[3] * b[9]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r5, r6, r0, r8 @ d += a[3] * b[8]
+ ldr r14, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r8 @ d' += a[4] * b[8]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r5, r6, r7, r14 @ d += a[4] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r14 @ d' += a[5] * b[7]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r5, r6, r0, r8 @ d += a[5] * b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umlal r9, r10, r7, r8 @ d' += a[6] * b[6]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r14 @ d += a[6] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r9, r10, r0, r14 @ d' += a[7] * b[5]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r8 @ d += a[7] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[4]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r9, r10, r0, r14 @ d' += a[9] * b[3]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[2]
+
+ bic r0, r5, field_not_M @ u1 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u1 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t1 = c & M
+ str r14, [sp, #4 + 1*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u1 * R1
+ umlal r3, r4, r0, r14
+
+ /* D */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u2 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u2 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t2 = c & M
+ str r14, [sp, #4 + 2*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u2 * R1
+ umlal r3, r4, r0, r14
+
+ /* E - interleaved with F */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #4*4] @ b[4]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[4]
+ ldr r8, [r2, #3*4] @ b[3]
+ umlal r3, r4, r7, r8 @ c += a[0] * b[3]
+ ldr r7, [r1, #1*4] @ a[1]
+ umlal r11, r12, r7, r8 @ c' += a[1] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r3, r4, r7, r8 @ c += a[1] * b[2]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[2]
+ ldr r8, [r2, #1*4] @ b[1]
+ umlal r3, r4, r7, r8 @ c += a[2] * b[1]
+ ldr r7, [r1, #3*4] @ a[3]
+ umlal r11, r12, r7, r8 @ c' += a[3] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r3, r4, r7, r8 @ c += a[3] * b[0]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[0]
+ ldr r8, [r2, #9*4] @ b[9]
+ umlal r5, r6, r7, r8 @ d += a[4] * b[9]
+ ldr r7, [r1, #5*4] @ a[5]
+ umull r9, r10, r7, r8 @ d' = a[5] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umlal r5, r6, r7, r8 @ d += a[5] * b[8]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r9, r10, r7, r8 @ d' += a[6] * b[8]
+ ldr r8, [r2, #7*4] @ b[7]
+ umlal r5, r6, r7, r8 @ d += a[6] * b[7]
+ ldr r7, [r1, #7*4] @ a[7]
+ umlal r9, r10, r7, r8 @ d' += a[7] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r5, r6, r7, r8 @ d += a[7] * b[6]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[6]
+ ldr r8, [r2, #5*4] @ b[5]
+ umlal r5, r6, r7, r8 @ d += a[8] * b[5]
+ ldr r7, [r1, #9*4] @ a[9]
+ umlal r9, r10, r7, r8 @ d' += a[9] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r5, r6, r7, r8 @ d += a[9] * b[4]
+
+ bic r0, r5, field_not_M @ u3 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u3 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t3 = c & M
+ str r14, [sp, #4 + 3*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u3 * R1
+ umlal r3, r4, r0, r14
+
+ /* F */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u4 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u4 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t4 = c & M
+ str r14, [sp, #4 + 4*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u4 * R1
+ umlal r3, r4, r0, r14
+
+ /* G - interleaved with H */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #6*4] @ b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[6]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[5]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[4]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r3, r4, r7, r14 @ c += a[2] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r11, r12, r0, r14 @ c' += a[3] * b[3]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r3, r4, r0, r8 @ c += a[3] * b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[2]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r3, r4, r7, r14 @ c += a[4] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[5] * b[1]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r3, r4, r0, r8 @ c += a[5] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[6] * b[0]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r14 @ d += a[6] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[7] * b[9]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r8 @ d += a[7] * b[8]
+ ldr r14, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[8]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r14 @ d' += a[9] * b[7]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[6]
+
+ bic r0, r5, field_not_M @ u5 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u5 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t5 = c & M
+ str r14, [sp, #4 + 5*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u5 * R1
+ umlal r3, r4, r0, r14
+
+ /* H */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u6 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u6 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t6 = c & M
+ str r14, [sp, #4 + 6*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u6 * R1
+ umlal r3, r4, r0, r14
+
+ /* I - interleaved with J */
+ ldr r8, [r2, #8*4] @ b[8]
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r14, [r2, #7*4] @ b[7]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[8]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[7]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[6]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r3, r4, r7, r14 @ c += a[2] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r11, r12, r0, r14 @ c' += a[3] * b[5]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r3, r4, r0, r8 @ c += a[3] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[4]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r3, r4, r7, r14 @ c += a[4] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r11, r12, r0, r14 @ c' += a[5] * b[3]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r3, r4, r0, r8 @ c += a[5] * b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umlal r11, r12, r7, r8 @ c' += a[6] * b[2]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r3, r4, r7, r14 @ c += a[6] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[7] * b[1]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r3, r4, r0, r8 @ c += a[7] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[8] * b[0]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[9] * b[9]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[8]
+
+ bic r0, r5, field_not_M @ u7 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u7 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t7 = c & M
+ str r14, [sp, #4 + 7*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u7 * R1
+ umlal r3, r4, r0, r14
+
+ /* J */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u8 = d & M
+ str r0, [sp, #4 + 8*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u8 * R0
+ umlal r3, r4, r0, r14
+
+ /******************************************
+ * compute and write back result
+ ******************************************
+ Allocation:
+ r0 r
+ r3:r4 c
+ r5:r6 d
+ r7 t0
+ r8 t1
+ r9 t2
+ r11 u8
+ r12 t9
+ r1,r2,r10,r14 scratch
+
+ Note: do not read from a[] after here, it may overlap with r[]
+ */
+ ldr r0, [sp, #0]
+ add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
+ ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
+ add r1, r0, #3*4
+ stmia r1, {r2,r7,r8,r9,r10}
+
+ bic r2, r3, field_not_M @ r[8] = c & M
+ str r2, [r0, #8*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u8 * R1
+ umlal r3, r4, r11, r14
+ movw r14, field_R0 @ c += d * R0
+ umlal r3, r4, r5, r14
+ adds r3, r3, r12 @ c += t9
+ adc r4, r4, #0
+
+ add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
+ ldmia r1, {r7,r8,r9}
+
+ ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
+ str r2, [r0, #9*4]
+ mov r3, r3, lsr #22 @ c >>= 22
+ orr r3, r3, r4, asl #10
+ mov r4, r4, lsr #22
+ movw r14, field_R1 << 4 @ c += d * (R1 << 4)
+ umlal r3, r4, r5, r14
+
+ movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
+ umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
+ adds r5, r5, r7 @ d.lo += t0
+ mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
+ adc r6, r6, 0 @ d.hi += carry
+
+ bic r2, r5, field_not_M @ r[0] = d & M
+ str r2, [r0, #0*4]
+
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
+ umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
+ adds r5, r5, r8 @ d.lo += t1
+ adc r6, r6, #0 @ d.hi += carry
+ adds r5, r5, r1 @ d.lo += tmp.lo
+ mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
+ adc r6, r6, r2 @ d.hi += carry + tmp.hi
+
+ bic r2, r5, field_not_M @ r[1] = d & M
+ str r2, [r0, #1*4]
+ mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
+ orr r5, r5, r6, asl #6
+
+ add r5, r5, r9 @ d += t2
+ str r5, [r0, #2*4] @ r[2] = d
+
+ add sp, sp, #48
+ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+ .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner
+
+ .align 2
+ .global secp256k1_fe_sqr_inner
+ .type secp256k1_fe_sqr_inner, %function
+ @ Arguments:
+ @ r0 r Can overlap with a
+ @ r1 a
+ @ Stack (total 4+10*4 = 44)
+ @ sp + #0 saved 'r' pointer
+ @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
+secp256k1_fe_sqr_inner:
+ stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
+ sub sp, sp, #48 @ frame=44 + alignment
+ str r0, [sp, #0] @ save result address, we need it only at the end
+ /******************************************
+ * Main computation code.
+ ******************************************
+
+ Allocation:
+ r0,r14,r2,r7,r8 scratch
+ r1 a (pointer)
+ r3:r4 c
+ r5:r6 d
+ r11:r12 c'
+ r9:r10 d'
+
+ Note: do not write to r[] here, it may overlap with a[]
+ */
+ /* A interleaved with B */
+ ldr r0, [r1, #1*4] @ a[1]*2
+ ldr r7, [r1, #0*4] @ a[0]
+ mov r0, r0, asl #1
+ ldr r14, [r1, #9*4] @ a[9]
+ umull r3, r4, r7, r7 @ c = a[0] * a[0]
+ ldr r8, [r1, #8*4] @ a[8]
+ mov r7, r7, asl #1
+ umull r5, r6, r7, r14 @ d = a[0]*2 * a[9]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9]
+ ldr r14, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8]
+ mov r7, r7, asl #1
+ ldr r0, [r1, #3*4] @ a[3]*2
+ umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8]
+ ldr r8, [r1, #6*4] @ a[6]
+ umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7]
+ mov r0, r0, asl #1
+ ldr r7, [r1, #4*4] @ a[4]*2
+ umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7]
+ ldr r14, [r1, #5*4] @ a[5]
+ mov r7, r7, asl #1
+ umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
+ umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
+ umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
+ umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
+
+ bic r0, r5, field_not_M @ t9 = d & M
+ str r0, [sp, #4 + 9*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ /* B */
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u0 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u0 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t0 = c & M
+ str r14, [sp, #4 + 0*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u0 * R1
+ umlal r3, r4, r0, r14
+
+ /* C interleaved with D */
+ ldr r0, [r1, #0*4] @ a[0]*2
+ ldr r14, [r1, #1*4] @ a[1]
+ mov r0, r0, asl #1
+ ldr r8, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
+ mov r7, r8, asl #1 @ a[2]*2
+ umull r11, r12, r14, r14 @ c' = a[1] * a[1]
+ ldr r14, [r1, #9*4] @ a[9]
+ umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
+ ldr r0, [r1, #3*4] @ a[3]*2
+ ldr r8, [r1, #8*4] @ a[8]
+ umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
+ mov r0, r0, asl #1
+ ldr r7, [r1, #4*4] @ a[4]*2
+ umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
+ ldr r14, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
+ mov r7, r7, asl #1
+ ldr r0, [r1, #5*4] @ a[5]*2
+ umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
+ ldr r8, [r1, #6*4] @ a[6]
+ mov r0, r0, asl #1
+ umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
+ umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
+ umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
+ umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
+
+ bic r0, r5, field_not_M @ u1 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u1 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t1 = c & M
+ str r14, [sp, #4 + 1*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u1 * R1
+ umlal r3, r4, r0, r14
+
+ /* D */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u2 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u2 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t2 = c & M
+ str r14, [sp, #4 + 2*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u2 * R1
+ umlal r3, r4, r0, r14
+
+ /* E interleaved with F */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ ldr r14, [r1, #2*4] @ a[2]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #3*4] @ a[3]
+ ldr r2, [r1, #4*4]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
+ mov r2, r2, asl #1 @ a[4]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
+ ldr r8, [r1, #9*4] @ a[9]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
+ ldr r0, [r1, #5*4] @ a[5]*2
+ umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
+ ldr r14, [r1, #8*4] @ a[8]
+ mov r0, r0, asl #1
+ umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
+ ldr r7, [r1, #6*4] @ a[6]*2
+ umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
+ umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
+ umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
+ umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
+
+ bic r0, r5, field_not_M @ u3 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u3 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t3 = c & M
+ str r14, [sp, #4 + 3*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u3 * R1
+ umlal r3, r4, r0, r14
+
+ /* F */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u4 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u4 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t4 = c & M
+ str r14, [sp, #4 + 4*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u4 * R1
+ umlal r3, r4, r0, r14
+
+ /* G interleaved with H */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ mov r7, r7, asl #1
+ ldr r8, [r1, #5*4] @ a[5]
+ ldr r2, [r1, #6*4] @ a[6]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
+ ldr r14, [r1, #4*4] @ a[4]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #3*4] @ a[3]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
+ mov r0, r2, asl #1 @ a[6]*2
+ umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
+ ldr r14, [r1, #9*4] @ a[9]
+ umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
+ ldr r7, [r1, #7*4] @ a[7]*2
+ umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
+ umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
+ umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
+ umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
+
+ bic r0, r5, field_not_M @ u5 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u5 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t5 = c & M
+ str r14, [sp, #4 + 5*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u5 * R1
+ umlal r3, r4, r0, r14
+
+ /* H */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u6 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u6 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t6 = c & M
+ str r14, [sp, #4 + 6*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u6 * R1
+ umlal r3, r4, r0, r14
+
+ /* I interleaved with J */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ mov r7, r7, asl #1
+ ldr r8, [r1, #7*4] @ a[7]
+ ldr r2, [r1, #8*4] @ a[8]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
+ ldr r14, [r1, #6*4] @ a[6]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
+ ldr r8, [r1, #5*4] @ a[5]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
+ ldr r0, [r1, #3*4] @ a[3]*2
+ mov r7, r7, asl #1
+ umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
+ ldr r14, [r1, #4*4] @ a[4]
+ mov r0, r0, asl #1
+ umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
+ mov r2, r2, asl #1 @ a[8]*2
+ umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
+ umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
+ umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
+ ldr r8, [r1, #9*4] @ a[9]
+ umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
+ @ r8 will be used in J
+
+ bic r0, r5, field_not_M @ u7 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u7 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t7 = c & M
+ str r14, [sp, #4 + 7*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u7 * R1
+ umlal r3, r4, r0, r14
+
+ /* J */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ umlal r5, r6, r8, r8 @ d += a[9] * a[9]
+
+ bic r0, r5, field_not_M @ u8 = d & M
+ str r0, [sp, #4 + 8*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u8 * R0
+ umlal r3, r4, r0, r14
+
+ /******************************************
+ * compute and write back result
+ ******************************************
+ Allocation:
+ r0 r
+ r3:r4 c
+ r5:r6 d
+ r7 t0
+ r8 t1
+ r9 t2
+ r11 u8
+ r12 t9
+ r1,r2,r10,r14 scratch
+
+ Note: do not read from a[] after here, it may overlap with r[]
+ */
+ ldr r0, [sp, #0]
+ add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
+ ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
+ add r1, r0, #3*4
+ stmia r1, {r2,r7,r8,r9,r10}
+
+ bic r2, r3, field_not_M @ r[8] = c & M
+ str r2, [r0, #8*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u8 * R1
+ umlal r3, r4, r11, r14
+ movw r14, field_R0 @ c += d * R0
+ umlal r3, r4, r5, r14
+ adds r3, r3, r12 @ c += t9
+ adc r4, r4, #0
+
+ add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
+ ldmia r1, {r7,r8,r9}
+
+ ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
+ str r2, [r0, #9*4]
+ mov r3, r3, lsr #22 @ c >>= 22
+ orr r3, r3, r4, asl #10
+ mov r4, r4, lsr #22
+ movw r14, field_R1 << 4 @ c += d * (R1 << 4)
+ umlal r3, r4, r5, r14
+
+ movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
+ umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
+ adds r5, r5, r7 @ d.lo += t0
+ mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
+ adc r6, r6, 0 @ d.hi += carry
+
+ bic r2, r5, field_not_M @ r[0] = d & M
+ str r2, [r0, #0*4]
+
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
+ umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
+ adds r5, r5, r8 @ d.lo += t1
+ adc r6, r6, #0 @ d.hi += carry
+ adds r5, r5, r1 @ d.lo += tmp.lo
+ mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
+ adc r6, r6, r2 @ d.hi += carry + tmp.hi
+
+ bic r2, r5, field_not_M @ r[1] = d & M
+ str r2, [r0, #1*4]
+ mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
+ orr r5, r5, r6, asl #6
+
+ add r5, r5, r9 @ d += t2
+ str r5, [r0, #2*4] @ r[2] = d
+
+ add sp, sp, #48
+ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+ .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
+
diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c
index 5a7c6376e0..cde5e2dbb4 100644
--- a/src/secp256k1/src/bench_ecdh.c
+++ b/src/secp256k1/src/bench_ecdh.c
@@ -28,7 +28,8 @@ static void bench_ecdh_setup(void* arg) {
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
};
- data->ctx = secp256k1_context_create(0);
+ /* create a context with no capabilities */
+ data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
for (i = 0; i < 32; i++) {
data->scalar[i] = i + 1;
}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index 7809f5f8cf..0809f77bda 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -181,12 +181,12 @@ void bench_field_inverse_var(void* arg) {
}
}
-void bench_field_sqrt_var(void* arg) {
+void bench_field_sqrt(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_sqrt(&data->fe_x, &data->fe_x);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
@@ -227,6 +227,15 @@ void bench_group_add_affine_var(void* arg) {
}
}
+void bench_group_jacobi_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_gej_has_quad_y_var(&data->gej_x);
+ }
+}
+
void bench_ecmult_wnaf(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
@@ -299,6 +308,21 @@ void bench_context_sign(void* arg) {
}
}
+#ifndef USE_NUM_NONE
+void bench_num_jacobi(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+ secp256k1_num nx, norder;
+
+ secp256k1_scalar_get_num(&nx, &data->scalar_x);
+ secp256k1_scalar_order_get_num(&norder);
+ secp256k1_scalar_get_num(&norder, &data->scalar_y);
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_num_jacobi(&nx, &norder);
+ }
+}
+#endif
int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
@@ -333,12 +357,13 @@ int main(int argc, char **argv) {
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, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, 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, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
@@ -350,5 +375,8 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
+#ifndef USE_NUM_NONE
+ if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
+#endif
return 0;
}
diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c
index 5718320cda..418defa0aa 100644
--- a/src/secp256k1/src/bench_verify.c
+++ b/src/secp256k1/src/bench_verify.c
@@ -11,6 +11,12 @@
#include "util.h"
#include "bench.h"
+#ifdef ENABLE_OPENSSL_TESTS
+#include <openssl/bn.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+#endif
+
typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
@@ -19,6 +25,9 @@ typedef struct {
size_t siglen;
unsigned char pubkey[33];
size_t pubkeylen;
+#ifdef ENABLE_OPENSSL_TESTS
+ EC_GROUP* ec_group;
+#endif
} benchmark_verify_t;
static void benchmark_verify(void* arg) {
@@ -40,6 +49,36 @@ static void benchmark_verify(void* arg) {
}
}
+#ifdef ENABLE_OPENSSL_TESTS
+static void benchmark_verify_openssl(void* arg) {
+ int i;
+ benchmark_verify_t* data = (benchmark_verify_t*)arg;
+
+ 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);
+ {
+ EC_KEY *pkey = EC_KEY_new();
+ const unsigned char *pubkey = &data->pubkey[0];
+ int result;
+
+ CHECK(pkey != NULL);
+ result = EC_KEY_set_group(pkey, data->ec_group);
+ CHECK(result);
+ result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL;
+ CHECK(result);
+ result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0);
+ CHECK(result);
+ EC_KEY_free(pkey);
+ }
+ data->sig[data->siglen - 1] ^= (i & 0xFF);
+ data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
+ data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
+ }
+}
+#endif
+
int main(void) {
int i;
secp256k1_pubkey pubkey;
@@ -62,6 +101,11 @@ int main(void) {
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
+#ifdef ENABLE_OPENSSL_TESTS
+ data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
+ run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
+ EC_GROUP_free(data.ec_group);
+#endif
secp256k1_context_destroy(data.ctx);
return 0;
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 90ac94770e..7a6a25318c 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -58,22 +58,24 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
int global_sign;
int skew = 0;
int word = 0;
+
/* 1 2 3 */
int u_last;
int u;
-#ifdef USE_ENDOMORPHISM
int flip;
int bit;
secp256k1_scalar neg_s;
int not_neg_one;
- /* If we are using the endomorphism, we cannot handle even numbers by negating
- * them, since we are working with 128-bit numbers whose negations would be 256
- * bits, eliminating the performance advantage. Instead we use a technique from
+ /* Note that we cannot handle even numbers by negating them to be odd, as is
+ * done in other implementations, since if our scalars were specified to have
+ * width < 256 for performance reasons, their negations would have width 256
+ * and we'd lose any performance benefit. Instead, we use a technique from
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
- * or 2 (for odd) to the number we are encoding, then compensating after the
- * multiplication. */
- /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */
+ * or 2 (for odd) to the number we are encoding, returning a skew value indicating
+ * this, and having the caller compensate after doing the multiplication. */
+
+ /* Negative numbers will be negated to keep their bit representation below the maximum width */
flip = secp256k1_scalar_is_high(&s);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ (s.d[0] & 1);
@@ -89,11 +91,6 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
global_sign = secp256k1_scalar_cond_negate(&s, flip);
global_sign *= not_neg_one * 2 - 1;
skew = 1 << bit;
-#else
- /* Otherwise, we just negate to force oddness */
- int is_even = secp256k1_scalar_is_even(&s);
- global_sign = secp256k1_scalar_cond_negate(&s, is_even);
-#endif
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
@@ -127,15 +124,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_ge tmpa;
secp256k1_fe Z;
+ int skew_1;
+ int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
#ifdef USE_ENDOMORPHISM
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
- int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
- int skew_1;
int skew_lam;
secp256k1_scalar q_1, q_lam;
-#else
- int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)];
#endif
int i;
@@ -145,18 +140,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
#ifdef USE_ENDOMORPHISM
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
- /* no need for zero correction when using endomorphism since even
- * numbers have one added to them anyway */
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
#else
- int is_zero = secp256k1_scalar_is_zero(scalar);
- /* the wNAF ladder cannot handle zero, so bump this to one .. we will
- * correct the result after the fact */
- sc.d[0] += is_zero;
- VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc));
-
- secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1);
+ skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
#endif
/* Calculate odd multiples of a.
@@ -179,21 +166,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
-#ifdef USE_ENDOMORPHISM
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
-
+#ifdef USE_ENDOMORPHISM
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
secp256k1_gej_add_ge(r, r, &tmpa);
-#else
- i = wnaf[WNAF_SIZE(WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
- secp256k1_gej_set_ge(r, &tmpa);
#endif
/* remaining loop iterations */
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
@@ -202,59 +183,57 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
for (j = 0; j < WINDOW_A - 1; ++j) {
secp256k1_gej_double_nonzero(r, r, NULL);
}
-#ifdef USE_ENDOMORPHISM
+
n = wnaf_1[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
-
+#ifdef USE_ENDOMORPHISM
n = wnaf_lam[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
-#else
- n = wnaf[i];
- VERIFY_CHECK(n != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
- secp256k1_gej_add_ge(r, r, &tmpa);
#endif
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
-#ifdef USE_ENDOMORPHISM
{
/* Correct for wNAF skew */
secp256k1_ge correction = *a;
secp256k1_ge_storage correction_1_stor;
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage correction_lam_stor;
+#endif
secp256k1_ge_storage a2_stor;
secp256k1_gej tmpj;
secp256k1_gej_set_ge(&tmpj, &correction);
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
secp256k1_ge_set_gej(&correction, &tmpj);
secp256k1_ge_to_storage(&correction_1_stor, a);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_to_storage(&correction_lam_stor, a);
+#endif
secp256k1_ge_to_storage(&a2_stor, &correction);
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
+#endif
/* Apply the correction */
secp256k1_ge_from_storage(&correction, &correction_1_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_ge_mul_lambda(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
- }
-#else
- /* correct for zero */
- r->infinity |= is_zero;
#endif
+ }
}
#endif
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index e6e5f47188..81ae08e100 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -11,6 +11,8 @@
#include "scalar.h"
#include "ecmult.h"
+#include <string.h>
+
/* optimal for 128-bit and 256-bit exponents. */
#define WINDOW_A 5
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 2d52af5e36..c5ba074244 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -57,6 +57,9 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a);
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
/** Compare two field elements. Requires magnitude-1 inputs. */
+static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
+
+/** Same as secp256k1_fe_equal, but may be variable time. */
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
/** Compare two field elements. Requires both inputs to be normalized */
@@ -92,7 +95,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
* The input's magnitude can be at most 8. The output magnitude is 1 (but not
* guaranteed to be normalized). The result in r will always be a square
* itself. */
-static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a);
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
+
+/** Checks whether a field element is a quadratic residue. */
+static int secp256k1_fe_is_quad_var(const secp256k1_fe *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 212cc5396a..7b8c079608 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
-#include <stdio.h>
-#include <string.h>
#include "util.h"
#include "num.h"
#include "field.h"
@@ -429,6 +427,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
#endif
}
+#if defined(USE_EXTERNAL_ASM)
+
+/* External assembler implementation */
+void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b);
+void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
+
+#else
+
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
#else
@@ -1037,7 +1043,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
VERIFY_BITS(r[2], 27);
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
-
+#endif
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index b31e24ab81..7a99eb21ec 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -11,7 +11,6 @@
#include "libsecp256k1-config.h"
#endif
-#include <string.h>
#include "util.h"
#include "num.h"
#include "field.h"
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 9280bb5ea2..0bf22bdd3e 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += d * R + t3;;
+ c += d * R + t3;
VERIFY_BITS(c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
@@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
VERIFY_BITS(c, 63);
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += d * R + t3;;
+ c += d * R + t3;
VERIFY_BITS(c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 77f4aae2f9..52cd902eb3 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -21,6 +21,13 @@
#error "Please select field implementation"
#endif
+SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe na;
+ secp256k1_fe_negate(&na, a, 1);
+ secp256k1_fe_add(&na, b);
+ return secp256k1_fe_normalizes_to_zero(&na);
+}
+
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
secp256k1_fe_negate(&na, a, 1);
@@ -28,7 +35,7 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const
return secp256k1_fe_normalizes_to_zero_var(&na);
}
-static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
/** Given that p is congruent to 3 mod 4, we can compute the square root of
* a mod p as the (p+1)/4'th power of a.
*
@@ -123,7 +130,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
/* Check that a square root was actually calculated */
secp256k1_fe_sqr(&t1, r);
- return secp256k1_fe_equal_var(&t1, a);
+ return secp256k1_fe_equal(&t1, a);
}
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
@@ -280,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k
r[0] = u;
}
+static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
+#ifndef USE_NUM_NONE
+ unsigned char b[32];
+ secp256k1_num n;
+ secp256k1_num 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
+ };
+
+ secp256k1_fe c = *a;
+ secp256k1_fe_normalize_var(&c);
+ secp256k1_fe_get_b32(b, &c);
+ secp256k1_num_set_bin(&n, b, 32);
+ secp256k1_num_set_bin(&m, prime, 32);
+ return secp256k1_num_jacobi(&n, &m) >= 0;
+#else
+ secp256k1_fe r;
+ return secp256k1_fe_sqrt(&r, a);
+#endif
+}
+
#endif
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index ebfe1ca70c..d515716744 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -47,7 +47,7 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
* and a Y coordinate that is a quadratic residue modulo p. The return value
* is true iff a coordinate with the given X coordinate exists.
*/
-static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x);
+static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x);
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
* for Y. Return value indicates whether the result is valid. */
@@ -94,6 +94,9 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
/** Check whether a group element is the point at infinity. */
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
+/** Check whether a group element's y coordinate is a quadratic residue. */
+static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
+
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
* a may not be zero. Constant time. */
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 42e2f6e6eb..3e9c4c410d 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_GROUP_IMPL_H_
#define _SECP256K1_GROUP_IMPL_H_
-#include <string.h>
-
#include "num.h"
#include "field.h"
#include "group.h"
@@ -165,7 +163,7 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
secp256k1_fe_clear(&r->y);
}
-static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
+static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
secp256k1_fe x2, x3, c;
r->x = *x;
secp256k1_fe_sqr(&x2, x);
@@ -173,11 +171,11 @@ static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
r->infinity = 0;
secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&c, &x3);
- return secp256k1_fe_sqrt_var(&r->y, &c);
+ return secp256k1_fe_sqrt(&r->y, &c);
}
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
- if (!secp256k1_ge_set_xquad_var(r, x)) {
+ if (!secp256k1_ge_set_xquad(r, x)) {
return 0;
}
secp256k1_fe_normalize_var(&r->y);
@@ -251,11 +249,23 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
- /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
+ /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
+ *
+ * Note that there is an implementation described at
+ * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+ * which trades a multiply for a square, but in practice this is actually slower,
+ * mainly because it requires more normalizations.
+ */
secp256k1_fe t1,t2,t3,t4;
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
+ *
+ * Having said this, if this function receives a point on a sextic twist, e.g. by
+ * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
+ * since -6 does have a cube root mod p. For this point, this function will not set
+ * the infinity flag even though the point doubles to infinity, and the result
+ * point will be gibberish (z = 0 but infinity = 0).
*/
r->infinity = a->infinity;
if (r->infinity) {
@@ -623,4 +633,18 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
}
#endif
+static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
+ secp256k1_fe yz;
+
+ if (a->infinity) {
+ return 0;
+ }
+
+ /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as
+ * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z
+ is */
+ secp256k1_fe_mul(&yz, &a->y, &a->z);
+ return secp256k1_fe_is_quad_var(&yz);
+}
+
#endif
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index 0ff01e63fa..fca98cab9f 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -11,7 +11,7 @@
#include <stdint.h>
typedef struct {
- uint32_t s[32];
+ uint32_t s[8];
uint32_t buf[16]; /* In big endian */
size_t bytes;
} secp256k1_sha256_t;
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index ae55df6d8a..b47e65f830 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -269,15 +269,13 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
rng->retry = 0;
}
-
+#undef BE32
#undef Round
-#undef sigma0
#undef sigma1
-#undef Sigma0
+#undef sigma0
#undef Sigma1
-#undef Ch
+#undef Sigma0
#undef Maj
-#undef ReadBE32
-#undef WriteBE32
+#undef Ch
#endif
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
index 90a498eaa2..be67048fbe 100644
--- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
@@ -1,60 +1,478 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.bitcoin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.math.BigInteger;
import com.google.common.base.Preconditions;
-
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import static org.bitcoin.NativeSecp256k1Util.*;
/**
- * This class holds native methods to handle ECDSA verification.
- * You can find an example library that can be used for this at
- * https://github.com/sipa/secp256k1
+ * <p>This class holds native methods to handle ECDSA verification.</p>
+ *
+ * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
+ *
+ * <p>To build secp256k1 for use with bitcoinj, run
+ * `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh`
+ * and `make` then copy `.libs/libsecp256k1.so` to your system library path
+ * or point the JVM to the folder containing it with -Djava.library.path
+ * </p>
*/
public class NativeSecp256k1 {
- public static final boolean enabled;
- static {
- boolean isEnabled = true;
- try {
- System.loadLibrary("javasecp256k1");
- } catch (UnsatisfiedLinkError e) {
- isEnabled = false;
- }
- enabled = isEnabled;
- }
-
+
+ private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ private static final Lock r = rwl.readLock();
+ private static final Lock w = rwl.writeLock();
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
/**
* Verifies the given secp256k1 signature in native code.
* Calling when enabled == false is undefined (probably library not loaded)
- *
+ *
* @param data The data which was signed, must be exactly 32 bytes
* @param signature The signature
* @param pub The public key which did the signing
*/
- public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
+ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
ByteBuffer byteBuff = nativeECDSABuffer.get();
- if (byteBuff == null) {
- byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
+ if (byteBuff == null || byteBuff.capacity() < 520) {
+ byteBuff = ByteBuffer.allocateDirect(520);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
- byteBuff.putInt(signature.length);
- byteBuff.putInt(pub.length);
byteBuff.put(signature);
byteBuff.put(pub);
- return secp256k1_ecdsa_verify(byteBuff) == 1;
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
+ } finally {
+ r.unlock();
+ }
+ }
+
+ /**
+ * libsecp256k1 Create an ECDSA signature.
+ *
+ * @param data Message hash, 32 bytes
+ * @param key Secret key, 32 bytes
+ *
+ * Return values
+ * @param sig byte array of signature
+ */
+ public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
+ Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
+ byteBuff = ByteBuffer.allocateDirect(32 + 32);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(data);
+ byteBuff.put(sec);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] sigArr = retByteArray[0];
+ int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(sigArr.length, sigLen, "Got bad signature length.");
+
+ return retVal == 0 ? new byte[0] : sigArr;
+ }
+
+ /**
+ * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
+ *
+ * @param seckey ECDSA Secret key, 32 bytes
+ */
+ public static boolean secKeyVerify(byte[] seckey) {
+ Preconditions.checkArgument(seckey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seckey.length) {
+ byteBuff = ByteBuffer.allocateDirect(seckey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+
+ r.lock();
+ try {
+ return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
+ } finally {
+ r.unlock();
+ }
+ }
+
+
+ /**
+ * libsecp256k1 Compute Pubkey - computes public key from secret key
+ *
+ * @param seckey ECDSA Secret key, 32 bytes
+ *
+ * Return values
+ * @param pubkey ECDSA Public key, 33 or 65 bytes
+ */
+ //TODO add a 'compressed' arg
+ public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
+ Preconditions.checkArgument(seckey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seckey.length) {
+ byteBuff = ByteBuffer.allocateDirect(seckey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+ int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ return retVal == 0 ? new byte[0]: pubArr;
+ }
+
+ /**
+ * libsecp256k1 Cleanup - This destroys the secp256k1 context object
+ * This should be called at the end of the program for proper cleanup of the context.
+ */
+ public static synchronized void cleanup() {
+ w.lock();
+ try {
+ secp256k1_destroy_context(Secp256k1Context.getContext());
+ } finally {
+ w.unlock();
+ }
+ }
+
+ public static long cloneContext() {
+ r.lock();
+ try {
+ return secp256k1_ctx_clone(Secp256k1Context.getContext());
+ } finally { r.unlock(); }
+ }
+
+ /**
+ * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param seckey 32-byte seckey
+ */
+ public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(privkey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(privkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] privArr = retByteArray[0];
+
+ int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(privArr.length, privLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return privArr;
}
/**
- * @param byteBuff signature format is byte[32] data,
- * native-endian int signatureLength, native-endian int pubkeyLength,
- * byte[signatureLength] signature, byte[pubkeyLength] pub
- * @returns 1 for valid signature, anything else for invalid
+ * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param seckey 32-byte seckey
*/
- private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
+ public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(privkey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(privkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] privArr = retByteArray[0];
+
+ int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(privArr.length, privLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return privArr;
+ }
+
+ /**
+ * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param pubkey 32-byte seckey
+ */
+ public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(pubkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+
+ int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return pubArr;
+ }
+
+ /**
+ * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param pubkey 32-byte seckey
+ */
+ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(pubkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+
+ int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return pubArr;
+ }
+
+ /**
+ * libsecp256k1 create ECDH secret - constant time ECDH calculation
+ *
+ * @param seckey byte array of secret key used in exponentiaion
+ * @param pubkey byte array of public key used in exponentiaion
+ */
+ public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
+ Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
+ byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+ byteBuff.put(pubkey);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] resArr = retByteArray[0];
+ int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+
+ assertEquals(resArr.length, 32, "Got bad result length.");
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return resArr;
+ }
+
+ /**
+ * libsecp256k1 randomize - updates the context randomization
+ *
+ * @param seed 32-byte random seed
+ */
+ public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
+ Preconditions.checkArgument(seed.length == 32 || seed == null);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seed.length) {
+ byteBuff = ByteBuffer.allocateDirect(seed.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seed);
+
+ w.lock();
+ try {
+ return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
+ } finally {
+ w.unlock();
+ }
+ }
+
+ public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
+ Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null) {
+ byteBuff = ByteBuffer.allocateDirect(32 + 32);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(data);
+ byteBuff.put(sec);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] sigArr = retByteArray[0];
+ int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+
+ assertEquals(sigArr.length, 64, "Got bad signature length.");
+
+ return retVal == 0 ? new byte[0] : sigArr;
+ }
+
+ private static native long secp256k1_ctx_clone(long context);
+
+ private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
+
+ private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
+
+ private static native void secp256k1_destroy_context(long context);
+
+ private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
+
+ private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
+
+ private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
+
+ private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
+
}
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
new file mode 100644
index 0000000000..f18ce95810
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
@@ -0,0 +1,247 @@
+package org.bitcoin;
+
+import com.google.common.io.BaseEncoding;
+import java.util.Arrays;
+import java.math.BigInteger;
+import javax.xml.bind.DatatypeConverter;
+import static org.bitcoin.NativeSecp256k1Util.*;
+
+/**
+ * This class holds test cases defined for testing this library.
+ */
+public class NativeSecp256k1Test {
+
+ //TODO improve comments/add more tests
+ /**
+ * This tests verify() for a valid signature
+ */
+ public static void testVerifyPos() throws AssertFailException{
+ boolean result = false;
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ result = NativeSecp256k1.verify( data, sig, pub);
+ assertEquals( result, true , "testVerifyPos");
+ }
+
+ /**
+ * This tests verify() for a non-valid signature
+ */
+ public static void testVerifyNeg() throws AssertFailException{
+ boolean result = false;
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
+ byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ result = NativeSecp256k1.verify( data, sig, pub);
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, false , "testVerifyNeg");
+ }
+
+ /**
+ * This tests secret key verify() for a valid secretkey
+ */
+ public static void testSecKeyVerifyPos() throws AssertFailException{
+ boolean result = false;
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ result = NativeSecp256k1.secKeyVerify( sec );
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, true , "testSecKeyVerifyPos");
+ }
+
+ /**
+ * This tests secret key verify() for a invalid secretkey
+ */
+ public static void testSecKeyVerifyNeg() throws AssertFailException{
+ boolean result = false;
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ result = NativeSecp256k1.secKeyVerify( sec );
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, false , "testSecKeyVerifyNeg");
+ }
+
+ /**
+ * This tests public key create() for a valid secretkey
+ */
+ public static void testPubKeyCreatePos() throws AssertFailException{
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.computePubkey( sec);
+ String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
+ }
+
+ /**
+ * This tests public key create() for a invalid secretkey
+ */
+ public static void testPubKeyCreateNeg() throws AssertFailException{
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.computePubkey( sec);
+ String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
+ }
+
+ /**
+ * This tests sign() for a valid secretkey
+ */
+ public static void testSignPos() throws AssertFailException{
+
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.sign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
+ }
+
+ /**
+ * This tests sign() for a invalid secretkey
+ */
+ public static void testSignNeg() throws AssertFailException{
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.sign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "" , "testSignNeg");
+ }
+
+ /**
+ * This tests private key tweak-add
+ */
+ public static void testPrivKeyTweakAdd_1() throws AssertFailException {
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
+ }
+
+ /**
+ * This tests private key tweak-mul
+ */
+ public static void testPrivKeyTweakMul_1() throws AssertFailException {
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
+ }
+
+ /**
+ * This tests private key tweak-add uncompressed
+ */
+ public static void testPrivKeyTweakAdd_2() throws AssertFailException {
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
+ }
+
+ /**
+ * This tests private key tweak-mul uncompressed
+ */
+ public static void testPrivKeyTweakMul_2() throws AssertFailException {
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
+ }
+
+ /**
+ * This tests seed randomization
+ */
+ public static void testRandomize() throws AssertFailException {
+ byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
+ boolean result = NativeSecp256k1.randomize(seed);
+ assertEquals( result, true, "testRandomize");
+ }
+
+ /**
+ * This tests signSchnorr() for a valid secretkey
+ */
+ public static void testSchnorrSign() throws AssertFailException{
+
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
+ }
+
+ /**
+ * This tests signSchnorr() for a valid secretkey
+ */
+ public static void testCreateECDHSecret() throws AssertFailException{
+
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
+ String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
+ }
+
+ public static void main(String[] args) throws AssertFailException{
+
+
+ System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
+
+ assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
+
+ //Test verify() success/fail
+ testVerifyPos();
+ testVerifyNeg();
+
+ //Test secKeyVerify() success/fail
+ testSecKeyVerifyPos();
+ testSecKeyVerifyNeg();
+
+ //Test computePubkey() success/fail
+ testPubKeyCreatePos();
+ testPubKeyCreateNeg();
+
+ //Test sign() success/fail
+ testSignPos();
+ testSignNeg();
+
+ //Test Schnorr (partial support) //TODO
+ testSchnorrSign();
+ //testSchnorrVerify
+ //testSchnorrRecovery
+
+ //Test privKeyTweakAdd() 1
+ testPrivKeyTweakAdd_1();
+
+ //Test privKeyTweakMul() 2
+ testPrivKeyTweakMul_1();
+
+ //Test privKeyTweakAdd() 3
+ testPrivKeyTweakAdd_2();
+
+ //Test privKeyTweakMul() 4
+ testPrivKeyTweakMul_2();
+
+ //Test randomize()
+ testRandomize();
+
+ //Test ECDH
+ testCreateECDHSecret();
+
+ NativeSecp256k1.cleanup();
+
+ System.out.println(" All tests passed." );
+
+ }
+}
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java
new file mode 100644
index 0000000000..04732ba044
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bitcoin;
+
+public class NativeSecp256k1Util{
+
+ public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
+ if( val != val2 )
+ throw new AssertFailException("FAIL: " + message);
+ }
+
+ public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
+ if( val != val2 )
+ throw new AssertFailException("FAIL: " + message);
+ else
+ System.out.println("PASS: " + message);
+ }
+
+ public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
+ if( !val.equals(val2) )
+ throw new AssertFailException("FAIL: " + message);
+ else
+ System.out.println("PASS: " + message);
+ }
+
+ public static class AssertFailException extends Exception {
+ public AssertFailException(String message) {
+ super( message );
+ }
+ }
+}
diff --git a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java
new file mode 100644
index 0000000000..216c986a8b
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bitcoin;
+
+/**
+ * This class holds the context reference used in native methods
+ * to handle ECDSA operations.
+ */
+public class Secp256k1Context {
+ private static final boolean enabled; //true if the library is loaded
+ private static final long context; //ref to pointer to context obj
+
+ static { //static initializer
+ boolean isEnabled = true;
+ long contextRef = -1;
+ try {
+ System.loadLibrary("secp256k1");
+ contextRef = secp256k1_init_context();
+ } catch (UnsatisfiedLinkError e) {
+ System.out.println("UnsatisfiedLinkError: " + e.toString());
+ isEnabled = false;
+ }
+ enabled = isEnabled;
+ context = contextRef;
+ }
+
+ public static boolean isEnabled() {
+ return enabled;
+ }
+
+ public static long getContext() {
+ if(!enabled) return -1; //sanity check
+ return context;
+ }
+
+ private static native long secp256k1_init_context();
+}
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
index bb4cd70728..dba9524dd4 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
@@ -1,23 +1,411 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
#include "org_bitcoin_NativeSecp256k1.h"
#include "include/secp256k1.h"
+#include "include/secp256k1_ecdh.h"
+#include "include/secp256k1_recovery.h"
+#include "include/secp256k1_schnorr.h"
-JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
- (JNIEnv* env, jclass classObject, jobject byteBufferObject)
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
+ (JNIEnv* env, jclass classObject, jlong ctx_l)
+{
+ const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
+
+ (void)classObject;(void)env;
+
+ return ctx_clone_l;
+
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ (void)classObject;
+
+ return secp256k1_context_randomize(ctx, seed);
+
+}
+
+SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
+ (JNIEnv* env, jclass classObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ secp256k1_context_destroy(ctx);
+
+ (void)classObject;(void)env;
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* sigdata = { (unsigned char*) (data + 32) };
+ const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
+
+ secp256k1_ecdsa_signature sig;
+ secp256k1_pubkey pubkey;
+
+ int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
+
+ if( ret ) {
+ ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
+
+ if( ret ) {
+ ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
+ }
+ }
+
+ (void)classObject;
+
+ return ret;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ unsigned char* secKey = (unsigned char*) (data + 32);
+
+ jobjectArray retArray;
+ jbyteArray sigArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ secp256k1_ecdsa_signature sig[72];
+
+ int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
+
+ unsigned char outputSer[72];
+ size_t outputLen = 72;
+
+ if( ret ) {
+ int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ sigArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ (void)classObject;
+
+ return secp256k1_ec_seckey_verify(ctx, secKey);
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ secp256k1_pubkey pubkey;
+
+ jobjectArray retArray;
+ jbyteArray pubkeyArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
+
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubkeyArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (privkey + 32);
+
+ jobjectArray retArray;
+ jbyteArray privArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int privkeylen = 32;
+
+ int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
+
+ intsarray[0] = privkeylen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ privArray = (*env)->NewByteArray(env, privkeylen);
+ (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
+ (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (privkey + 32);
+
+ jobjectArray retArray;
+ jbyteArray privArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int privkeylen = 32;
+
+ int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
+
+ intsarray[0] = privkeylen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ privArray = (*env)->NewByteArray(env, privkeylen);
+ (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
+ (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
+ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (pkey + publen);
+
+ jobjectArray retArray;
+ jbyteArray pubArray, intsByteArray;
+ unsigned char intsarray[2];
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ secp256k1_pubkey pubkey;
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
+
+ if( ret ) {
+ ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
+ }
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
{
- unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
- int sigLen = *((int*)(data + 32));
- int pubLen = *((int*)(data + 32 + 4));
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (pkey + publen);
+
+ jobjectArray retArray;
+ jbyteArray pubArray, intsByteArray;
+ unsigned char intsarray[2];
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ secp256k1_pubkey pubkey;
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
+
+ if ( ret ) {
+ ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
+ }
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
- return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
}
-static void __javasecp256k1_attach(void) __attribute__((constructor));
-static void __javasecp256k1_detach(void) __attribute__((destructor));
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
+ (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
+{
+ (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
-static void __javasecp256k1_attach(void) {
- secp256k1_start(SECP256K1_START_VERIFY);
+ return 0;
}
-static void __javasecp256k1_detach(void) {
- secp256k1_stop();
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ unsigned char* secKey = (unsigned char*) (data + 32);
+
+ jobjectArray retArray;
+ jbyteArray sigArray, intsByteArray;
+ unsigned char intsarray[1];
+ unsigned char sig[64];
+
+ int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
+
+ intsarray[0] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ sigArray = (*env)->NewByteArray(env, 64);
+ (*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig);
+ (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 1);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
+
+ jobjectArray retArray;
+ jbyteArray outArray, intsByteArray;
+ unsigned char intsarray[1];
+ secp256k1_pubkey pubkey;
+ unsigned char nonce_res[32];
+ size_t outputLen = 32;
+
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
+
+ if (ret) {
+ ret = secp256k1_ecdh(
+ ctx,
+ nonce_res,
+ &pubkey,
+ secdata
+ );
+ }
+
+ intsarray[0] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ outArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
+ (*env)->SetObjectArrayElement(env, retArray, 0, outArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 1);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
}
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
index d7fb004fa8..4125a1f523 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
@@ -1,5 +1,6 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
+#include "include/secp256k1.h"
/* Header for class org_bitcoin_NativeSecp256k1 */
#ifndef _Included_org_bitcoin_NativeSecp256k1
@@ -9,11 +10,116 @@ extern "C" {
#endif
/*
* Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ctx_clone
+ * Signature: (J)J
+ */
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_context_randomize
+ * Signature: (Ljava/nio/ByteBuffer;J)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_privkey_tweak_add
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_privkey_tweak_mul
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_pubkey_tweak_add
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_pubkey_tweak_mul
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_destroy_context
+ * Signature: (J)V
+ */
+SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_verify
- * Signature: (Ljava/nio/ByteBuffer;)I
+ * Signature: (Ljava/nio/ByteBuffer;JII)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv *, jclass, jobject, jlong, jint, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdsa_sign
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_seckey_verify
+ * Signature: (Ljava/nio/ByteBuffer;J)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_pubkey_create
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
*/
-JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
- (JNIEnv *, jclass, jobject);
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_pubkey_parse
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_schnorr_sign
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdh
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
+
#ifdef __cplusplus
}
diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c
new file mode 100644
index 0000000000..a52939e7e7
--- /dev/null
+++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include "org_bitcoin_Secp256k1Context.h"
+#include "include/secp256k1.h"
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
+ (JNIEnv* env, jclass classObject)
+{
+ secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ (void)classObject;(void)env;
+
+ return (uintptr_t)ctx;
+}
+
diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h
new file mode 100644
index 0000000000..0d2bc84b7f
--- /dev/null
+++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h
@@ -0,0 +1,22 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+#include "include/secp256k1.h"
+/* Header for class org_bitcoin_Secp256k1Context */
+
+#ifndef _Included_org_bitcoin_Secp256k1Context
+#define _Included_org_bitcoin_Secp256k1Context
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_bitcoin_Secp256k1Context
+ * Method: secp256k1_init_context
+ * Signature: ()J
+ */
+SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include
index 670b9c1152..e3088b4697 100644
--- a/src/secp256k1/src/modules/ecdh/Makefile.am.include
+++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include
@@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_ecdh
bench_ecdh_SOURCES = src/bench_ecdh.c
-bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include
index 5de3ea33ea..bf23c26e71 100644
--- a/src/secp256k1/src/modules/recovery/Makefile.am.include
+++ b/src/secp256k1/src/modules/recovery/Makefile.am.include
@@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_recover
bench_recover_SOURCES = src/bench_recover.c
-bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include
index b3bfa7d5cc..f1af8e8325 100644
--- a/src/secp256k1/src/modules/schnorr/Makefile.am.include
+++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include
@@ -6,5 +6,5 @@ noinst_HEADERS += src/modules/schnorr/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_schnorr_verify
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
-bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index ebfa71eb44..7bb9c5be8c 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -32,6 +32,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi
/** Compute a modular inverse. The input must be less than the modulus. */
static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);
+/** Compute the jacobi symbol (a|b). b must be positive and odd. */
+static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b);
+
/** Compare the absolute value of two numbers. */
static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);
@@ -57,6 +60,9 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits);
/** Check whether a number is zero. */
static int secp256k1_num_is_zero(const secp256k1_num *a);
+/** Check whether a number is one. */
+static int secp256k1_num_is_one(const secp256k1_num *a);
+
/** Check whether a number is strictly negative. */
static int secp256k1_num_is_neg(const secp256k1_num *a);
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index 7b6a89719a..3a46495eea 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -144,6 +144,32 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a,
memset(v, 0, sizeof(v));
}
+static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) {
+ int ret;
+ mpz_t ga, gb;
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+ VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1));
+
+ mpz_inits(ga, gb, NULL);
+
+ mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data);
+ mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);
+ if (a->neg) {
+ mpz_neg(ga, ga);
+ }
+
+ ret = mpz_jacobi(ga, gb);
+
+ mpz_clears(ga, gb, NULL);
+
+ return ret;
+}
+
+static int secp256k1_num_is_one(const secp256k1_num *a) {
+ return (a->limbs == 1 && a->data[0] == 1);
+}
+
static int secp256k1_num_is_zero(const secp256k1_num *a) {
return (a->limbs == 1 && a->data[0] == 0);
}
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 88ea97de86..c5baf4df41 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_SCALAR_IMPL_H_
#define _SECP256K1_SCALAR_IMPL_H_
-#include <string.h>
-
#include "group.h"
#include "scalar.h"
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 62d192baeb..7973d60c36 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -4,8 +4,6 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#define SECP256K1_BUILD (1)
-
#include "include/secp256k1.h"
#include "util.h"
@@ -152,7 +150,6 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
secp256k1_ge Q;
- (void)ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
memset(pubkey, 0, sizeof(*pubkey));
@@ -170,7 +167,6 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
size_t len;
int ret = 0;
- (void)ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(outputlen != NULL);
ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
@@ -216,7 +212,7 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input != NULL);
@@ -234,7 +230,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
int ret = 1;
int overflow = 0;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input64 != NULL);
@@ -253,7 +249,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(outputlen != NULL);
ARG_CHECK(sig != NULL);
@@ -265,7 +261,7 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsign
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output64 != NULL);
ARG_CHECK(sig != NULL);
@@ -398,7 +394,6 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char
int overflow;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
ret = !overflow && !secp256k1_scalar_is_zero(&sec);
@@ -437,7 +432,6 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
@@ -485,7 +479,6 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 687a5f2fdd..b32cb90813 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -473,6 +473,8 @@ void test_num_negate(void) {
}
void test_num_add_sub(void) {
+ int i;
+ secp256k1_scalar s;
secp256k1_num n1;
secp256k1_num n2;
secp256k1_num n1p2, n2p1, n1m2, n2m1;
@@ -498,6 +500,110 @@ void test_num_add_sub(void) {
CHECK(!secp256k1_num_eq(&n2p1, &n1));
secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */
CHECK(secp256k1_num_eq(&n2p1, &n1));
+
+ /* check is_one */
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_get_num(&n1, &s);
+ CHECK(secp256k1_num_is_one(&n1));
+ /* check that 2^n + 1 is never 1 */
+ secp256k1_scalar_get_num(&n2, &s);
+ for (i = 0; i < 250; ++i) {
+ secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */
+ secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */
+ CHECK(!secp256k1_num_is_one(&n1p2));
+ }
+}
+
+void test_num_mod(void) {
+ int i;
+ secp256k1_scalar s;
+ secp256k1_num order, n;
+
+ /* check that 0 mod anything is 0 */
+ random_scalar_order_test(&s);
+ secp256k1_scalar_get_num(&order, &s);
+ secp256k1_scalar_set_int(&s, 0);
+ secp256k1_scalar_get_num(&n, &s);
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+
+ /* check that anything mod 1 is 0 */
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_get_num(&order, &s);
+ secp256k1_scalar_get_num(&n, &s);
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+
+ /* check that increasing the number past 2^256 does not break this */
+ random_scalar_order_test(&s);
+ secp256k1_scalar_get_num(&n, &s);
+ /* multiply by 2^8, which'll test this case with high probability */
+ for (i = 0; i < 8; ++i) {
+ secp256k1_num_add(&n, &n, &n);
+ }
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+}
+
+void test_num_jacobi(void) {
+ secp256k1_scalar sqr;
+ secp256k1_scalar small;
+ secp256k1_scalar five; /* five is not a quadratic residue */
+ secp256k1_num order, n;
+ int i;
+ /* squares mod 5 are 1, 4 */
+ const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 };
+
+ /* check some small values with 5 as the order */
+ secp256k1_scalar_set_int(&five, 5);
+ secp256k1_scalar_get_num(&order, &five);
+ for (i = 0; i < 10; ++i) {
+ secp256k1_scalar_set_int(&small, i);
+ secp256k1_scalar_get_num(&n, &small);
+ CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]);
+ }
+
+ /** test large values with 5 as group order */
+ secp256k1_scalar_get_num(&order, &five);
+ /* we first need a scalar which is not a multiple of 5 */
+ do {
+ secp256k1_num fiven;
+ random_scalar_order_test(&sqr);
+ secp256k1_scalar_get_num(&fiven, &five);
+ secp256k1_scalar_get_num(&n, &sqr);
+ secp256k1_num_mod(&n, &fiven);
+ } while (secp256k1_num_is_zero(&n));
+ /* next force it to be a residue. 2 is a nonresidue mod 5 so we can
+ * just multiply by two, i.e. add the number to itself */
+ if (secp256k1_num_jacobi(&n, &order) == -1) {
+ secp256k1_num_add(&n, &n, &n);
+ }
+
+ /* test residue */
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1);
+ /* test nonresidue */
+ secp256k1_num_add(&n, &n, &n);
+ CHECK(secp256k1_num_jacobi(&n, &order) == -1);
+
+ /** test with secp group order as order */
+ secp256k1_scalar_order_get_num(&order);
+ random_scalar_order_test(&sqr);
+ secp256k1_scalar_sqr(&sqr, &sqr);
+ /* test residue */
+ secp256k1_scalar_get_num(&n, &sqr);
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1);
+ /* test nonresidue */
+ secp256k1_scalar_mul(&sqr, &sqr, &five);
+ secp256k1_scalar_get_num(&n, &sqr);
+ CHECK(secp256k1_num_jacobi(&n, &order) == -1);
+ /* test multiple of the order*/
+ CHECK(secp256k1_num_jacobi(&order, &order) == 0);
+
+ /* check one less than the order */
+ secp256k1_scalar_set_int(&small, 1);
+ secp256k1_scalar_get_num(&n, &small);
+ secp256k1_num_sub(&n, &order, &n);
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */
}
void run_num_smalltests(void) {
@@ -505,6 +611,8 @@ void run_num_smalltests(void) {
for (i = 0; i < 100*count; i++) {
test_num_negate();
test_num_add_sub();
+ test_num_mod();
+ test_num_jacobi();
}
}
#endif
@@ -689,6 +797,10 @@ void scalar_test(void) {
secp256k1_scalar_inverse(&inv, &inv);
/* Inverting one must result in one. */
CHECK(secp256k1_scalar_is_one(&inv));
+#ifndef USE_NUM_NONE
+ secp256k1_scalar_get_num(&invnum, &inv);
+ CHECK(secp256k1_num_is_one(&invnum));
+#endif
}
}
@@ -855,7 +967,7 @@ void run_scalar_tests(void) {
secp256k1_scalar zzv;
#endif
int overflow;
- unsigned char chal[32][2][32] = {
+ unsigned char chal[33][2][32] = {
{{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
@@ -1111,9 +1223,17 @@ void run_scalar_tests(void) {
{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}
+ 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}},
+ {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
+ 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03},
+ {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
+ 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}}
};
- unsigned char res[32][2][32] = {
+ unsigned char res[33][2][32] = {
{{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9,
0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1,
0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6,
@@ -1369,10 +1489,18 @@ void run_scalar_tests(void) {
{0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2,
0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38,
0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34,
- 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}
+ 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}},
+ {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
+ 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
+ 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
+ 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5},
+ {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
+ 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
+ 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
+ 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}
};
secp256k1_scalar_set_int(&one, 1);
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < 33; i++) {
secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
CHECK(!overflow);
secp256k1_scalar_set_b32(&y, chal[i][1], &overflow);
@@ -1446,7 +1574,7 @@ void random_fe_non_zero(secp256k1_fe *nz) {
void random_fe_non_square(secp256k1_fe *ns) {
secp256k1_fe r;
random_fe_non_zero(ns);
- if (secp256k1_fe_sqrt_var(&r, ns)) {
+ if (secp256k1_fe_sqrt(&r, ns)) {
secp256k1_fe_negate(ns, ns, 1);
}
}
@@ -1641,7 +1769,7 @@ void run_sqr(void) {
void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
secp256k1_fe r1, r2;
- int v = secp256k1_fe_sqrt_var(&r1, a);
+ int v = secp256k1_fe_sqrt(&r1, a);
CHECK((v == 0) == (k == NULL));
if (k != NULL) {
@@ -1951,8 +2079,8 @@ void test_add_neg_y_diff_x(void) {
* of the sum to be wrong (since infinity has no xy coordinates).
* HOWEVER, if the x-coordinates are different, infinity is the
* wrong answer, and such degeneracies are exposed. This is the
- * root of https://github.com/bitcoin/secp256k1/issues/257 which
- * this test is a regression test for.
+ * root of https://github.com/bitcoin-core/secp256k1/issues/257
+ * which this test is a regression test for.
*
* These points were generated in sage as
* # secp256k1 params
@@ -2051,15 +2179,16 @@ void run_ec_combine(void) {
void test_group_decompress(const secp256k1_fe* x) {
/* The input itself, normalized. */
secp256k1_fe fex = *x;
- secp256k1_fe tmp;
+ secp256k1_fe fez;
/* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */
secp256k1_ge ge_quad, ge_even, ge_odd;
+ secp256k1_gej gej_quad;
/* Return values of the above calls. */
int res_quad, res_even, res_odd;
secp256k1_fe_normalize_var(&fex);
- res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex);
+ res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex);
res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);
res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);
@@ -2085,13 +2214,29 @@ void test_group_decompress(const secp256k1_fe* x) {
CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));
/* Check that the Y coordinate result in ge_quad is a square. */
- CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y));
- secp256k1_fe_sqr(&tmp, &tmp);
- CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y));
+ CHECK(secp256k1_fe_is_quad_var(&ge_quad.y));
/* Check odd/even Y in ge_odd, ge_even. */
CHECK(secp256k1_fe_is_odd(&ge_odd.y));
CHECK(!secp256k1_fe_is_odd(&ge_even.y));
+
+ /* Check secp256k1_gej_has_quad_y_var. */
+ secp256k1_gej_set_ge(&gej_quad, &ge_quad);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
+ do {
+ random_fe_test(&fez);
+ } while (secp256k1_fe_is_zero(&fez));
+ secp256k1_gej_rescale(&gej_quad, &fez);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
+ secp256k1_gej_neg(&gej_quad, &gej_quad);
+ CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
+ do {
+ random_fe_test(&fez);
+ } while (secp256k1_fe_is_zero(&fez));
+ secp256k1_gej_rescale(&gej_quad, &fez);
+ CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
+ secp256k1_gej_neg(&gej_quad, &gej_quad);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
}
}
@@ -2383,9 +2528,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, shift;
int wnaf[256] = {0};
int i;
-#ifdef USE_ENDOMORPHISM
int skew;
-#endif
secp256k1_scalar num = *number;
secp256k1_scalar_set_int(&x, 0);
@@ -2395,10 +2538,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
for (i = 0; i < 16; ++i) {
secp256k1_scalar_shr_int(&num, 8);
}
- skew = secp256k1_wnaf_const(wnaf, num, w);
-#else
- secp256k1_wnaf_const(wnaf, num, w);
#endif
+ skew = secp256k1_wnaf_const(wnaf, num, w);
for (i = WNAF_SIZE(w); i >= 0; --i) {
secp256k1_scalar t;
@@ -2417,10 +2558,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
}
secp256k1_scalar_add(&x, &x, &t);
}
-#ifdef USE_ENDOMORPHISM
- /* Skew num because when encoding 128-bit numbers as odd we use an offset */
+ /* Skew num because when encoding numbers as odd we use an offset */
secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
-#endif
CHECK(secp256k1_scalar_eq(&x, &num));
}
@@ -3484,12 +3623,14 @@ void run_ecdsa_end_to_end(void) {
int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
static const unsigned char zeroes[32] = {0};
+#ifdef ENABLE_OPENSSL_TESTS
static const unsigned char max_scalar[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40
};
+#endif
int ret = 0;
@@ -3607,13 +3748,13 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) {
static void damage_array(unsigned char *sig, size_t *len) {
int pos;
int action = secp256k1_rand_bits(3);
- if (action < 1) {
+ if (action < 1 && *len > 3) {
/* Delete a byte. */
pos = secp256k1_rand_int(*len);
memmove(sig + pos, sig + pos + 1, *len - pos - 1);
(*len)--;
return;
- } else if (action < 2) {
+ } else if (action < 2 && *len < 2048) {
/* Insert a byte. */
pos = secp256k1_rand_int(1 + *len);
memmove(sig + pos + 1, sig + pos, *len - pos);
@@ -3785,6 +3926,7 @@ void run_ecdsa_der_parse(void) {
int certainly_der = 0;
int certainly_not_der = 0;
random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der);
+ CHECK(buflen <= 2048);
for (j = 0; j < 16; j++) {
int ret = 0;
if (j > 0) {
diff --git a/src/serialize.h b/src/serialize.h
index 378ed39074..04ab9aa2e7 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -322,8 +322,8 @@ uint64_t ReadCompactSize(Stream& is)
* 0: [0x00] 256: [0x81 0x00]
* 1: [0x01] 16383: [0xFE 0x7F]
* 127: [0x7F] 16384: [0xFF 0x00]
- * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F]
- * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F]
+ * 128: [0x80 0x00] 16511: [0xFF 0x7F]
+ * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F]
* 2^32: [0x8E 0xFE 0xFE 0xFF 0x00]
*/
diff --git a/src/sync.h b/src/sync.h
index 0c58fb6b4e..7733910749 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -171,7 +171,10 @@ public:
typedef CMutexLock<CCriticalSection> CCriticalBlock;
-#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+#define PASTE(x, y) x ## y
+#define PASTE2(x, y) PASTE(x, y)
+
+#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 01eb2aee9e..ac3ab4c83f 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -121,7 +121,6 @@ public:
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
- std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
@@ -179,7 +178,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
- std::vector<unsigned char> result;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@@ -247,7 +245,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
- std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
index 95dd3e81b4..882b5c67b8 100755
--- a/src/test/bitcoin-util-test.py
+++ b/src/test/bitcoin-util-test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 3884bf3fe3..d2392cfb22 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -283,7 +283,6 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
std::vector<CTransaction> vtx_missing;
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
- bool mutated;
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
BOOST_CHECK(!mutated);
}
diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in
index 1618bdeb76..153f34a3db 100644
--- a/src/test/buildenv.py.in
+++ b/src/test/buildenv.py.in
@@ -1,2 +1,2 @@
-#!/usr/bin/python
+#!/usr/bin/env python
exeext="@EXEEXT@"
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index a0bdcf4afb..d4d825d199 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
uint256 in2 = GetRandHash();
BOOST_CHECK(dbw.Write(key2, in2));
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
// Be sure to seek past the obfuscation key (if it exists)
it->Seek(key);
@@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
BOOST_CHECK(dbw.Write(key, value));
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
}
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 6511e6ffa2..267d1b55e1 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -150,4 +150,26 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_CHECK(addrman2.size() == 0);
}
+BOOST_AUTO_TEST_CASE(cnode_simple_test)
+{
+ SOCKET hSocket = INVALID_SOCKET;
+
+ in_addr ipv4Addr;
+ ipv4Addr.s_addr = 0xa0b0c001;
+
+ CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
+ std::string pszDest = "";
+ bool fInboundIn = false;
+
+ // Test that fFeeler is false by default.
+ CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
+ BOOST_CHECK(pnode1->fInbound == false);
+ BOOST_CHECK(pnode1->fFeeler == false);
+
+ fInboundIn = true;
+ CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
+ BOOST_CHECK(pnode2->fInbound == true);
+ BOOST_CHECK(pnode2->fFeeler == false);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 74ffe0cc74..e9c8691745 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -122,7 +122,6 @@ BOOST_AUTO_TEST_CASE(pmt_malleability)
std::vector<bool> vMatch = boost::assign::list_of(false)(false)(false)(false)(false)(false)(false)(false)(false)(true)(true)(false);
CPartialMerkleTree tree(vTxid, vMatch);
- std::vector<uint256> vTxid2;
std::vector<unsigned int> vIndex;
BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());
}
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index bbda6a48f4..a15915aad2 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -18,18 +18,6 @@
using namespace std;
-UniValue
-createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
-{
- UniValue result(UniValue::VARR);
- result.push_back(nRequired);
- UniValue addresses(UniValue::VARR);
- if (address1) addresses.push_back(address1);
- if (address2) addresses.push_back(address2);
- result.push_back(addresses);
- return result;
-}
-
UniValue CallRPC(string args)
{
vector<string> vArgs;
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 5224b57ca4..1a01593a8e 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -107,18 +107,20 @@ BOOST_AUTO_TEST_CASE(sign)
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++) {
+ PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
+ bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
txTo[i].vin[0].scriptSig = sigSave;
}
+ }
}
BOOST_AUTO_TEST_CASE(norecurse)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index fd4f174b40..b5af400bc5 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -7,6 +7,7 @@
#include "test/test_bitcoin.h"
#include "clientversion.h"
+#include "checkqueue.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
@@ -153,6 +154,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -168,7 +170,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err),
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@@ -237,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid();
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
}
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err);
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
@@ -419,6 +422,86 @@ void ReplaceRedeemScript(CScript& script, const CScript& redeemScript)
script = PushAll(stack);
}
+BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
+ CMutableTransaction mtx;
+ mtx.nVersion = 1;
+
+ CKey key;
+ key.MakeNewKey(false);
+ CBasicKeyStore keystore;
+ keystore.AddKeyPubKey(key, key.GetPubKey());
+ CKeyID hash = key.GetPubKey().GetID();
+ CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
+
+ vector<int> sigHashes;
+ sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_NONE);
+ sigHashes.push_back(SIGHASH_SINGLE);
+ sigHashes.push_back(SIGHASH_ALL);
+
+ // create a big transaction of 4500 inputs signed by the same key
+ for(uint32_t ij = 0; ij < 4500; ij++) {
+ uint32_t i = mtx.vin.size();
+ uint256 prevId;
+ prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
+ COutPoint outpoint(prevId, i);
+
+ mtx.vin.resize(mtx.vin.size() + 1);
+ mtx.vin[i].prevout = outpoint;
+ mtx.vin[i].scriptSig = CScript();
+
+ mtx.vout.resize(mtx.vout.size() + 1);
+ mtx.vout[i].nValue = 1000;
+ mtx.vout[i].scriptPubKey = CScript() << OP_1;
+ }
+
+ // sign all inputs
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
+ assert(hashSigned);
+ }
+
+ CTransaction tx;
+ CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
+ WithOrVersion(&ssout, 0) << mtx;
+ WithOrVersion(&ssout, 0) >> tx;
+
+ // check all inputs concurrently, with the cache
+ PrecomputedTransactionData txdata(tx);
+ boost::thread_group threadGroup;
+ CCheckQueue<CScriptCheck> scriptcheckqueue(128);
+ CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
+
+ for (int i=0; i<20; i++)
+ threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
+
+ CCoins coins;
+ coins.nVersion = 1;
+ coins.fCoinBase = false;
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ CTxOut txout;
+ txout.nValue = 1000;
+ txout.scriptPubKey = scriptPubKey;
+ coins.vout.push_back(txout);
+ }
+
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ std::vector<CScriptCheck> vChecks;
+ CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
+ vChecks.push_back(CScriptCheck());
+ check.swap(vChecks.back());
+ control.Add(vChecks);
+ }
+
+ bool controlCheck = control.Wait();
+ assert(controlCheck);
+
+ threadGroup.interrupt_all();
+ threadGroup.join_all();
+}
+
BOOST_AUTO_TEST_CASE(test_witness)
{
CBasicKeyStore keystore, keystore2;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index e467a4171d..efd4498747 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -243,11 +243,7 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
{
- int i;
- int count=0;
-
seed_insecure_rand(true);
-
for (int mod=2;mod<11;mod++)
{
int mask = 1;
@@ -256,10 +252,9 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
//mask is 2^ceil(log2(mod))-1
while(mask<mod-1)mask=(mask<<1)+1;
- count = 0;
+ int count = 0;
//How often does it get a zero from the uniform range [0,mod)?
- for (i=0;i<10000;i++)
- {
+ for (int i = 0; i < 10000; i++) {
uint32_t rval;
do{
rval=insecure_rand()&mask;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 078c29def3..4f11c7b951 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -173,7 +173,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
- boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
+ std::unique_ptr<CDBIterator> pcursor(NewIterator());
pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));
diff --git a/src/txdb.h b/src/txdb.h
index 5b98d2792c..adb3f66327 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -92,7 +92,7 @@ public:
private:
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
- boost::scoped_ptr<CDBIterator> pcursor;
+ std::unique_ptr<CDBIterator> pcursor;
std::pair<char, uint256> keyTmp;
friend class CCoinsViewDB;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index b631c48484..0a00d757a2 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -576,7 +576,6 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
{
// Remove transactions which depend on inputs of tx, recursively
- list<CTransaction> result;
LOCK(cs);
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
auto it = mapNextTx.find(txin.prevout);
diff --git a/src/util.cpp b/src/util.cpp
index 9a9209c621..ee12f2b443 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -801,11 +801,10 @@ int GetNumCores()
std::string CopyrightHolders(const std::string& strPrefix)
{
- std::string strCopyrightHolders = strPrefix + _(COPYRIGHT_HOLDERS);
- if (strCopyrightHolders.find("%s") != strCopyrightHolders.npos) {
- strCopyrightHolders = strprintf(strCopyrightHolders, _(COPYRIGHT_HOLDERS_SUBSTITUTION));
- }
- if (strCopyrightHolders.find("Bitcoin Core developers") == strCopyrightHolders.npos) {
+ std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
+
+ // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
+ if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index c906785e9e..a809c9ad64 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv(0).remove(strPath.c_str(), 0);
+ DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
}
void CDBEnv::Reset()
@@ -284,7 +284,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
pdb = NULL;
--bitdb.mapFileUseCount[strFile];
strFile = "";
- throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFile));
+ throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
}
if (fCreate && !Exists(string("version"))) {
@@ -387,11 +387,11 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
while (fSuccess) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
- if (ret == DB_NOTFOUND) {
+ int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret1 == DB_NOTFOUND) {
pcursor->close();
break;
- } else if (ret != 0) {
+ } else if (ret1 != 0) {
pcursor->close();
fSuccess = false;
break;
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 01b8c71a04..a0f673ecfc 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -228,19 +228,17 @@ protected:
return pcursor;
}
- int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
+ int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
{
// Read at cursor
Dbt datKey;
- if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
+ unsigned int fFlags = DB_NEXT;
+ if (setRange) {
datKey.set_data(&ssKey[0]);
datKey.set_size(ssKey.size());
+ fFlags = DB_SET_RANGE;
}
Dbt datValue;
- if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
- datValue.set_data(&ssValue[0]);
- datValue.set_size(ssValue.size());
- }
datKey.set_flags(DB_DBT_MALLOC);
datValue.set_flags(DB_DBT_MALLOC);
int ret = pcursor->get(&datKey, &datValue, fFlags);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index fe8b53ceb0..42ebdb9b9b 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -257,14 +257,13 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (fHelp || params.size() != 2)
throw runtime_error(
"importprunedfunds\n"
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
"\nArguments:\n"
"1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n"
"2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
- "3. \"label\" (string, optional) An optional label\n"
);
CTransaction tx;
@@ -277,10 +276,6 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
- string strLabel = "";
- if (params.size() == 3)
- strLabel = params[2].get_str();
-
//Search partial merkle tree in proof for our transaction and index in valid block
vector<uint256> vMatch;
vector<unsigned int> vIndex;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index aa0a9374c1..0ba6706baf 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1176,10 +1176,10 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
if (fByAccounts)
{
- tallyitem& item = mapAccountTally[strAccount];
- item.nAmount += nAmount;
- item.nConf = min(item.nConf, nConf);
- item.fIsWatchonly = fIsWatchonly;
+ tallyitem& _item = mapAccountTally[strAccount];
+ _item.nAmount += nAmount;
+ _item.nConf = min(_item.nConf, nConf);
+ _item.fIsWatchonly = fIsWatchonly;
}
else
{
@@ -1195,9 +1195,9 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
- BOOST_FOREACH(const uint256& item, (*it).second.txids)
+ BOOST_FOREACH(const uint256& _item, (*it).second.txids)
{
- transactions.push_back(item.GetHex());
+ transactions.push_back(_item.GetHex());
}
}
obj.push_back(Pair("txids", transactions));
@@ -2617,8 +2617,8 @@ static const CRPCCommand commands[] =
{ "wallet", "removeprunedfunds", &removeprunedfunds, true },
};
-void RegisterWalletRPCCommands(CRPCTable &tableRPC)
+void RegisterWalletRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index a5de7e2de1..3a68ccf1b2 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -7,6 +7,6 @@
class CRPCTable;
-void RegisterWalletRPCCommands(CRPCTable &tableRPC);
+void RegisterWalletRPCCommands(CRPCTable &t);
#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp
deleted file mode 100644
index 4e7d177f51..0000000000
--- a/src/wallet/test/rpc_wallet_tests.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright (c) 2013-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "rpc/server.h"
-#include "rpc/client.h"
-
-#include "base58.h"
-#include "main.h"
-#include "wallet/wallet.h"
-
-#include "wallet/test/wallet_test_fixture.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include <univalue.h>
-
-using namespace std;
-
-extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
-extern UniValue CallRPC(string args);
-
-extern CWallet* pwalletMain;
-
-BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, WalletTestingSetup)
-
-BOOST_AUTO_TEST_CASE(rpc_addmultisig)
-{
- rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
-
- // old, 65-byte-long:
- const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
- // new, compressed:
- const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
-
- UniValue v;
- CBitcoinAddress address;
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
-
- BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
-
- string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
-
- string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
-}
-
-BOOST_AUTO_TEST_CASE(rpc_wallet)
-{
- // Test RPC calls for various wallet statistics
- UniValue r;
- CPubKey demoPubkey;
- CBitcoinAddress demoAddress;
- UniValue retValue;
- string strAccount = "walletDemoAccount";
- CBitcoinAddress setaccountDemoAddress;
- {
- LOCK(pwalletMain->cs_wallet);
-
- demoPubkey = pwalletMain->GenerateNewKey();
- demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- string strPurpose = "receive";
- BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
- CWalletDB walletdb(pwalletMain->strWalletFile);
- CAccount account;
- account.vchPubKey = demoPubkey;
- pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
- walletdb.WriteAccount(strAccount, account);
- });
-
- CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
- setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID()));
- }
- /*********************************
- * setaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount"));
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
-
-
- /*********************************
- * getbalance
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
- BOOST_CHECK_NO_THROW(CallRPC("getbalance " + demoAddress.ToString()));
-
- /*********************************
- * listunspent
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
- BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
- BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []"));
- BOOST_CHECK(r.get_array().empty());
-
- /*********************************
- * listreceivedbyaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
-
- /*********************************
- * listreceivedbyaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
-
- /*********************************
- * listsinceblock
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listsinceblock"));
-
- /*********************************
- * listtransactions
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString()));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20"));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20 0"));
- BOOST_CHECK_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " not_int"), runtime_error);
-
- /*********************************
- * listlockunspent
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listlockunspent"));
-
- /*********************************
- * listaccounts
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listaccounts"));
-
- /*********************************
- * listaddressgroupings
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listaddressgroupings"));
-
- /*********************************
- * getrawchangeaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress"));
-
- /*********************************
- * getnewaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"));
-
- /*********************************
- * getaccountaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
- BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * getaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString()));
-
- /*********************************
- * signmessage + verifymessage
- *********************************/
- BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
- BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
- /* Should throw error because this address is not loaded in the wallet */
- BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
-
- /* missing arguments */
- BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error);
- BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
- /* Illegal address */
- BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
- /* wrong address */
- BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
- /* Correct address and signature but wrong message */
- BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
- /* Correct address, message and signature*/
- BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true);
-
- /*********************************
- * getaddressesbyaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- UniValue arr = retValue.get_array();
- BOOST_CHECK(arr.size() > 0);
- BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * fundrawtransaction
- *********************************/
- BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 9036ee26d8..a76db37617 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -1,3 +1,7 @@
+// Copyright (c) 2016 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 "wallet/test/wallet_test_fixture.h"
#include "rpc/server.h"
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c6c5058984..acf980c784 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
empty_wallet();
- for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
add_coin(50000 * COIN);
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
@@ -296,7 +296,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
@@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(25 * CENT);
fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 888aa029a3..10aca2e499 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -98,7 +98,7 @@ CPubKey CWallet::GenerateNewKey()
CKeyMetadata metadata(nCreationTime);
// use HD key derivation if HD was enabled during wallet creation
- if (!hdChain.masterKeyID.IsNull()) {
+ if (IsHDEnabled()) {
// for now we use a fixed keypath scheme of m/0'/0'/k
CKey key; //master key seed (256bit)
CExtKey masterKey; //hd master key
@@ -108,7 +108,7 @@ CPubKey CWallet::GenerateNewKey()
// try to get the master key
if (!GetKey(hdChain.masterKeyID, key))
- throw std::runtime_error("CWallet::GenerateNewKey(): Master key not found");
+ throw std::runtime_error(std::string(__func__) + ": Master key not found");
masterKey.SetMaster(key.begin(), key.size());
@@ -135,7 +135,7 @@ CPubKey CWallet::GenerateNewKey()
// update the chain model in the database
if (!CWalletDB(strWalletFile).WriteHDChain(hdChain))
- throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
+ throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
} else {
secret.MakeNewKey(fCompressed);
}
@@ -152,7 +152,7 @@ CPubKey CWallet::GenerateNewKey()
nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey))
- throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
+ throw std::runtime_error(std::string(__func__) + ": AddKey failed");
return pubkey;
}
@@ -628,7 +628,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
Unlock(strWalletPassphrase);
// if we are using HD, replace the HD master key (seed) with a new one
- if (!hdChain.masterKeyID.IsNull()) {
+ if (IsHDEnabled()) {
CKey key;
CPubKey masterPubKey = GenerateNewHDMasterKey();
if (!SetHDMasterKey(masterPubKey))
@@ -1094,7 +1094,7 @@ isminetype CWallet::IsMine(const CTxOut& txout) const
CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
{
if (!MoneyRange(txout.nValue))
- throw std::runtime_error("CWallet::GetCredit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
return ((IsMine(txout) & filter) ? txout.nValue : 0);
}
@@ -1123,7 +1123,7 @@ bool CWallet::IsChange(const CTxOut& txout) const
CAmount CWallet::GetChange(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
- throw std::runtime_error("CWallet::GetChange(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
return (IsChange(txout) ? txout.nValue : 0);
}
@@ -1147,7 +1147,7 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co
{
nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit))
- throw std::runtime_error("CWallet::GetDebit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nDebit;
}
@@ -1159,7 +1159,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
{
nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWallet::GetCredit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nCredit;
}
@@ -1171,7 +1171,7 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
{
nChange += GetChange(txout);
if (!MoneyRange(nChange))
- throw std::runtime_error("CWallet::GetChange(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nChange;
}
@@ -1200,7 +1200,7 @@ CPubKey CWallet::GenerateNewHDMasterKey()
// write the key&metadata to the database
if (!AddKeyPubKey(key, pubkey))
- throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
+ throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
}
return pubkey;
@@ -1227,12 +1227,17 @@ bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
- throw runtime_error("AddHDChain(): writing chain failed");
+ throw runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
return true;
}
+bool CWallet::IsHDEnabled()
+{
+ return !hdChain.masterKeyID.IsNull();
+}
+
int64_t CWalletTx::GetTxTime() const
{
int64_t n = nTimeSmart;
@@ -2456,7 +2461,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
AddToWallet(wtxNew);
// Notify that old coins are spent
- set<CWalletTx*> setCoins;
BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
@@ -2707,7 +2711,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
- throw runtime_error("TopUpKeyPool(): writing generated key failed");
+ throw runtime_error(std::string(__func__) + ": writing generated key failed");
setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
@@ -2734,9 +2738,9 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error("ReserveKeyFromKeyPool(): read failed");
+ throw runtime_error(std::string(__func__) + ": read failed");
if (!HaveKey(keypool.vchPubKey.GetID()))
- throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
+ throw runtime_error(std::string(__func__) + ": unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
LogPrintf("keypool reserve %d\n", nIndex);
}
@@ -2795,7 +2799,7 @@ int64_t CWallet::GetOldestKeyPoolTime()
CWalletDB walletdb(strWalletFile);
int64_t nIndex = *(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error("GetOldestKeyPoolTime(): read oldest key in keypool failed");
+ throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
@@ -3022,11 +3026,11 @@ void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
- throw runtime_error("GetAllReserveKeyHashes(): read failed");
+ throw runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
- throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
+ throw runtime_error(std::string(__func__) + ": unknown key in key pool");
setAddress.insert(keyID);
}
}
@@ -3133,7 +3137,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
mapKeyBirth[it->first] = it->second.nCreateTime;
// map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
+ CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
std::set<CKeyID> setKeys;
GetKeys(setKeys);
@@ -3322,12 +3326,11 @@ bool CWallet::InitLoadWallet()
if (fFirstRun)
{
// Create new keyUser and set as default key
- if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) {
+ if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
// generate a new master key
- CKey key;
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
if (!walletInstance->SetHDMasterKey(masterPubKey))
- throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed");
+ throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
}
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
@@ -3340,9 +3343,9 @@ bool CWallet::InitLoadWallet()
}
else if (mapArgs.count("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
- if (!walletInstance->hdChain.masterKeyID.IsNull() && !useHD)
+ if (walletInstance->IsHDEnabled() && !useHD)
return InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
- if (walletInstance->hdChain.masterKeyID.IsNull() && useHD)
+ if (!walletInstance->IsHDEnabled() && useHD)
return InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
}
@@ -3412,7 +3415,17 @@ bool CWallet::InitLoadWallet()
}
walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
+ {
+ LOCK(walletInstance->cs_wallet);
+ LogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
+ LogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
+ LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
+ }
+ // Add wallet transactions that aren't already in a block to mapTransactions
+ walletInstance->ReacceptWalletTransactions();
+
pwalletMain = walletInstance;
+
return true;
}
@@ -3530,7 +3543,6 @@ CWalletKey::CWalletKey(int64_t nExpires)
int CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
{
AssertLockHeld(cs_main);
- CBlock blockTmp;
// Update the tx's hashBlock
hashBlock = pindex->GetBlockHash();
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 952acd1535..c06513650c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -582,6 +582,8 @@ private:
CHDChain hdChain;
bool fFileBacked;
+
+ std::set<int64_t> setKeyPool;
public:
/*
* Main wallet lock.
@@ -594,7 +596,18 @@ public:
std::string strWalletFile;
- std::set<int64_t> setKeyPool;
+ void LoadKeyPool(int nIndex, const CKeyPool &keypool)
+ {
+ setKeyPool.insert(nIndex);
+
+ // If no metadata exists yet, create a default with the pool key's
+ // creation time. Note that this may be overwritten by actually
+ // stored metadata for that key later, which is fine.
+ CKeyID keyid = keypool.vchPubKey.GetID();
+ if (mapKeyMetadata.count(keyid) == 0)
+ mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+ }
+
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
@@ -902,6 +915,9 @@ public:
bool SetHDChain(const CHDChain& chain, bool memonly);
const CHDChain& GetHDChain() { return hdChain; }
+ /* Returns true if HD is enabled */
+ bool IsHDEnabled();
+
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 543522ca64..80bfe8255d 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -18,7 +18,6 @@
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
using namespace std;
@@ -215,23 +214,23 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
Dbc* pcursor = GetCursor();
if (!pcursor)
- throw runtime_error("CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
- unsigned int fFlags = DB_SET_RANGE;
+ throw runtime_error(std::string(__func__) + ": cannot create DB cursor");
+ bool setRange = true;
while (true)
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- if (fFlags == DB_SET_RANGE)
+ if (setRange)
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange);
+ setRange = false;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
- throw runtime_error("CWalletDB::ListAccountCreditDebit(): error scanning DB");
+ throw runtime_error(std::string(__func__) + ": error scanning DB");
}
// Unserialize
@@ -556,14 +555,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> nIndex;
CKeyPool keypool;
ssValue >> keypool;
- pwallet->setKeyPool.insert(nIndex);
-
- // If no metadata exists yet, create a default with the pool key's
- // creation time. Note that this may be overwritten by actually
- // stored metadata for that key later, which is fine.
- CKeyID keyid = keypool.vchPubKey.GetID();
- if (pwallet->mapKeyMetadata.count(keyid) == 0)
- pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+
+ pwallet->LoadKeyPool(nIndex, keypool);
}
else if (strType == "version")
{
@@ -893,8 +886,8 @@ void ThreadFlushWalletDB(const string& strFile)
if (nRefCount == 0)
{
boost::this_thread::interruption_point();
- map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
- if (mi != bitdb.mapFileUseCount.end())
+ map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile);
+ if (_mi != bitdb.mapFileUseCount.end())
{
LogPrint("db", "Flushing %s\n", strFile);
nLastFlushed = nWalletDBUpdated;
@@ -904,7 +897,7 @@ void ThreadFlushWalletDB(const string& strFile)
bitdb.CloseDb(strFile);
bitdb.CheckpointLSN(strFile);
- bitdb.mapFileUseCount.erase(mi++);
+ bitdb.mapFileUseCount.erase(_mi++);
LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
}
}
@@ -947,7 +940,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
}
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
- boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
+ std::unique_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 22f02a3d0d..751ded3957 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -12,7 +12,7 @@ class CBlockIndex;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
{
private:
- uint32_t nSequence; //! upcounting per message sequence number
+ uint32_t nSequence; //!< upcounting per message sequence number
public: