aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-format2
-rw-r--r--src/Makefile.am5
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/bench/ellswift.cpp4
-rw-r--r--src/bench/readblock.cpp53
-rw-r--r--src/bench/rpc_blockchain.cpp4
-rw-r--r--src/bench/wallet_create.cpp2
-rw-r--r--src/bench/wallet_create_tx.cpp5
-rw-r--r--src/bitcoin-chainstate.cpp4
-rw-r--r--src/bitcoin-tx.cpp8
-rw-r--r--src/bitcoind.cpp5
-rw-r--r--src/common/args.cpp4
-rw-r--r--src/common/args.h8
-rw-r--r--src/httpserver.cpp13
-rw-r--r--src/httpserver.h9
-rw-r--r--src/index/base.cpp3
-rw-r--r--src/init.cpp80
-rw-r--r--src/init.h5
-rw-r--r--src/init/bitcoin-gui.cpp4
-rw-r--r--src/init/bitcoin-node.cpp4
-rw-r--r--src/init/bitcoin-qt.cpp4
-rw-r--r--src/init/bitcoind.cpp4
-rw-r--r--src/interfaces/chain.h3
-rw-r--r--src/kernel/context.cpp6
-rw-r--r--src/kernel/context.h15
-rw-r--r--src/kernel/mempool_entry.h6
-rw-r--r--src/key.cpp10
-rw-r--r--src/key.h2
-rw-r--r--src/net.cpp8
-rw-r--r--src/node/abort.cpp8
-rw-r--r--src/node/abort.h6
-rw-r--r--src/node/blockstorage.cpp4
-rw-r--r--src/node/blockstorage.h2
-rw-r--r--src/node/chainstate.cpp5
-rw-r--r--src/node/chainstate.h1
-rw-r--r--src/node/context.h2
-rw-r--r--src/node/interfaces.cpp18
-rw-r--r--src/node/kernel_notifications.cpp10
-rw-r--r--src/node/kernel_notifications.h7
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/fees.cpp2
-rw-r--r--src/qt/bitcoin.cpp5
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/guiutil.cpp5
-rw-r--r--src/qt/test/addressbooktests.cpp3
-rw-r--r--src/qt/test/apptests.cpp1
-rw-r--r--src/qt/winshutdownmonitor.cpp3
-rw-r--r--src/qt/winshutdownmonitor.h6
-rw-r--r--src/rest.cpp9
-rw-r--r--src/rpc/blockchain.cpp94
-rw-r--r--src/rpc/blockchain.h6
-rw-r--r--src/rpc/mempool.cpp2
-rw-r--r--src/rpc/mining.cpp9
-rw-r--r--src/rpc/rawtransaction.cpp7
-rw-r--r--src/rpc/server.cpp8
-rw-r--r--src/script/descriptor.cpp8
-rw-r--r--src/secp256k1/.cirrus.yml95
-rw-r--r--src/secp256k1/.github/actions/run-in-docker-action/action.yml6
-rw-r--r--src/secp256k1/.github/workflows/ci.yml6
-rw-r--r--src/secp256k1/CHANGELOG.md14
-rw-r--r--src/secp256k1/CMakeLists.txt14
-rw-r--r--src/secp256k1/CONTRIBUTING.md107
-rw-r--r--src/secp256k1/Makefile.am2
-rw-r--r--src/secp256k1/README.md32
-rwxr-xr-xsrc/secp256k1/ci/ci.sh16
-rw-r--r--src/secp256k1/ci/linux-debian.Dockerfile10
-rw-r--r--src/secp256k1/cmake/GeneratePkgConfigFile.cmake8
-rw-r--r--src/secp256k1/configure.ac20
-rw-r--r--src/secp256k1/doc/release-process.md11
-rw-r--r--src/secp256k1/src/CMakeLists.txt10
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s1
-rw-r--r--src/secp256k1/src/bench_internal.c59
-rw-r--r--src/secp256k1/src/ecdsa_impl.h7
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h385
-rw-r--r--src/secp256k1/src/field.h5
-rw-r--r--src/secp256k1/src/field_10x26_impl.h4
-rw-r--r--src/secp256k1/src/field_5x52_asm_impl.h504
-rw-r--r--src/secp256k1/src/field_5x52_impl.h4
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h13
-rw-r--r--src/secp256k1/src/field_impl.h160
-rw-r--r--src/secp256k1/src/group.h8
-rw-r--r--src/secp256k1/src/group_impl.h200
-rw-r--r--src/secp256k1/src/modinv32_impl.h33
-rw-r--r--src/secp256k1/src/modinv64_impl.h44
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h25
-rw-r--r--src/secp256k1/src/modules/ellswift/main_impl.h21
-rw-r--r--src/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h2
-rw-r--r--src/secp256k1/src/modules/ellswift/tests_impl.h6
-rw-r--r--src/secp256k1/src/modules/extrakeys/tests_impl.h167
-rw-r--r--src/secp256k1/src/modules/recovery/tests_impl.h69
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_impl.h67
-rw-r--r--src/secp256k1/src/scalar.h10
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h139
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h150
-rw-r--r--src/secp256k1/src/scalar_impl.h16
-rw-r--r--src/secp256k1/src/scalar_low.h11
-rw-r--r--src/secp256k1/src/scalar_low_impl.h87
-rw-r--r--src/secp256k1/src/tests.c674
-rw-r--r--src/secp256k1/src/tests_exhaustive.c77
-rw-r--r--src/secp256k1/src/testutil.h29
-rw-r--r--src/secp256k1/src/util.h11
-rwxr-xr-xsrc/secp256k1/tools/check-abi.sh64
-rw-r--r--src/serialize.h29
-rw-r--r--src/shutdown.cpp44
-rw-r--r--src/shutdown.h25
-rw-r--r--src/span.h6
-rw-r--r--src/test/amount_tests.cpp26
-rw-r--r--src/test/blockchain_tests.cpp2
-rw-r--r--src/test/blockfilter_index_tests.cpp7
-rw-r--r--src/test/blockmanager_tests.cpp8
-rw-r--r--src/test/coinstatsindex_tests.cpp4
-rw-r--r--src/test/compress_tests.cpp9
-rw-r--r--src/test/descriptor_tests.cpp4
-rw-r--r--src/test/fs_tests.cpp33
-rw-r--r--src/test/fuzz/descriptor_parse.cpp8
-rw-r--r--src/test/fuzz/http_request.cpp4
-rw-r--r--src/test/fuzz/minisketch.cpp26
-rw-r--r--src/test/fuzz/policy_estimator.cpp10
-rw-r--r--src/test/fuzz/process_message.cpp11
-rw-r--r--src/test/fuzz/process_messages.cpp3
-rw-r--r--src/test/fuzz/util/descriptor.cpp14
-rw-r--r--src/test/fuzz/util/descriptor.h10
-rw-r--r--src/test/policyestimator_tests.cpp27
-rw-r--r--src/test/script_p2sh_tests.cpp12
-rw-r--r--src/test/script_standard_tests.cpp12
-rw-r--r--src/test/script_tests.cpp19
-rw-r--r--src/test/sigopcount_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp28
-rw-r--r--src/test/txindex_tests.cpp2
-rw-r--r--src/test/txpackage_tests.cpp36
-rw-r--r--src/test/util/index.cpp6
-rw-r--r--src/test/util/index.h5
-rw-r--r--src/test/util/setup_common.cpp6
-rw-r--r--src/test/util/setup_common.h1
-rw-r--r--src/test/util_tests.cpp76
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp4
-rw-r--r--src/txmempool.cpp24
-rw-r--r--src/txmempool.h7
-rw-r--r--src/util/fs.cpp5
-rw-r--r--src/util/fs.h35
-rw-r--r--src/util/fs_helpers.cpp34
-rw-r--r--src/util/fs_helpers.h10
-rw-r--r--src/util/getuniquepath.cpp14
-rw-r--r--src/util/getuniquepath.h19
-rw-r--r--src/util/signalinterrupt.cpp15
-rw-r--r--src/util/signalinterrupt.h6
-rw-r--r--src/validation.cpp7
-rw-r--r--src/validationinterface.h2
-rw-r--r--src/wallet/bdb.cpp2
-rw-r--r--src/wallet/feebumper.cpp2
-rw-r--r--src/wallet/rpc/backup.cpp4
-rw-r--r--src/wallet/rpc/spend.cpp2
-rw-r--r--src/wallet/rpc/wallet.cpp8
-rw-r--r--src/wallet/scriptpubkeyman.cpp5
-rw-r--r--src/wallet/scriptpubkeyman.h6
-rw-r--r--src/wallet/spend.cpp15
-rw-r--r--src/wallet/spend.h2
-rw-r--r--src/wallet/test/coinselector_tests.cpp76
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp15
-rw-r--r--src/wallet/test/fuzz/fees.cpp7
-rw-r--r--src/wallet/test/fuzz/scriptpubkeyman.cpp12
-rw-r--r--src/wallet/test/ismine_tests.cpp3
-rw-r--r--src/wallet/test/spend_tests.cpp6
-rw-r--r--src/wallet/test/util.cpp1
-rw-r--r--src/wallet/test/wallet_tests.cpp14
-rw-r--r--src/wallet/wallet.cpp26
-rw-r--r--src/wallet/wallet.h7
-rw-r--r--src/wallet/walletdb.cpp4
168 files changed, 2247 insertions, 2590 deletions
diff --git a/src/.clang-format b/src/.clang-format
index 2e5d5c6449..f20e5ee2d4 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -43,5 +43,7 @@ SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
+BreakBeforeConceptDeclarations: Always
+RequiresExpressionIndentation: OuterScope
Standard: c++20
UseTab: Never
diff --git a/src/Makefile.am b/src/Makefile.am
index df56ac7090..b6f0daaaba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -271,7 +271,6 @@ BITCOIN_CORE_H = \
script/sign.h \
script/signingprovider.h \
script/solver.h \
- shutdown.h \
signet.h \
streams.h \
support/allocators/pool.h \
@@ -304,7 +303,6 @@ BITCOIN_CORE_H = \
util/fees.h \
util/fs.h \
util/fs_helpers.h \
- util/getuniquepath.h \
util/golombrice.h \
util/hash_type.h \
util/hasher.h \
@@ -459,7 +457,6 @@ libbitcoin_node_a_SOURCES = \
rpc/signmessage.cpp \
rpc/txoutproof.cpp \
script/sigcache.cpp \
- shutdown.cpp \
signet.cpp \
timedata.cpp \
torcontrol.cpp \
@@ -741,7 +738,6 @@ libbitcoin_util_a_SOURCES = \
util/fees.cpp \
util/fs.cpp \
util/fs_helpers.cpp \
- util/getuniquepath.cpp \
util/hasher.cpp \
util/sock.cpp \
util/syserror.cpp \
@@ -984,7 +980,6 @@ libbitcoinkernel_la_SOURCES = \
util/exception.cpp \
util/fs.cpp \
util/fs_helpers.cpp \
- util/getuniquepath.cpp \
util/hasher.cpp \
util/moneystr.cpp \
util/rbf.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 217f123b16..9e5366f0b4 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -46,6 +46,7 @@ bench_bench_bitcoin_SOURCES = \
bench/poly1305.cpp \
bench/pool.cpp \
bench/prevector.cpp \
+ bench/readblock.cpp \
bench/rollingbloom.cpp \
bench/rpc_blockchain.cpp \
bench/rpc_mempool.cpp \
diff --git a/src/bench/ellswift.cpp b/src/bench/ellswift.cpp
index f0348421b3..82e8dec982 100644
--- a/src/bench/ellswift.cpp
+++ b/src/bench/ellswift.cpp
@@ -11,9 +11,7 @@ static void EllSwiftCreate(benchmark::Bench& bench)
{
ECC_Start();
- CKey key;
- key.MakeNewKey(true);
-
+ CKey key = GenerateRandomKey();
uint256 entropy = GetRandHash();
bench.batch(1).unit("pubkey").run([&] {
diff --git a/src/bench/readblock.cpp b/src/bench/readblock.cpp
new file mode 100644
index 0000000000..0545c6b017
--- /dev/null
+++ b/src/bench/readblock.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2023 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 <bench/bench.h>
+#include <bench/data.h>
+
+#include <consensus/validation.h>
+#include <node/blockstorage.h>
+#include <streams.h>
+#include <test/util/setup_common.h>
+#include <util/chaintype.h>
+#include <validation.h>
+
+static FlatFilePos WriteBlockToDisk(ChainstateManager& chainman)
+{
+ DataStream stream{benchmark::data::block413567};
+ CBlock block;
+ stream >> TX_WITH_WITNESS(block);
+
+ return chainman.m_blockman.SaveBlockToDisk(block, 0, nullptr);
+}
+
+static void ReadBlockFromDiskTest(benchmark::Bench& bench)
+{
+ const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
+ ChainstateManager& chainman{*testing_setup->m_node.chainman};
+
+ CBlock block;
+ const auto pos{WriteBlockToDisk(chainman)};
+
+ bench.run([&] {
+ const auto success{chainman.m_blockman.ReadBlockFromDisk(block, pos)};
+ assert(success);
+ });
+}
+
+static void ReadRawBlockFromDiskTest(benchmark::Bench& bench)
+{
+ const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
+ ChainstateManager& chainman{*testing_setup->m_node.chainman};
+
+ std::vector<uint8_t> block_data;
+ const auto pos{WriteBlockToDisk(chainman)};
+
+ bench.run([&] {
+ const auto success{chainman.m_blockman.ReadRawBlockFromDisk(block_data, pos)};
+ assert(success);
+ });
+}
+
+BENCHMARK(ReadBlockFromDiskTest, benchmark::PriorityLevel::HIGH);
+BENCHMARK(ReadRawBlockFromDiskTest, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index 2416d40798..713853e8c5 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -41,7 +41,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
{
TestBlockAndIndex data;
bench.run([&] {
- auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
+ auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
ankerl::nanobench::doNotOptimizeAway(univalue);
});
}
@@ -51,7 +51,7 @@ BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{
TestBlockAndIndex data;
- auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
+ auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
bench.run([&] {
auto str = univalue.write();
ankerl::nanobench::doNotOptimizeAway(str);
diff --git a/src/bench/wallet_create.cpp b/src/bench/wallet_create.cpp
index ba3c25d25e..993c4c4b3f 100644
--- a/src/bench/wallet_create.cpp
+++ b/src/bench/wallet_create.cpp
@@ -34,7 +34,7 @@ static void WalletCreate(benchmark::Bench& bench, bool encrypted)
fs::path wallet_path = test_setup->m_path_root / strprintf("test_wallet_%d", random.rand32()).c_str();
bench.run([&] {
- auto wallet = CreateWallet(context, wallet_path.u8string(), /*load_on_start=*/std::nullopt, options, status, error_string, warnings);
+ auto wallet = CreateWallet(context, wallet_path.utf8string(), /*load_on_start=*/std::nullopt, options, status, error_string, warnings);
assert(status == DatabaseStatus::SUCCESS);
assert(wallet != nullptr);
diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp
index 632918c0ca..84e02d2a26 100644
--- a/src/bench/wallet_create_tx.cpp
+++ b/src/bench/wallet_create_tx.cpp
@@ -16,7 +16,6 @@
using wallet::CWallet;
using wallet::CreateMockableWalletDatabase;
-using wallet::DBErrors;
using wallet::WALLET_FLAG_DESCRIPTORS;
struct TipBlock
@@ -90,7 +89,6 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetupDescriptorScriptPubKeyMans();
- if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
}
// Generate destinations
@@ -131,7 +129,7 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
bench.epochIterations(5).run([&] {
LOCK(wallet.cs_wallet);
- const auto& tx_res = CreateTransaction(wallet, recipients, -1, coin_control);
+ const auto& tx_res = CreateTransaction(wallet, recipients, /*change_pos=*/std::nullopt, coin_control);
assert(tx_res);
});
}
@@ -146,7 +144,6 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetupDescriptorScriptPubKeyMans();
- if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
}
// Generate destinations
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index 31edb86ce2..ee8b0a44c5 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -125,14 +125,14 @@ int main(int argc, char* argv[])
.blocks_dir = abs_datadir / "blocks",
.notifications = chainman_opts.notifications,
};
- ChainstateManager chainman{kernel_context.interrupt, chainman_opts, blockman_opts};
+ util::SignalInterrupt interrupt;
+ ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
node::CacheSizes cache_sizes;
cache_sizes.block_tree_db = 2 << 20;
cache_sizes.coins_db = 2 << 22;
cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
node::ChainstateLoadOptions options;
- options.check_interrupt = [] { return false; };
auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 8fe2881f6f..320624c419 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -66,7 +66,9 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman)
argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
"Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
"Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
- argsman.AddArg("replaceable(=N)", "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
+ argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. "
+ "If N is not provided, the command attempts to opt-in all available inputs for RBF. "
+ "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "
"This command requires JSON registers:"
"prevtxs=JSON object, "
@@ -223,8 +225,8 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested index
- int64_t inIdx;
- if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
+ int64_t inIdx = -1;
+ if (strInIdx != "" && (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size()))) {
throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index e2224befef..4f0a816388 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -20,7 +20,6 @@
#include <node/context.h>
#include <node/interface_ui.h>
#include <noui.h>
-#include <shutdown.h>
#include <util/check.h>
#include <util/exception.h>
#include <util/strencodings.h>
@@ -272,9 +271,7 @@ MAIN_FUNCTION
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
// Start application
- if (AppInit(node)) {
- WaitForShutdown();
- } else {
+ if (!AppInit(node) || !Assert(node.shutdown)->wait()) {
node.exit_status = EXIT_FAILURE;
}
Interrupt(node);
diff --git a/src/common/args.cpp b/src/common/args.cpp
index 1f25d13bee..a9108e5916 100644
--- a/src/common/args.cpp
+++ b/src/common/args.cpp
@@ -277,7 +277,7 @@ fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value)
return result.has_filename() ? result : result.parent_path();
}
-const fs::path& ArgsManager::GetBlocksDirPath() const
+fs::path ArgsManager::GetBlocksDirPath() const
{
LOCK(cs_args);
fs::path& path = m_cached_blocks_path;
@@ -302,7 +302,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const
return path;
}
-const fs::path& ArgsManager::GetDataDir(bool net_specific) const
+fs::path ArgsManager::GetDataDir(bool net_specific) const
{
LOCK(cs_args);
fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
diff --git a/src/common/args.h b/src/common/args.h
index 1c5db718f4..6451b194d1 100644
--- a/src/common/args.h
+++ b/src/common/args.h
@@ -215,21 +215,21 @@ protected:
*
* @return Blocks path which is network specific
*/
- const fs::path& GetBlocksDirPath() const;
+ fs::path GetBlocksDirPath() const;
/**
* Get data directory path
*
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
*/
- const fs::path& GetDataDirBase() const { return GetDataDir(false); }
+ fs::path GetDataDirBase() const { return GetDataDir(false); }
/**
* Get data directory path with appended network identifier
*
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
*/
- const fs::path& GetDataDirNet() const { return GetDataDir(true); }
+ fs::path GetDataDirNet() const { return GetDataDir(true); }
/**
* Clear cached directory paths
@@ -420,7 +420,7 @@ private:
* @param net_specific Append network identifier to the returned path
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
*/
- const fs::path& GetDataDir(bool net_specific) const;
+ fs::path GetDataDir(bool net_specific) const;
/**
* Return -regtest/-signet/-testnet/-chain= setting as a ChainType enum if a
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 4c14c5b939..e26ea6a596 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -15,9 +15,9 @@
#include <netbase.h>
#include <node/interface_ui.h>
#include <rpc/protocol.h> // For HTTP status codes
-#include <shutdown.h>
#include <sync.h>
#include <util/check.h>
+#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/threadnames.h>
#include <util/translation.h>
@@ -284,7 +284,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
}
}
}
- std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
+ auto hreq{std::make_unique<HTTPRequest>(req, *static_cast<const util::SignalInterrupt*>(arg))};
// Early address-based allow check
if (!ClientAllowed(hreq->GetPeer())) {
@@ -425,7 +425,7 @@ static void libevent_log_cb(int severity, const char *msg)
LogPrintLevel(BCLog::LIBEVENT, level, "%s\n", msg);
}
-bool InitHTTPServer()
+bool InitHTTPServer(const util::SignalInterrupt& interrupt)
{
if (!InitHTTPAllowList())
return false;
@@ -454,7 +454,7 @@ bool InitHTTPServer()
evhttp_set_timeout(http, gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
evhttp_set_max_body_size(http, MAX_SIZE);
- evhttp_set_gencb(http, http_request_cb, nullptr);
+ evhttp_set_gencb(http, http_request_cb, (void*)&interrupt);
if (!HTTPBindAddresses(http)) {
LogPrintf("Unable to bind any endpoint for RPC server\n");
@@ -579,7 +579,8 @@ void HTTPEvent::trigger(struct timeval* tv)
else
evtimer_add(ev, tv); // trigger after timeval passed
}
-HTTPRequest::HTTPRequest(struct evhttp_request* _req, bool _replySent) : req(_req), replySent(_replySent)
+HTTPRequest::HTTPRequest(struct evhttp_request* _req, const util::SignalInterrupt& interrupt, bool _replySent)
+ : req(_req), m_interrupt(interrupt), replySent(_replySent)
{
}
@@ -639,7 +640,7 @@ void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
{
assert(!replySent && req);
- if (ShutdownRequested()) {
+ if (m_interrupt) {
WriteHeader("Connection", "close");
}
// Send event to main http thread to send reply message
diff --git a/src/httpserver.h b/src/httpserver.h
index 036a39a023..9a49877f09 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -9,6 +9,10 @@
#include <optional>
#include <string>
+namespace util {
+class SignalInterrupt;
+} // namespace util
+
static const int DEFAULT_HTTP_THREADS=4;
static const int DEFAULT_HTTP_WORKQUEUE=16;
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;
@@ -21,7 +25,7 @@ class HTTPRequest;
/** Initialize HTTP server.
* Call this before RegisterHTTPHandler or EventBase().
*/
-bool InitHTTPServer();
+bool InitHTTPServer(const util::SignalInterrupt& interrupt);
/** Start HTTP server.
* This is separate from InitHTTPServer to give users race-condition-free time
* to register their handlers between InitHTTPServer and StartHTTPServer.
@@ -57,10 +61,11 @@ class HTTPRequest
{
private:
struct evhttp_request* req;
+ const util::SignalInterrupt& m_interrupt;
bool replySent;
public:
- explicit HTTPRequest(struct evhttp_request* req, bool replySent = false);
+ explicit HTTPRequest(struct evhttp_request* req, const util::SignalInterrupt& interrupt, bool replySent = false);
~HTTPRequest();
enum RequestMethod {
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 8474d01c41..bcfe7215be 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -13,7 +13,6 @@
#include <node/context.h>
#include <node/database_args.h>
#include <node/interface_ui.h>
-#include <shutdown.h>
#include <tinyformat.h>
#include <util/thread.h>
#include <util/translation.h>
@@ -32,7 +31,7 @@ template <typename... Args>
void BaseIndex::FatalErrorf(const char* fmt, const Args&... args)
{
auto message = tfm::format(fmt, args...);
- node::AbortNode(m_chain->context()->exit_status, message);
+ node::AbortNode(m_chain->context()->shutdown, m_chain->context()->exit_status, message);
}
CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)
diff --git a/src/init.cpp b/src/init.cpp
index 3d6d04a1ec..39ee9fe60d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -66,7 +66,6 @@
#include <rpc/util.h>
#include <scheduler.h>
#include <script/sigcache.h>
-#include <shutdown.h>
#include <sync.h>
#include <timedata.h>
#include <torcontrol.h>
@@ -192,6 +191,16 @@ static void RemovePidFile(const ArgsManager& args)
}
}
+static std::optional<util::SignalInterrupt> g_shutdown;
+
+void InitContext(NodeContext& node)
+{
+ assert(!g_shutdown);
+ g_shutdown.emplace();
+
+ node.args = &gArgs;
+ node.shutdown = &*g_shutdown;
+}
//////////////////////////////////////////////////////////////////////////////
//
@@ -204,11 +213,9 @@ static void RemovePidFile(const ArgsManager& args)
// The network-processing threads are all part of a thread group
// created by AppInit() or the Qt main() function.
//
-// A clean exit happens when StartShutdown() or the SIGTERM
-// signal handler sets ShutdownRequested(), which makes main thread's
-// WaitForShutdown() interrupts the thread group.
-// And then, WaitForShutdown() makes all other on-going threads
-// in the thread group join the main thread.
+// A clean exit happens when the SignalInterrupt object is triggered, which
+// makes the main thread's SignalInterrupt::wait() call return, and join all
+// other ongoing threads in the thread group to the main thread.
// Shutdown() is then called to clean up database connections, and stop other
// threads that should only be stopped after the main network-processing
// threads have exited.
@@ -218,6 +225,11 @@ static void RemovePidFile(const ArgsManager& args)
// shutdown thing.
//
+bool ShutdownRequested(node::NodeContext& node)
+{
+ return bool{*Assert(node.shutdown)};
+}
+
#if HAVE_SYSTEM
static void ShutdownNotify(const ArgsManager& args)
{
@@ -301,7 +313,7 @@ void Shutdown(NodeContext& node)
DumpMempool(*node.mempool, MempoolPath(*node.args));
}
- // Drop transactions we were still watching, record fee estimations and Unregister
+ // Drop transactions we were still watching, record fee estimations and unregister
// fee estimator from validation interface.
if (node.fee_estimator) {
node.fee_estimator->Flush();
@@ -382,7 +394,9 @@ void Shutdown(NodeContext& node)
#ifndef WIN32
static void HandleSIGTERM(int)
{
- StartShutdown();
+ // Return value is intentionally ignored because there is not a better way
+ // of handling this failure in a signal handler.
+ (void)(*Assert(g_shutdown))();
}
static void HandleSIGHUP(int)
@@ -392,7 +406,10 @@ static void HandleSIGHUP(int)
#else
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
{
- StartShutdown();
+ if (!(*Assert(g_shutdown))()) {
+ LogPrintf("Error: failed to send shutdown signal on Ctrl-C\n");
+ return false;
+ }
Sleep(INFINITE);
return true;
}
@@ -689,8 +706,9 @@ static bool AppInitServers(NodeContext& node)
const ArgsManager& args = *Assert(node.args);
RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
- if (!InitHTTPServer())
+ if (!InitHTTPServer(*Assert(node.shutdown))) {
return false;
+ }
StartRPC();
node.rpc_interruption_point = RpcInterruptionPoint;
if (!StartHTTPRPC(&node))
@@ -1036,13 +1054,14 @@ static bool LockDataDirectory(bool probeOnly)
{
// Make sure only a single Bitcoin process is using the data directory.
const fs::path& datadir = gArgs.GetDataDirNet();
- if (!DirIsWritable(datadir)) {
+ switch (util::LockDirectory(datadir, ".lock", probeOnly)) {
+ case util::LockResult::ErrorWrite:
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir)));
- }
- if (!LockDirectory(datadir, ".lock", probeOnly)) {
+ case util::LockResult::ErrorLock:
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME));
- }
- return true;
+ case util::LockResult::Success: return true;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
bool AppInitSanityChecks(const kernel::Context& kernel)
@@ -1129,11 +1148,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}, std::chrono::minutes{1});
// Check disk space every 5 minutes to avoid db corruption.
- node.scheduler->scheduleEvery([&args]{
+ node.scheduler->scheduleEvery([&args, &node]{
constexpr uint64_t min_disk_space = 50 << 20; // 50 MB
if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) {
LogPrintf("Shutting down due to lack of disk space!\n");
- StartShutdown();
+ if (!(*Assert(node.shutdown))()) {
+ LogPrintf("Error: failed to send shutdown signal after disk space check\n");
+ }
}
}, std::chrono::minutes{5});
@@ -1420,7 +1441,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 7: load block chain
- node.notifications = std::make_unique<KernelNotifications>(node.exit_status);
+ node.notifications = std::make_unique<KernelNotifications>(*Assert(node.shutdown), node.exit_status);
ReadNotificationArgs(args, *node.notifications);
fReindex = args.GetBoolArg("-reindex", false);
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
@@ -1471,10 +1492,10 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
- for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
+ for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
- node.chainman = std::make_unique<ChainstateManager>(node.kernel->interrupt, chainman_opts, blockman_opts);
+ node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
ChainstateManager& chainman = *node.chainman;
// This is defined and set here instead of inline in validation.h to avoid a hard
@@ -1504,7 +1525,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel");
- options.check_interrupt = ShutdownRequested;
options.coins_error_cb = [] {
uiInterface.ThreadSafeMessageBox(
_("Error reading from database, shutting down."),
@@ -1539,7 +1559,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return InitError(error);
}
- if (!fLoaded && !ShutdownRequested()) {
+ if (!fLoaded && !ShutdownRequested(node)) {
// first suggest a reindex
if (!options.reindex) {
bool fRet = uiInterface.ThreadSafeQuestion(
@@ -1548,7 +1568,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
if (fRet) {
fReindex = true;
- AbortShutdown();
+ if (!Assert(node.shutdown)->reset()) {
+ LogPrintf("Internal error: failed to reset shutdown signal.\n");
+ }
} else {
LogPrintf("Aborted block database rebuild. Exiting.\n");
return false;
@@ -1562,7 +1584,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// As LoadBlockIndex can take several minutes, it's possible the user
// requested to kill the GUI during the last operation. If so, exit.
// As the program has not fully started yet, Shutdown() is possibly overkill.
- if (ShutdownRequested()) {
+ if (ShutdownRequested(node)) {
LogPrintf("Shutdown requested. Exiting.\n");
return false;
}
@@ -1683,7 +1705,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
ImportBlocks(chainman, vImportFiles);
if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
LogPrintf("Stopping after block import\n");
- StartShutdown();
+ if (!(*Assert(node.shutdown))()) {
+ LogPrintf("Error: failed to send shutdown signal after finishing block import\n");
+ }
return;
}
@@ -1703,16 +1727,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Wait for genesis block to be processed
{
WAIT_LOCK(g_genesis_wait_mutex, lock);
- // We previously could hang here if StartShutdown() is called prior to
+ // We previously could hang here if shutdown was requested prior to
// ImportBlocks getting started, so instead we just wait on a timer to
// check ShutdownRequested() regularly.
- while (!fHaveGenesis && !ShutdownRequested()) {
+ while (!fHaveGenesis && !ShutdownRequested(node)) {
g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500));
}
block_notify_genesis_wait_connection.disconnect();
}
- if (ShutdownRequested()) {
+ if (ShutdownRequested(node)) {
return false;
}
diff --git a/src/init.h b/src/init.h
index f27d6120ef..ead5f5e0d2 100644
--- a/src/init.h
+++ b/src/init.h
@@ -26,6 +26,11 @@ namespace node {
struct NodeContext;
} // namespace node
+/** Initialize node context shutdown and args variables. */
+void InitContext(node::NodeContext& node);
+/** Return whether node shutdown was requested. */
+bool ShutdownRequested(node::NodeContext& node);
+
/** Interrupt threads */
void Interrupt(node::NodeContext& node);
void Shutdown(node::NodeContext& node);
diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp
index ddbdaa6cd0..aceff1e40f 100644
--- a/src/init/bitcoin-gui.cpp
+++ b/src/init/bitcoin-gui.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <common/args.h>
+#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -23,7 +23,7 @@ class BitcoinGuiInit : public interfaces::Init
public:
BitcoinGuiInit(const char* arg0) : m_ipc(interfaces::MakeIpc(EXE_NAME, arg0, *this))
{
- m_node.args = &gArgs;
+ InitContext(m_node);
m_node.init = this;
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp
index b04596f986..97b8dc1161 100644
--- a/src/init/bitcoin-node.cpp
+++ b/src/init/bitcoin-node.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <common/args.h>
+#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -25,7 +25,7 @@ public:
: m_node(node),
m_ipc(interfaces::MakeIpc(EXE_NAME, arg0, *this))
{
- m_node.args = &gArgs;
+ InitContext(m_node);
m_node.init = this;
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp
index dd5826d982..3003a8fde1 100644
--- a/src/init/bitcoin-qt.cpp
+++ b/src/init/bitcoin-qt.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <common/args.h>
+#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -20,7 +20,7 @@ class BitcoinQtInit : public interfaces::Init
public:
BitcoinQtInit()
{
- m_node.args = &gArgs;
+ InitContext(m_node);
m_node.init = this;
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp
index 210608370c..b5df764017 100644
--- a/src/init/bitcoind.cpp
+++ b/src/init/bitcoind.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <common/args.h>
+#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -22,7 +22,7 @@ class BitcoindInit : public interfaces::Init
public:
BitcoindInit(NodeContext& node) : m_node(node)
{
- m_node.args = &gArgs;
+ InitContext(m_node);
m_node.init = this;
}
std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); }
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index c5f956822f..9da5cb9637 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -8,6 +8,7 @@
#include <blockfilter.h>
#include <common/settings.h>
#include <primitives/transaction.h> // For CTransactionRef
+#include <util/result.h>
#include <functional>
#include <memory>
@@ -260,7 +261,7 @@ public:
virtual void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) = 0;
//! Check if transaction will pass the mempool's chain limits.
- virtual bool checkChainLimits(const CTransactionRef& tx) = 0;
+ virtual util::Result<void> checkChainLimits(const CTransactionRef& tx) = 0;
//! Estimate smart fee.
virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc = nullptr) = 0;
diff --git a/src/kernel/context.cpp b/src/kernel/context.cpp
index 3f4a423531..c60f1638d1 100644
--- a/src/kernel/context.cpp
+++ b/src/kernel/context.cpp
@@ -14,12 +14,8 @@
namespace kernel {
-Context* g_context;
-
Context::Context()
{
- assert(!g_context);
- g_context = this;
std::string sha256_algo = SHA256AutoDetect();
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
RandomInit();
@@ -29,8 +25,6 @@ Context::Context()
Context::~Context()
{
ECC_Stop();
- assert(g_context);
- g_context = nullptr;
}
} // namespace kernel
diff --git a/src/kernel/context.h b/src/kernel/context.h
index e74e0a6f08..ff4df20473 100644
--- a/src/kernel/context.h
+++ b/src/kernel/context.h
@@ -18,24 +18,9 @@ namespace kernel {
//! State stored directly in this struct should be simple. More complex state
//! should be stored to std::unique_ptr members pointing to opaque types.
struct Context {
- //! Interrupt object that can be used to stop long-running kernel operations.
- util::SignalInterrupt interrupt;
-
- //! Declare default constructor and destructor that are not inline, so code
- //! instantiating the kernel::Context struct doesn't need to #include class
- //! definitions for all the unique_ptr members.
Context();
~Context();
};
-
-//! Global pointer to kernel::Context for legacy code. New code should avoid
-//! using this, and require state it needs to be passed to it directly.
-//!
-//! Having this pointer is useful because it allows state be moved out of global
-//! variables into the kernel::Context struct before all global references to
-//! that state are removed. This allows the global references to be removed
-//! incrementally, instead of all at once.
-extern Context* g_context;
} // namespace kernel
#endif // BITCOIN_KERNEL_CONTEXT_H
diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h
index bd39c9cc5f..2adeaea652 100644
--- a/src/kernel/mempool_entry.h
+++ b/src/kernel/mempool_entry.h
@@ -226,7 +226,7 @@ struct NewMempoolTransactionInfo {
* This boolean indicates whether the transaction was added
* without enforcing mempool fee limits.
*/
- const bool m_from_disconnected_block;
+ const bool m_mempool_limit_bypassed;
/* This boolean indicates whether the transaction is part of a package. */
const bool m_submitted_in_package;
/*
@@ -239,11 +239,11 @@ struct NewMempoolTransactionInfo {
explicit NewMempoolTransactionInfo(const CTransactionRef& tx, const CAmount& fee,
const int64_t vsize, const unsigned int height,
- const bool from_disconnected_block, const bool submitted_in_package,
+ const bool mempool_limit_bypassed, const bool submitted_in_package,
const bool chainstate_is_current,
const bool has_no_mempool_parents)
: info{tx, fee, vsize, height},
- m_from_disconnected_block{from_disconnected_block},
+ m_mempool_limit_bypassed{mempool_limit_bypassed},
m_submitted_in_package{submitted_in_package},
m_chainstate_is_current{chainstate_is_current},
m_has_no_mempool_parents{has_no_mempool_parents} {}
diff --git a/src/key.cpp b/src/key.cpp
index 0f283ca3e3..512790252a 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -369,6 +369,13 @@ ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, c
return output;
}
+CKey GenerateRandomKey(bool compressed) noexcept
+{
+ CKey key;
+ key.MakeNewKey(/*fCompressed=*/compressed);
+ return key;
+}
+
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
out.nDepth = nDepth + 1;
@@ -420,8 +427,7 @@ void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
}
bool ECC_InitSanityCheck() {
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
CPubKey pubkey = key.GetPubKey();
return key.VerifyPubKey(pubkey);
}
diff --git a/src/key.h b/src/key.h
index 785059da02..9cac716ec8 100644
--- a/src/key.h
+++ b/src/key.h
@@ -205,6 +205,8 @@ public:
bool initiating) const;
};
+CKey GenerateRandomKey(bool compressed = true) noexcept;
+
struct CExtKey {
unsigned char nDepth;
unsigned char vchFingerprint[4];
diff --git a/src/net.cpp b/src/net.cpp
index 102d81579f..41f5323d91 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -18,6 +18,7 @@
#include <consensus/consensus.h>
#include <crypto/sha256.h>
#include <i2p.h>
+#include <key.h>
#include <logging.h>
#include <memusage.h>
#include <net_permissions.h>
@@ -938,13 +939,6 @@ public:
const V2MessageMap V2_MESSAGE_MAP;
-CKey GenerateRandomKey() noexcept
-{
- CKey key;
- key.MakeNewKey(/*fCompressed=*/true);
- return key;
-}
-
std::vector<uint8_t> GenerateRandomGarbage() noexcept
{
std::vector<uint8_t> ret;
diff --git a/src/node/abort.cpp b/src/node/abort.cpp
index a554126b86..1bdc91670d 100644
--- a/src/node/abort.cpp
+++ b/src/node/abort.cpp
@@ -6,7 +6,7 @@
#include <logging.h>
#include <node/interface_ui.h>
-#include <shutdown.h>
+#include <util/signalinterrupt.h>
#include <util/translation.h>
#include <warnings.h>
@@ -16,12 +16,14 @@
namespace node {
-void AbortNode(std::atomic<int>& exit_status, const std::string& debug_message, const bilingual_str& user_message, bool shutdown)
+void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const std::string& debug_message, const bilingual_str& user_message)
{
SetMiscWarning(Untranslated(debug_message));
LogPrintf("*** %s\n", debug_message);
InitError(user_message.empty() ? _("A fatal internal error occurred, see debug.log for details") : user_message);
exit_status.store(EXIT_FAILURE);
- if (shutdown) StartShutdown();
+ if (shutdown && !(*shutdown)()) {
+ LogPrintf("Error: failed to send shutdown signal\n");
+ };
}
} // namespace node
diff --git a/src/node/abort.h b/src/node/abort.h
index d6bb0c14d5..28d021cc78 100644
--- a/src/node/abort.h
+++ b/src/node/abort.h
@@ -10,8 +10,12 @@
#include <atomic>
#include <string>
+namespace util {
+class SignalInterrupt;
+} // namespace util
+
namespace node {
-void AbortNode(std::atomic<int>& exit_status, const std::string& debug_message, const bilingual_str& user_message = {}, bool shutdown = true);
+void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const std::string& debug_message, const bilingual_str& user_message = {});
} // namespace node
#endif // BITCOIN_NODE_ABORT_H
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index ebc08d7567..e6164c2e59 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -582,10 +582,10 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
return nullptr;
}
-bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex)
+bool BlockManager::IsBlockPruned(const CBlockIndex& block)
{
AssertLockHeld(::cs_main);
- return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
+ return m_have_pruned && !(block.nStatus & BLOCK_HAVE_DATA) && (block.nTx > 0);
}
const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& upper_block, const CBlockIndex* lower_block)
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index d540406ae5..ce514cc645 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -344,7 +344,7 @@ public:
bool m_have_pruned = false;
//! Check whether the block associated with this index entry is pruned or not.
- bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ bool IsBlockPruned(const CBlockIndex& block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
//! Create or update a prune lock identified by its name
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index eb1994177a..bf1fc06b0b 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -17,6 +17,7 @@
#include <txdb.h>
#include <uint256.h>
#include <util/fs.h>
+#include <util/signalinterrupt.h>
#include <util/time.h>
#include <util/translation.h>
#include <validation.h>
@@ -55,14 +56,14 @@ static ChainstateLoadResult CompleteChainstateInitialization(
}
}
- if (options.check_interrupt && options.check_interrupt()) return {ChainstateLoadStatus::INTERRUPTED, {}};
+ if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
// LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
// Note that it also sets fReindex global based on the disk flag!
// From here on, fReindex and options.reindex values may be different!
if (!chainman.LoadBlockIndex()) {
- if (options.check_interrupt && options.check_interrupt()) return {ChainstateLoadStatus::INTERRUPTED, {}};
+ if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
}
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index 2e35035c28..a6e9a0331b 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -32,7 +32,6 @@ struct ChainstateLoadOptions {
bool require_full_verification{true};
int64_t check_blocks{DEFAULT_CHECKBLOCKS};
int64_t check_level{DEFAULT_CHECKLEVEL};
- std::function<bool()> check_interrupt;
std::function<void()> coins_error_cb;
};
diff --git a/src/node/context.h b/src/node/context.h
index dae900ff7f..4f3b640b2d 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -50,6 +50,8 @@ struct NodeContext {
std::unique_ptr<kernel::Context> kernel;
//! Init interface for initializing current process and connecting to other processes.
interfaces::Init* init{nullptr};
+ //! Interrupt object used to track whether node shutdown was requested.
+ util::SignalInterrupt* shutdown{nullptr};
std::unique_ptr<AddrMan> addrman;
std::unique_ptr<CConnman> connman;
std::unique_ptr<CTxMemPool> mempool;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 56d841b311..5a8b7fc105 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -39,13 +39,14 @@
#include <primitives/transaction.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
-#include <shutdown.h>
#include <support/allocators/secure.h>
#include <sync.h>
#include <txmempool.h>
#include <uint256.h>
#include <univalue.h>
#include <util/check.h>
+#include <util/result.h>
+#include <util/signalinterrupt.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -120,14 +121,16 @@ public:
}
void startShutdown() override
{
- StartShutdown();
+ if (!(*Assert(Assert(m_context)->shutdown))()) {
+ LogPrintf("Error: failed to send shutdown signal\n");
+ }
// Stop RPC for clean shutdown if any of waitfor* commands is executed.
if (args().GetBoolArg("-server", false)) {
InterruptRPC();
StopRPC();
}
}
- bool shutdownRequested() override { return ShutdownRequested(); }
+ bool shutdownRequested() override { return ShutdownRequested(*Assert(m_context)); };
bool isSettingIgnored(const std::string& name) override
{
bool ignored = false;
@@ -700,14 +703,13 @@ public:
limit_ancestor_count = limits.ancestor_count;
limit_descendant_count = limits.descendant_count;
}
- bool checkChainLimits(const CTransactionRef& tx) override
+ util::Result<void> checkChainLimits(const CTransactionRef& tx) override
{
- if (!m_node.mempool) return true;
+ if (!m_node.mempool) return {};
LockPoints lp;
CTxMemPoolEntry entry(tx, 0, 0, 0, 0, false, 0, lp);
LOCK(m_node.mempool->cs);
- std::string err_string;
- return m_node.mempool->CheckPackageLimits({tx}, entry.GetTxSize(), err_string);
+ return m_node.mempool->CheckPackageLimits({tx}, entry.GetTxSize());
}
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
{
@@ -749,7 +751,7 @@ public:
{
return chainman().IsInitialBlockDownload();
}
- bool shutdownRequested() override { return ShutdownRequested(); }
+ bool shutdownRequested() override { return ShutdownRequested(m_node); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
void initWarning(const bilingual_str& message) override { InitWarning(message); }
void initError(const bilingual_str& message) override { InitError(message); }
diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp
index 7224127c72..1fd3bad296 100644
--- a/src/node/kernel_notifications.cpp
+++ b/src/node/kernel_notifications.cpp
@@ -15,7 +15,6 @@
#include <logging.h>
#include <node/abort.h>
#include <node/interface_ui.h>
-#include <shutdown.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -62,7 +61,9 @@ kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state
{
uiInterface.NotifyBlockTip(state, &index);
if (m_stop_at_height && index.nHeight >= m_stop_at_height) {
- StartShutdown();
+ if (!m_shutdown()) {
+ LogPrintf("Error: failed to send shutdown signal after reaching stop height\n");
+ }
return kernel::Interrupted{};
}
return {};
@@ -85,12 +86,13 @@ void KernelNotifications::warning(const bilingual_str& warning)
void KernelNotifications::flushError(const std::string& debug_message)
{
- AbortNode(m_exit_status, debug_message);
+ AbortNode(&m_shutdown, m_exit_status, debug_message);
}
void KernelNotifications::fatalError(const std::string& debug_message, const bilingual_str& user_message)
{
- node::AbortNode(m_exit_status, debug_message, user_message, m_shutdown_on_fatal_error);
+ node::AbortNode(m_shutdown_on_fatal_error ? &m_shutdown : nullptr,
+ m_exit_status, debug_message, user_message);
}
void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications)
diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h
index b2dfc03398..38d8600ac6 100644
--- a/src/node/kernel_notifications.h
+++ b/src/node/kernel_notifications.h
@@ -16,6 +16,10 @@ class CBlockIndex;
enum class SynchronizationState;
struct bilingual_str;
+namespace util {
+class SignalInterrupt;
+} // namespace util
+
namespace node {
static constexpr int DEFAULT_STOPATHEIGHT{0};
@@ -23,7 +27,7 @@ static constexpr int DEFAULT_STOPATHEIGHT{0};
class KernelNotifications : public kernel::Notifications
{
public:
- KernelNotifications(std::atomic<int>& exit_status) : m_exit_status{exit_status} {}
+ KernelNotifications(util::SignalInterrupt& shutdown, std::atomic<int>& exit_status) : m_shutdown(shutdown), m_exit_status{exit_status} {}
[[nodiscard]] kernel::InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) override;
@@ -42,6 +46,7 @@ public:
//! Useful for tests, can be set to false to avoid shutdown on fatal error.
bool m_shutdown_on_fatal_error{true};
private:
+ util::SignalInterrupt& m_shutdown;
std::atomic<int>& m_exit_status;
};
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 41f4a4d06b..2e50172914 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -71,6 +71,8 @@ public:
friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; }
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString(const FeeEstimateMode& fee_estimate_mode = FeeEstimateMode::BTC_KVB) const;
+ friend CFeeRate operator*(const CFeeRate& f, int a) { return CFeeRate(a * f.nSatoshisPerK); }
+ friend CFeeRate operator*(int a, const CFeeRate& f) { return CFeeRate(a * f.nSatoshisPerK); }
SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
};
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 74c688060d..5440548636 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -612,7 +612,7 @@ void CBlockPolicyEstimator::processTransaction(const NewMempoolTransactionInfo&
// - the node is not behind
// - the transaction is not dependent on any other transactions in the mempool
// - it's not part of a package.
- const bool validForFeeEstimation = !tx.m_from_disconnected_block && !tx.m_submitted_in_package && tx.m_chainstate_is_current && tx.m_has_no_mempool_parents;
+ const bool validForFeeEstimation = !tx.m_mempool_limit_bypassed && !tx.m_submitted_in_package && tx.m_chainstate_is_current && tx.m_has_no_mempool_parents;
// Only want to be updating estimates when our blockchain is synced,
// otherwise we'll miscalculate how many blocks its taking to get included.
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index a9a9b39bf4..33c305f0d4 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -661,7 +661,10 @@ int GuiMain(int argc, char* argv[])
app.installEventFilter(new GUIUtil::LabelOutOfFocusEventFilter(&app));
#if defined(Q_OS_WIN)
// Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
- qApp->installNativeEventFilter(new WinShutdownMonitor());
+ // Note: it is safe to call app.node() in the lambda below despite the fact
+ // that app.createNode() hasn't been called yet, because native events will
+ // not be processed until the Qt event loop is executed.
+ qApp->installNativeEventFilter(new WinShutdownMonitor([&app] { app.node().startShutdown(); }));
#endif
// Install qDebug() message handler to route to debug.log
qInstallMessageHandler(DebugMessageHandler);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 6fdc4c60d8..ba91eeb1ff 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -315,7 +315,7 @@ public Q_SLOTS:
/** Simply calls showNormalIfMinimized(true) */
void toggleHidden();
- /** called by a timer to check if ShutdownRequested() has been set **/
+ /** called by a timer to check if shutdown has been requested */
void detectShutdown();
/** Show progress dialog e.g. for verifychain */
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index eb9c65caf2..ebfd14cc25 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -669,7 +669,7 @@ fs::path QStringToPath(const QString &path)
QString PathToQString(const fs::path &path)
{
- return QString::fromStdString(path.u8string());
+ return QString::fromStdString(path.utf8string());
}
QString NetworkToQString(Network net)
@@ -723,8 +723,7 @@ QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction
QString formatDurationStr(std::chrono::seconds dur)
{
- using days = std::chrono::duration<int, std::ratio<86400>>; // can remove this line after C++20
- const auto d{std::chrono::duration_cast<days>(dur)};
+ const auto d{std::chrono::duration_cast<std::chrono::days>(dur)};
const auto h{std::chrono::duration_cast<std::chrono::hours>(dur - d)};
const auto m{std::chrono::duration_cast<std::chrono::minutes>(dur - d - h)};
const auto s{std::chrono::duration_cast<std::chrono::seconds>(dur - d - h - m)};
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index f17a6b7f74..f7d66f316e 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -85,8 +85,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
}
auto build_address = [&wallet]() {
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
CTxDestination dest(GetDestinationForKey(
key.GetPubKey(), wallet->m_default_address_type));
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
index b05009965f..9007b183aa 100644
--- a/src/qt/test/apptests.cpp
+++ b/src/qt/test/apptests.cpp
@@ -11,7 +11,6 @@
#include <qt/bitcoingui.h>
#include <qt/networkstyle.h>
#include <qt/rpcconsole.h>
-#include <shutdown.h>
#include <test/util/setup_common.h>
#include <validation.h>
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index 97a9ec318c..0b5278c192 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -5,7 +5,6 @@
#include <qt/winshutdownmonitor.h>
#if defined(Q_OS_WIN)
-#include <shutdown.h>
#include <windows.h>
@@ -25,7 +24,7 @@ bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pM
{
// Initiate a client shutdown after receiving a WM_QUERYENDSESSION and block
// Windows session end until we have finished client shutdown.
- StartShutdown();
+ m_shutdown_fn();
*pnResult = FALSE;
return true;
}
diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h
index 72655da3da..78f287637f 100644
--- a/src/qt/winshutdownmonitor.h
+++ b/src/qt/winshutdownmonitor.h
@@ -8,6 +8,7 @@
#ifdef WIN32
#include <QByteArray>
#include <QString>
+#include <functional>
#include <windef.h> // for HWND
@@ -16,11 +17,16 @@
class WinShutdownMonitor : public QAbstractNativeEventFilter
{
public:
+ WinShutdownMonitor(std::function<void()> shutdown_fn) : m_shutdown_fn{std::move(shutdown_fn)} {}
+
/** Implements QAbstractNativeEventFilter interface for processing Windows messages */
bool nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult) override;
/** Register the reason for blocking shutdown on Windows to allow clean client exit */
static void registerShutdownBlockReason(const QString& strReason, const HWND& mainWinId);
+
+private:
+ std::function<void()> m_shutdown_fn;
};
#endif
diff --git a/src/rest.cpp b/src/rest.cpp
index 8657ecc14c..fbbf6cfa84 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -264,7 +264,7 @@ static bool rest_headers(const std::any& context,
case RESTResponseFormat::JSON: {
UniValue jsonHeaders(UniValue::VARR);
for (const CBlockIndex *pindex : headers) {
- jsonHeaders.push_back(blockheaderToJSON(tip, pindex));
+ jsonHeaders.push_back(blockheaderToJSON(*tip, *pindex));
}
std::string strJSON = jsonHeaders.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -304,10 +304,9 @@ static bool rest_block(const std::any& context,
if (!pblockindex) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
-
- if (chainman.m_blockman.IsBlockPruned(pblockindex))
+ if (chainman.m_blockman.IsBlockPruned(*pblockindex)) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
-
+ }
}
if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) {
@@ -334,7 +333,7 @@ static bool rest_block(const std::any& context,
}
case RESTResponseFormat::JSON: {
- UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
+ UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 931a741f53..1618987e82 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -73,13 +73,11 @@ static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
/* Calculate the difficulty for a given block index.
*/
-double GetDifficulty(const CBlockIndex* blockindex)
+double GetDifficulty(const CBlockIndex& blockindex)
{
- CHECK_NONFATAL(blockindex);
-
- int nShift = (blockindex->nBits >> 24) & 0xff;
+ int nShift = (blockindex.nBits >> 24) & 0xff;
double dDiff =
- (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
+ (double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
while (nShift < 29)
{
@@ -95,14 +93,14 @@ double GetDifficulty(const CBlockIndex* blockindex)
return dDiff;
}
-static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
+static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
{
- next = tip->GetAncestor(blockindex->nHeight + 1);
- if (next && next->pprev == blockindex) {
- return tip->nHeight - blockindex->nHeight + 1;
+ next = tip.GetAncestor(blockindex.nHeight + 1);
+ if (next && next->pprev == &blockindex) {
+ return tip.nHeight - blockindex.nHeight + 1;
}
next = nullptr;
- return blockindex == tip ? 1 : -1;
+ return &blockindex == &tip ? 1 : -1;
}
static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
@@ -133,36 +131,36 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan
}
}
-UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
+UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex)
{
// Serialize passed information without accessing chain state of the active chain!
AssertLockNotHeld(cs_main); // For performance reasons
UniValue result(UniValue::VOBJ);
- result.pushKV("hash", blockindex->GetBlockHash().GetHex());
+ result.pushKV("hash", blockindex.GetBlockHash().GetHex());
const CBlockIndex* pnext;
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
result.pushKV("confirmations", confirmations);
- result.pushKV("height", blockindex->nHeight);
- result.pushKV("version", blockindex->nVersion);
- result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
- result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
- result.pushKV("time", (int64_t)blockindex->nTime);
- result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
- result.pushKV("nonce", (uint64_t)blockindex->nNonce);
- result.pushKV("bits", strprintf("%08x", blockindex->nBits));
+ result.pushKV("height", blockindex.nHeight);
+ result.pushKV("version", blockindex.nVersion);
+ result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
+ result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
+ result.pushKV("time", blockindex.nTime);
+ result.pushKV("mediantime", blockindex.GetMedianTimePast());
+ result.pushKV("nonce", blockindex.nNonce);
+ result.pushKV("bits", strprintf("%08x", blockindex.nBits));
result.pushKV("difficulty", GetDifficulty(blockindex));
- result.pushKV("chainwork", blockindex->nChainWork.GetHex());
- result.pushKV("nTx", (uint64_t)blockindex->nTx);
+ result.pushKV("chainwork", blockindex.nChainWork.GetHex());
+ result.pushKV("nTx", blockindex.nTx);
- if (blockindex->pprev)
- result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
+ if (blockindex.pprev)
+ result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
if (pnext)
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
return result;
}
-UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
+UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
{
UniValue result = blockheaderToJSON(tip, blockindex);
@@ -182,7 +180,7 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
CBlockUndo blockUndo;
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
- const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, *blockindex)};
+ const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)};
for (size_t i = 0; i < block.vtx.size(); ++i) {
const CTransactionRef& tx = block.vtx.at(i);
@@ -418,7 +416,7 @@ static RPCHelpMan getdifficulty()
{
ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
- return GetDifficulty(chainman.ActiveChain().Tip());
+ return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
},
};
}
@@ -571,22 +569,22 @@ static RPCHelpMan getblockheader()
return strHex;
}
- return blockheaderToJSON(tip, pblockindex);
+ return blockheaderToJSON(*tip, *pblockindex);
},
};
}
-static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
+static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
{
CBlock block;
{
LOCK(cs_main);
- if (blockman.IsBlockPruned(pblockindex)) {
+ if (blockman.IsBlockPruned(blockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
}
}
- if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
+ if (!blockman.ReadBlockFromDisk(block, blockindex)) {
// Block not found on disk. This could be because we have the block
// header in our index but not yet have the block or did not accept the
// block. Or if the block was pruned right after we released the lock above.
@@ -596,21 +594,21 @@ static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblocki
return block;
}
-static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
+static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
{
CBlockUndo blockUndo;
// The Genesis block does not have undo data
- if (pblockindex->nHeight == 0) return blockUndo;
+ if (blockindex.nHeight == 0) return blockUndo;
{
LOCK(cs_main);
- if (blockman.IsBlockPruned(pblockindex)) {
+ if (blockman.IsBlockPruned(blockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
}
}
- if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
+ if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
}
@@ -736,7 +734,7 @@ static RPCHelpMan getblock()
}
}
- const CBlock block{GetBlockChecked(chainman.m_blockman, pblockindex)};
+ const CBlock block{GetBlockChecked(chainman.m_blockman, *pblockindex)};
if (verbosity <= 0) {
DataStream ssBlock;
@@ -754,7 +752,7 @@ static RPCHelpMan getblock()
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
}
- return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
+ return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
},
};
}
@@ -1256,7 +1254,7 @@ RPCHelpMan getblockchaininfo()
obj.pushKV("blocks", height);
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
- obj.pushKV("difficulty", GetDifficulty(&tip));
+ obj.pushKV("difficulty", GetDifficulty(tip));
obj.pushKV("time", tip.GetBlockTime());
obj.pushKV("mediantime", tip.GetMedianTimePast());
obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
@@ -1814,8 +1812,8 @@ static RPCHelpMan getblockstats()
}
}
- const CBlock& block = GetBlockChecked(chainman.m_blockman, &pindex);
- const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, &pindex);
+ const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
+ const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
@@ -2274,8 +2272,8 @@ public:
static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
{
- const CBlock block{GetBlockChecked(blockman, &blockindex)};
- const CBlockUndo block_undo{GetUndoChecked(blockman, &blockindex)};
+ const CBlock block{GetBlockChecked(blockman, blockindex)};
+ const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
// Check if any of the outputs match the scriptPubKey
for (const auto& tx : block.vtx) {
@@ -2602,7 +2600,7 @@ static RPCHelpMan dumptxoutset()
if (fs::exists(path)) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
- path.u8string() + " already exists. If you are sure this is what you want, "
+ path.utf8string() + " already exists. If you are sure this is what you want, "
"move it out of the way first");
}
@@ -2611,7 +2609,7 @@ static RPCHelpMan dumptxoutset()
if (afile.IsNull()) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
- "Couldn't open file " + temppath.u8string() + " for writing.");
+ "Couldn't open file " + temppath.utf8string() + " for writing.");
}
NodeContext& node = EnsureAnyNodeContext(request.context);
@@ -2619,7 +2617,7 @@ static RPCHelpMan dumptxoutset()
node, node.chainman->ActiveChainstate(), afile, path, temppath);
fs::rename(temppath, path);
- result.pushKV("path", path.u8string());
+ result.pushKV("path", path.utf8string());
return result;
},
};
@@ -2691,7 +2689,7 @@ UniValue CreateUTXOSnapshot(
result.pushKV("coins_written", maybe_stats->coins_count);
result.pushKV("base_hash", tip->GetBlockHash().ToString());
result.pushKV("base_height", tip->nHeight);
- result.pushKV("path", path.u8string());
+ result.pushKV("path", path.utf8string());
result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
result.pushKV("nchaintx", tip->nChainTx);
return result;
@@ -2744,7 +2742,7 @@ static RPCHelpMan loadtxoutset()
if (afile.IsNull()) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
- "Couldn't open file " + path.u8string() + " for reading.");
+ "Couldn't open file " + path.utf8string() + " for reading.");
}
SnapshotMetadata metadata;
@@ -2844,7 +2842,7 @@ return RPCHelpMan{
data.pushKV("blocks", (int)chain.Height());
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
- data.pushKV("difficulty", (double)GetDifficulty(tip));
+ data.pushKV("difficulty", GetDifficulty(*tip));
data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 0a86085db0..c2021c3608 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -32,16 +32,16 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
* @return A floating point number that is a multiple of the main net minimum
* difficulty (4295032833 hashes).
*/
-double GetDifficulty(const CBlockIndex* blockindex);
+double GetDifficulty(const CBlockIndex& blockindex);
/** Callback for when block tip changed. */
void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */
-UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
+UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
/** Block header to JSON */
-UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main);
+UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex) LOCKS_EXCLUDED(cs_main);
/** Used by getblockstats to get feerates at different percentiles by weight */
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 04bd7fa928..f6d9d42f0f 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -806,7 +806,7 @@ static RPCHelpMan savemempool()
}
UniValue ret(UniValue::VOBJ);
- ret.pushKV("filename", dump_path.u8string());
+ ret.pushKV("filename", dump_path.utf8string());
return ret;
},
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 4e5d4b75a9..31551dfe98 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -27,7 +27,6 @@
#include <script/descriptor.h>
#include <script/script.h>
#include <script/signingprovider.h>
-#include <shutdown.h>
#include <timedata.h>
#include <txmempool.h>
#include <univalue.h>
@@ -129,11 +128,11 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
block_out.reset();
block.hashMerkleRoot = BlockMerkleRoot(block);
- while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !ShutdownRequested()) {
+ while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !chainman.m_interrupt) {
++block.nNonce;
--max_tries;
}
- if (max_tries == 0 || ShutdownRequested()) {
+ if (max_tries == 0 || chainman.m_interrupt) {
return false;
}
if (block.nNonce == std::numeric_limits<uint32_t>::max()) {
@@ -154,7 +153,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
{
UniValue blockHashes(UniValue::VARR);
- while (nGenerate > 0 && !ShutdownRequested()) {
+ while (nGenerate > 0 && !chainman.m_interrupt) {
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
@@ -441,7 +440,7 @@ static RPCHelpMan getmininginfo()
obj.pushKV("blocks", active_chain.Height());
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
- obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip()));
+ obj.pushKV("difficulty", GetDifficulty(*CHECK_NONFATAL(active_chain.Tip())));
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 23aca62ec2..634be2f7fb 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -394,18 +394,17 @@ static RPCHelpMan getrawtransaction()
// If request is verbosity >= 1 but no blockhash was given, then look up the blockindex
if (request.params[2].isNull()) {
LOCK(cs_main);
- blockindex = chainman.m_blockman.LookupBlockIndex(hash_block);
+ blockindex = chainman.m_blockman.LookupBlockIndex(hash_block); // May be nullptr for mempool transactions
}
- if (verbosity == 1 || !blockindex) {
+ if (verbosity == 1) {
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
}
CBlockUndo blockUndo;
CBlock block;
- const bool is_block_pruned{WITH_LOCK(cs_main, return chainman.m_blockman.IsBlockPruned(blockindex))};
- if (tx->IsCoinBase() || is_block_pruned ||
+ if (tx->IsCoinBase() || !blockindex || WITH_LOCK(::cs_main, return chainman.m_blockman.IsBlockPruned(*blockindex)) ||
!(chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex) && chainman.m_blockman.ReadBlockFromDisk(block, *blockindex))) {
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index ead940df11..e1ac510cba 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -8,9 +8,11 @@
#include <common/args.h>
#include <common/system.h>
#include <logging.h>
+#include <node/context.h>
+#include <rpc/server_util.h>
#include <rpc/util.h>
-#include <shutdown.h>
#include <sync.h>
+#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
@@ -179,7 +181,7 @@ static RPCHelpMan stop()
{
// Event loop will exit after current HTTP requests have been handled, so
// this reply will get back to the client.
- StartShutdown();
+ CHECK_NONFATAL((*CHECK_NONFATAL(EnsureAnyNodeContext(jsonRequest.context).shutdown))());
if (jsonRequest.params[0].isNum()) {
UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt<int>()});
}
@@ -243,7 +245,7 @@ static RPCHelpMan getrpcinfo()
UniValue result(UniValue::VOBJ);
result.pushKV("active_commands", active_commands);
- const std::string path = LogInstance().m_file_path.u8string();
+ const std::string path = LogInstance().m_file_path.utf8string();
UniValue log_path(UniValue::VSTR, path);
result.pushKV("logpath", log_path);
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 7e62d75583..c6bc5f8f1d 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -1777,15 +1777,15 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
const auto script_ctx{ctx == ParseScriptContext::P2WSH ? miniscript::MiniscriptContext::P2WSH : miniscript::MiniscriptContext::TAPSCRIPT};
KeyParser parser(/*out = */&out, /* in = */nullptr, /* ctx = */script_ctx, key_exp_index);
auto node = miniscript::FromString(std::string(expr.begin(), expr.end()), parser);
+ if (parser.m_key_parsing_error != "") {
+ error = std::move(parser.m_key_parsing_error);
+ return nullptr;
+ }
if (node) {
if (ctx != ParseScriptContext::P2WSH && ctx != ParseScriptContext::P2TR) {
error = "Miniscript expressions can only be used in wsh or tr.";
return nullptr;
}
- if (parser.m_key_parsing_error != "") {
- error = std::move(parser.m_key_parsing_error);
- return nullptr;
- }
if (!node->IsSane() || node->IsNotSatisfiable()) {
// Try to find the first insane sub for better error reporting.
auto insane_node = node.get();
diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml
new file mode 100644
index 0000000000..04aa8f2409
--- /dev/null
+++ b/src/secp256k1/.cirrus.yml
@@ -0,0 +1,95 @@
+env:
+ ### cirrus config
+ CIRRUS_CLONE_DEPTH: 1
+ ### compiler options
+ HOST:
+ WRAPPER_CMD:
+ # Specific warnings can be disabled with -Wno-error=foo.
+ # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
+ WERROR_CFLAGS: -Werror -pedantic-errors
+ MAKEFLAGS: -j4
+ BUILD: check
+ ### secp256k1 config
+ ECMULTWINDOW: auto
+ ECMULTGENPRECISION: auto
+ ASM: no
+ WIDEMUL: auto
+ WITH_VALGRIND: yes
+ EXTRAFLAGS:
+ ### secp256k1 modules
+ EXPERIMENTAL: no
+ ECDH: no
+ RECOVERY: no
+ SCHNORRSIG: no
+ ELLSWIFT: no
+ ### test options
+ SECP256K1_TEST_ITERS:
+ BENCH: yes
+ SECP256K1_BENCH_ITERS: 2
+ CTIMETESTS: yes
+ # Compile and run the tests
+ EXAMPLES: yes
+
+cat_logs_snippet: &CAT_LOGS
+ always:
+ cat_tests_log_script:
+ - cat tests.log || true
+ cat_noverify_tests_log_script:
+ - cat noverify_tests.log || true
+ cat_exhaustive_tests_log_script:
+ - cat exhaustive_tests.log || true
+ cat_ctime_tests_log_script:
+ - cat ctime_tests.log || true
+ cat_bench_log_script:
+ - cat bench.log || true
+ cat_config_log_script:
+ - cat config.log || true
+ cat_test_env_script:
+ - cat test_env.log || true
+ cat_ci_env_script:
+ - env
+
+linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER
+ env_script:
+ - env | tee /tmp/env
+ build_script:
+ - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm"
+ - docker image prune --force # Cleanup stale layers
+ test_script:
+ - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh"
+
+task:
+ name: "ARM64: Linux (Debian stable)"
+ persistent_worker:
+ labels:
+ type: arm64
+ env:
+ ECDH: yes
+ RECOVERY: yes
+ SCHNORRSIG: yes
+ ELLSWIFT: yes
+ matrix:
+ # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
+ - env: { CC: 'gcc-snapshot' }
+ << : *LINUX_ARM64_CONTAINER
+ << : *CAT_LOGS
+
+task:
+ name: "ARM64: Linux (Debian stable), Valgrind"
+ persistent_worker:
+ labels:
+ type: arm64
+ env:
+ ECDH: yes
+ RECOVERY: yes
+ SCHNORRSIG: yes
+ ELLSWIFT: yes
+ WRAPPER_CMD: 'valgrind --error-exitcode=42'
+ SECP256K1_TEST_ITERS: 2
+ matrix:
+ - env: { CC: 'gcc' }
+ - env: { CC: 'clang' }
+ - env: { CC: 'gcc-snapshot' }
+ - env: { CC: 'clang-snapshot' }
+ << : *LINUX_ARM64_CONTAINER
+ << : *CAT_LOGS
diff --git a/src/secp256k1/.github/actions/run-in-docker-action/action.yml b/src/secp256k1/.github/actions/run-in-docker-action/action.yml
index d357c3cf75..dbfaa4fece 100644
--- a/src/secp256k1/.github/actions/run-in-docker-action/action.yml
+++ b/src/secp256k1/.github/actions/run-in-docker-action/action.yml
@@ -14,9 +14,9 @@ inputs:
runs:
using: "composite"
steps:
- - uses: docker/setup-buildx-action@v2
+ - uses: docker/setup-buildx-action@v3
- - uses: docker/build-push-action@v4
+ - uses: docker/build-push-action@v5
id: main_builder
continue-on-error: true
with:
@@ -26,7 +26,7 @@ runs:
load: true
cache-from: type=gha
- - uses: docker/build-push-action@v4
+ - uses: docker/build-push-action@v5
id: retry_builder
if: steps.main_builder.outcome == 'failure'
with:
diff --git a/src/secp256k1/.github/workflows/ci.yml b/src/secp256k1/.github/workflows/ci.yml
index b9a9eaa82e..4ad905af52 100644
--- a/src/secp256k1/.github/workflows/ci.yml
+++ b/src/secp256k1/.github/workflows/ci.yml
@@ -47,14 +47,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
with:
# See: https://github.com/moby/buildkit/issues/3969.
driver-opts: |
network=host
- name: Build container
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
file: ./ci/linux-debian.Dockerfile
tags: linux-debian-image
@@ -792,7 +792,7 @@ jobs:
- name: Check installation with Autotools
env:
- CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}
+ CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install
run: |
./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }}
gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa
diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md
index e8d8db5a1e..04ac9b7e5a 100644
--- a/src/secp256k1/CHANGELOG.md
+++ b/src/secp256k1/CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [Unreleased]
+
+## [0.4.1] - 2023-12-21
+
+#### Changed
+ - The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one.
+ - Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`.
+
+#### ABI Compatibility
+The ABI is backward compatible with versions 0.4.0 and 0.3.x.
+
## [0.4.0] - 2023-09-04
#### Added
@@ -104,7 +115,8 @@ This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
Therefore, this version number does not uniquely identify a set of source files.
-[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...HEAD
+[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...HEAD
+[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0
[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1
diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt
index cdac47ba9d..cf0dc3ba93 100644
--- a/src/secp256k1/CMakeLists.txt
+++ b/src/secp256k1/CMakeLists.txt
@@ -11,7 +11,7 @@ project(libsecp256k1
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
- VERSION 0.4.0
+ VERSION 0.4.2
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
LANGUAGES C
@@ -35,7 +35,7 @@ endif()
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 3)
-set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
+set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
set(${PROJECT_NAME}_LIB_VERSION_AGE 1)
set(CMAKE_C_STANDARD 90)
@@ -107,7 +107,7 @@ if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
endif()
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
-set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
+set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
check_string_option_value(SECP256K1_ASM)
if(SECP256K1_ASM STREQUAL "arm32")
@@ -117,7 +117,7 @@ if(SECP256K1_ASM STREQUAL "arm32")
if(HAVE_ARM32_ASM)
add_compile_definitions(USE_EXTERNAL_ASM=1)
else()
- message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
+ message(FATAL_ERROR "ARM32 assembly requested but not available.")
endif()
elseif(SECP256K1_ASM)
include(CheckX86_64Assembly)
@@ -128,14 +128,14 @@ elseif(SECP256K1_ASM)
elseif(SECP256K1_ASM STREQUAL "AUTO")
set(SECP256K1_ASM "OFF")
else()
- message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
+ message(FATAL_ERROR "x86_64 assembly requested but not available.")
endif()
endif()
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
if(NOT SECP256K1_EXPERIMENTAL)
if(SECP256K1_ASM STREQUAL "arm32")
- message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
+ message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
endif()
endif()
@@ -280,7 +280,7 @@ message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
message("Optional features:")
-message(" assembly optimization ............... ${SECP256K1_ASM}")
+message(" assembly ............................ ${SECP256K1_ASM}")
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
diff --git a/src/secp256k1/CONTRIBUTING.md b/src/secp256k1/CONTRIBUTING.md
new file mode 100644
index 0000000000..a5e457913a
--- /dev/null
+++ b/src/secp256k1/CONTRIBUTING.md
@@ -0,0 +1,107 @@
+# Contributing to libsecp256k1
+
+## Scope
+
+libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library.
+The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem.
+
+## Adding new functionality or modules
+
+The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope.
+
+It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable.
+Contributors are recommended to provide the following in addition to the new code:
+
+* **Specification:**
+ A specification can help significantly in reviewing the new code as it provides documentation and context.
+ It may justify various design decisions, give a motivation and outline security goals.
+ If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code.
+* **Security Arguments:**
+ In addition to a defining the security goals, it should be argued that the new functionality meets these goals.
+ Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security.
+* **Relevance Arguments:**
+ The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases.
+
+These are not the only factors taken into account when considering to add new functionality.
+The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design.
+
+We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality.
+
+## Communication channels
+
+Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board.
+
+Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic).
+The channel is `#secp256k1` on Libera Chat.
+The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1).
+Chat history logs can be found at https://gnusha.org/secp256k1/.
+
+## Contributor workflow & peer review
+
+The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md).
+
+### Coding conventions
+
+In addition, libsecp256k1 tries to maintain the following coding conventions:
+
+* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Morever, it should be possible to use the library without any heap allocations.
+* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)).
+* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)).
+* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory.
+* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)).
+
+#### Style conventions
+
+* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures.
+* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting.
+* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block:
+ ```C
+ void secp256k_foo(void) {
+ unsigned int x; /* declaration */
+ int y = 2*x; /* declaration */
+ x = 17; /* statement */
+ {
+ int a, b; /* declaration */
+ a = x + y; /* statement */
+ secp256k_bar(x, &b); /* statement */
+ }
+ }
+ ```
+* Use `unsigned int` instead of just `unsigned`.
+* Use `void *ptr` instead of `void* ptr`.
+* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h).
+* User-facing comment lines in headers should be limited to 80 chars if possible.
+* All identifiers in file scope should start with `secp256k1_`.
+* Avoid trailing whitespace.
+
+### Tests
+
+#### Coverage
+
+This library aims to have full coverage of reachable lines and branches.
+
+To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
+
+ $ ./configure --enable-coverage
+
+Run the tests:
+
+ $ make check
+
+To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
+
+ $ gcovr --exclude 'src/bench*' --print-summary
+
+To create a HTML report with coloured and annotated source code:
+
+ $ mkdir -p coverage
+ $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html
+
+#### Exhaustive tests
+
+There are tests of several functions in which a small group replaces secp256k1.
+These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)).
+
+### Benchmarks
+
+See `src/bench*.c` for examples of benchmarks.
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 32bc729a41..5498617915 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -37,7 +37,6 @@ noinst_HEADERS += src/field_10x26_impl.h
noinst_HEADERS += src/field_5x52.h
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/modinv32.h
noinst_HEADERS += src/modinv32_impl.h
noinst_HEADERS += src/modinv64.h
@@ -46,6 +45,7 @@ noinst_HEADERS += src/precomputed_ecmult.h
noinst_HEADERS += src/precomputed_ecmult_gen.h
noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/checkmem.h
+noinst_HEADERS += src/testutil.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/int128.h
noinst_HEADERS += src/int128_impl.h
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 19dabe8505..4013e6a93b 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -1,11 +1,10 @@
libsecp256k1
============
-[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1)
-Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
+High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve.
This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
@@ -34,7 +33,7 @@ Implementation details
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
* Field operations
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
- * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
+ * Using 5 52-bit limbs
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
* This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
* Scalar operations
@@ -117,28 +116,6 @@ Usage examples can be found in the [examples](examples) directory. To compile th
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
-Test coverage
------------
-
-This library aims to have full coverage of the reachable lines and branches.
-
-To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
-
- $ ./configure --enable-coverage
-
-Run the tests:
-
- $ make check
-
-To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
-
- $ gcovr --exclude 'src/bench*' --print-summary
-
-To create a HTML report with coloured and annotated source code:
-
- $ mkdir -p coverage
- $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html
-
Benchmark
------------
If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.
@@ -155,3 +132,8 @@ Reporting a vulnerability
------------
See [SECURITY.md](SECURITY.md)
+
+Contributing to libsecp256k1
+------------
+
+See [CONTRIBUTING.md](CONTRIBUTING.md)
diff --git a/src/secp256k1/ci/ci.sh b/src/secp256k1/ci/ci.sh
index 719e7851ef..9cc715955e 100755
--- a/src/secp256k1/ci/ci.sh
+++ b/src/secp256k1/ci/ci.sh
@@ -83,7 +83,21 @@ esac
--host="$HOST" $EXTRAFLAGS
# We have set "-j<n>" in MAKEFLAGS.
-make
+build_exit_code=0
+make > make.log 2>&1 || build_exit_code=$?
+cat make.log
+if [ $build_exit_code -ne 0 ]; then
+ case "${CC:-undefined}" in
+ *snapshot*)
+ # Ignore internal compiler errors in gcc-snapshot and clang-snapshot
+ grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log
+ return $?;
+ ;;
+ *)
+ return 1;
+ ;;
+ esac
+fi
# Print information about binaries so that we can see that the architecture is correct
file *tests* || true
diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile
index e719907e89..5ce715b41b 100644
--- a/src/secp256k1/ci/linux-debian.Dockerfile
+++ b/src/secp256k1/ci/linux-debian.Dockerfile
@@ -29,11 +29,15 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \
gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
- gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
gcc-mingw-w64-x86-64-win32 wine64 wine \
gcc-mingw-w64-i686-win32 wine32 \
- python3
+ python3 && \
+ if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \
+ apt-get install --no-install-recommends -y \
+ gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\
+ fi && \
+ apt-get clean && rm -rf /var/lib/apt/lists/*
# Build and install gcc snapshot
ARG GCC_SNAPSHOT_MAJOR=14
@@ -44,7 +48,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev
sha512sum --check --ignore-missing sha512.sum && \
# We should have downloaded exactly one tar.xz file
ls && \
- [[ $(ls *.tar.xz | wc -l) -eq "1" ]] && \
+ [ $(ls *.tar.xz | wc -l) -eq "1" ] && \
tar xf *.tar.xz && \
mkdir gcc-build && cd gcc-build && \
../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \
diff --git a/src/secp256k1/cmake/GeneratePkgConfigFile.cmake b/src/secp256k1/cmake/GeneratePkgConfigFile.cmake
new file mode 100644
index 0000000000..9c1d7f1ddd
--- /dev/null
+++ b/src/secp256k1/cmake/GeneratePkgConfigFile.cmake
@@ -0,0 +1,8 @@
+function(generate_pkg_config_file in_file)
+ set(prefix ${CMAKE_INSTALL_PREFIX})
+ set(exec_prefix \${prefix})
+ set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR})
+ set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR})
+ set(PACKAGE_VERSION ${PROJECT_VERSION})
+ configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY)
+endfunction()
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index e3877850d3..2c1596775e 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -5,8 +5,8 @@ AC_PREREQ([2.60])
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
define(_PKG_VERSION_MINOR, 4)
-define(_PKG_VERSION_PATCH, 0)
-define(_PKG_VERSION_IS_RELEASE, true)
+define(_PKG_VERSION_PATCH, 2)
+define(_PKG_VERSION_IS_RELEASE, false)
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
@@ -14,7 +14,7 @@ define(_PKG_VERSION_IS_RELEASE, true)
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
define(_LIB_VERSION_CURRENT, 3)
-define(_LIB_VERSION_REVISION, 0)
+define(_LIB_VERSION_REVISION, 2)
define(_LIB_VERSION_AGE, 1)
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
@@ -201,7 +201,7 @@ AC_ARG_ENABLE(external_default_callbacks,
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
-[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
+[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
@@ -279,24 +279,24 @@ else
x86_64)
SECP_X86_64_ASM_CHECK
if test x"$has_x86_64_asm" != x"yes"; then
- AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
+ AC_MSG_ERROR([x86_64 assembly requested but not available])
fi
;;
arm32)
SECP_ARM32_ASM_CHECK
if test x"$has_arm32_asm" != x"yes"; then
- AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
+ AC_MSG_ERROR([ARM32 assembly requested but not available])
fi
;;
no)
;;
*)
- AC_MSG_ERROR([invalid assembly optimization selection])
+ AC_MSG_ERROR([invalid assembly selection])
;;
esac
fi
-# Select assembly optimization
+# Select assembly
enable_external_asm=no
case $set_asm in
@@ -309,7 +309,7 @@ arm32)
no)
;;
*)
- AC_MSG_ERROR([invalid assembly optimizations])
+ AC_MSG_ERROR([invalid assembly selection])
;;
esac
@@ -425,7 +425,7 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
else
if test x"$set_asm" = x"arm32"; then
- AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
+ AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.])
fi
fi
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
index ea6087c9ff..51e337a5ab 100644
--- a/src/secp256k1/doc/release-process.md
+++ b/src/secp256k1/doc/release-process.md
@@ -24,16 +24,21 @@ Perform these checks before creating a release:
2. Check installation with autotools:
```shell
dir=$(mktemp -d)
-./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -l $dir/include $dir/lib
+./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir
gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
```
3. Check installation with CMake:
```shell
dir=$(mktemp -d)
build=$(mktemp -d)
-cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -l $dir/include $dir/lib*
+cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -RlAh $dir
gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
```
+4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to ensure there are no unexpected ABI incompatibilities and that the version number and release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required.
+
+```shell
+tools/check-abi.sh
+```
## Regular release
@@ -41,7 +46,7 @@ gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rp
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
* adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
* removing the `[Unreleased]` section header, and
- * including an entry for `### ABI Compatibility` if it doesn't exist that mentions the library soname of the release,
+ * including an entry for `### ABI Compatibility` if it doesn't exist,
* sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
* if this is not a patch release
* updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
diff --git a/src/secp256k1/src/CMakeLists.txt b/src/secp256k1/src/CMakeLists.txt
index b305751b08..4cbaeb914d 100644
--- a/src/secp256k1/src/CMakeLists.txt
+++ b/src/secp256k1/src/CMakeLists.txt
@@ -161,5 +161,13 @@ if(SECP256K1_INSTALL)
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
-)
+ )
+
+ include(GeneratePkgConfigFile)
+ generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in)
+ install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
+ )
endif()
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
index 42cbf879ef..664b921400 100644
--- a/src/secp256k1/src/asm/field_10x26_arm.s
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -913,3 +913,4 @@ secp256k1_fe_sqr_inner:
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
+ .section .note.GNU-stack,"",%progbits
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index f3686dd289..a700684922 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -14,10 +14,28 @@
#include "field_impl.h"
#include "group_impl.h"
#include "scalar_impl.h"
-#include "ecmult_const_impl.h"
#include "ecmult_impl.h"
#include "bench.h"
+static void help(int default_iters) {
+ printf("Benchmarks various internal routines.\n");
+ printf("\n");
+ printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters);
+ printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n");
+ printf("\n");
+ printf("Usage: ./bench_internal [args]\n");
+ printf("By default, all benchmarks will be run.\n");
+ printf("args:\n");
+ printf(" help : display this help and exit\n");
+ printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n");
+ printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n");
+ printf(" group : all group operations (add, double, to_affine)\n");
+ printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n");
+ printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n");
+ printf(" context : all context object operations (context_create)\n");
+ printf("\n");
+}
+
typedef struct {
secp256k1_scalar scalar[2];
secp256k1_fe fe[4];
@@ -98,6 +116,18 @@ static void bench_scalar_negate(void* arg, int iters) {
}
}
+static void bench_scalar_half(void* arg, int iters) {
+ int i;
+ bench_inv *data = (bench_inv*)arg;
+ secp256k1_scalar s = data->scalar[0];
+
+ for (i = 0; i < iters; i++) {
+ secp256k1_scalar_half(&s, &s);
+ }
+
+ data->scalar[0] = s;
+}
+
static void bench_scalar_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -309,18 +339,6 @@ static void bench_ecmult_wnaf(void* arg, int iters) {
CHECK(bits <= 256*iters);
}
-static void bench_wnaf_const(void* arg, int iters) {
- int i, bits = 0, overflow = 0;
- bench_inv *data = (bench_inv*)arg;
-
- for (i = 0; i < iters; i++) {
- bits += secp256k1_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256);
- overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
- }
- CHECK(overflow >= 0);
- CHECK(bits <= 256*iters);
-}
-
static void bench_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -366,10 +384,22 @@ static void bench_context(void* arg, int iters) {
int main(int argc, char **argv) {
bench_inv data;
- int iters = get_iters(20000);
+ int default_iters = 20000;
+ int iters = get_iters(default_iters);
int d = argc == 1; /* default */
+
+ if (argc > 1) {
+ if (have_flag(argc, argv, "-h")
+ || have_flag(argc, argv, "--help")
+ || have_flag(argc, argv, "help")) {
+ help(default_iters);
+ return 0;
+ }
+ }
+
print_output_table_header_row();
+ if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
@@ -394,7 +424,6 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10);
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters);
- if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters);
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index e71254d9f9..ce36e85e6a 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -66,8 +66,7 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const
}
if (lenleft > sizeof(size_t)) {
/* The resulting length would exceed the range of a size_t, so
- * certainly longer than the passed array size.
- */
+ * it is certainly longer than the passed array size. */
return 0;
}
while (lenleft > 0) {
@@ -76,7 +75,9 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const
lenleft--;
}
if (*len > (size_t)(sigend - *sigp)) {
- /* Result exceeds the length of the passed array. */
+ /* Result exceeds the length of the passed array.
+ (Checking this is the responsibility of the caller but it
+ can't hurt do it here, too.) */
return 0;
}
if (*len < 128) {
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 06f9e53ffd..7dc4aac25d 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -1,5 +1,5 @@
/***********************************************************************
- * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
+ * Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
@@ -12,208 +12,259 @@
#include "ecmult_const.h"
#include "ecmult_impl.h"
+#if defined(EXHAUSTIVE_TEST_ORDER)
+/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because
+ * the tables cannot have infinities in them (this breaks the effective-affine technique's
+ * z-ratio tracking) */
+# if EXHAUSTIVE_TEST_ORDER == 199
+# define ECMULT_CONST_GROUP_SIZE 4
+# elif EXHAUSTIVE_TEST_ORDER == 13
+# define ECMULT_CONST_GROUP_SIZE 3
+# elif EXHAUSTIVE_TEST_ORDER == 7
+# define ECMULT_CONST_GROUP_SIZE 2
+# else
+# error "Unknown EXHAUSTIVE_TEST_ORDER"
+# endif
+#else
+/* Group size 4 or 5 appears optimal. */
+# define ECMULT_CONST_GROUP_SIZE 5
+#endif
+
+#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1))
+#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE)
+#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE)
+
/** Fill a table 'pre' with precomputed odd multiples of a.
*
* The resulting point set is brought to a single constant Z denominator, stores the X and Y
- * coordinates as ge_storage points in pre, and stores the global Z in globalz.
- * It only operates on tables sized for WINDOW_A wnaf multiples.
+ * coordinates as ge points in pre, and stores the global Z in globalz.
+ *
+ * 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE.
*/
-static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
- secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
+static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
+ secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE];
- secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a);
- secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr);
+ secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a);
+ secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr);
}
-/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
-#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
- int m = 0; \
- /* Extract the sign-bit for a constant time absolute-value. */ \
- int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
- int abs_n = ((n) + mask) ^ mask; \
- int idx_n = abs_n >> 1; \
+/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point.
+ *
+ * For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries:
+ * [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its
+ * bits are interpreted as signs of powers of two to look up.
+ *
+ * For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is
+ * [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15],
+ * which means we just need to look up one of the precomputed values, and optionally negate it.
+ */
+#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \
+ unsigned int m = 0; \
+ /* If the top bit of n is 0, we want the negation. */ \
+ volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \
+ /* Let n[i] be the i-th bit of n, then the index is
+ * sum(cnot(n[i]) * 2^i, i=0..l-2)
+ * where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise.
+ * For example, if n = 4, in binary 0100, the index is 3, in binary 011.
+ *
+ * Proof:
+ * Let
+ * x = sum((2*n[i] - 1)*2^i, i=0..l-1)
+ * = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1
+ * be the value represented by n.
+ * The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise.
+ * Case x > 0:
+ * n[l-1] = 1
+ * index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1)
+ * = sum(n[i] * 2^i, i=0..l-2)
+ * Case x <= 0:
+ * n[l-1] = 0
+ * index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2
+ * = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1)
+ * = sum((1 - n[i]) * 2^i, i=0..l-2)
+ */ \
+ unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \
secp256k1_fe neg_y; \
- VERIFY_CHECK(((n) & 1) == 1); \
- VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
- VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
- VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
- VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
- /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
+ VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \
+ VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \
+ /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
(r)->x = (pre)[m].x; \
(r)->y = (pre)[m].y; \
- for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
+ for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \
/* This loop is used to avoid secret data in array indices. See
* the comment in ecmult_gen_impl.h for rationale. */ \
- secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
- secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \
+ secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \
+ secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \
} \
(r)->infinity = 0; \
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
- secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \
+ secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \
} while(0)
-/** Convert a number to WNAF notation.
- * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
- * It has the following guarantees:
- * - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
- * - each wnaf[i] is nonzero
- * - the number of words set is always WNAF_SIZE(w) + 1
- *
- * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
- * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
- * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003
- *
- * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
- */
-static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
- int global_sign;
- int skew;
- int word = 0;
-
- /* 1 2 3 */
- int u_last;
- int u;
-
- int flip;
- secp256k1_scalar s = *scalar;
-
- VERIFY_CHECK(w > 0);
- VERIFY_CHECK(size > 0);
+/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed
+ * formulas/constants.
+ * - in exhaustive test mode, we give an explicit expression to compute it at compile time: */
+#ifdef EXHAUSTIVE_TEST_ORDER
+static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER;
+/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */
+#elif ECMULT_CONST_BITS == 129
+/* For GROUP_SIZE = 1,3. */
+static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul);
+#elif ECMULT_CONST_BITS == 130
+/* For GROUP_SIZE = 2,5. */
+static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul);
+#elif ECMULT_CONST_BITS == 132
+/* For GROUP_SIZE = 4,6 */
+static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul);
+#else
+# error "Unknown ECMULT_CONST_BITS"
+#endif
- /* 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 variation of a
- * technique from Section 4.2 of the Okeya/Tagaki paper, which is to add 1 to the
- * number we are encoding when it is even, returning a skew value indicating
- * this, and having the caller compensate after doing the multiplication.
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) {
+ /* The approach below combines the signed-digit logic from Mike Hamburg's
+ * "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309)
+ * Section 3.3, with the GLV endomorphism.
*
- * In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
- * particular, to ensure that the outputs from the endomorphism-split fit into
- * 128 bits). If we negate, the parity of our number flips, affecting whether
- * we want to add to the scalar to ensure that it's odd. */
- flip = secp256k1_scalar_is_high(&s);
- skew = flip ^ secp256k1_scalar_is_even(&s);
- secp256k1_scalar_cadd_bit(&s, 0, skew);
- global_sign = secp256k1_scalar_cond_negate(&s, flip);
-
- /* 4 */
- u_last = secp256k1_scalar_shr_int(&s, w);
- do {
- int even;
-
- /* 4.1 4.4 */
- u = secp256k1_scalar_shr_int(&s, w);
- /* 4.2 */
- even = ((u & 1) == 0);
- /* In contrast to the original algorithm, u_last is always > 0 and
- * therefore we do not need to check its sign. In particular, it's easy
- * to see that u_last is never < 0 because u is never < 0. Moreover,
- * u_last is never = 0 because u is never even after a loop
- * iteration. The same holds analogously for the initial value of
- * u_last (in the first loop iteration). */
- VERIFY_CHECK(u_last > 0);
- VERIFY_CHECK((u_last & 1) == 1);
- u += even;
- u_last -= even * (1 << w);
-
- /* 4.3, adapted for global sign change */
- wnaf[word++] = u_last * global_sign;
-
- u_last = u;
- } while (word * w < size);
- wnaf[word] = u * global_sign;
-
- VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
- VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
- return skew;
-}
-
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
- secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
- secp256k1_ge tmpa;
- secp256k1_fe Z;
-
- int skew_1;
- secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
- int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
- int skew_lam;
- secp256k1_scalar q_1, q_lam;
- int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
-
- int i;
+ * The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a
+ * point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n),
+ * and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define:
+ *
+ * C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
+ *
+ * Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
+ * = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A
+ * = (2*v + 1 - 2^l) * A
+ *
+ * Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the
+ * paper's signed-digit multi-comb algorithm for multiplication using a precomputed table.
+ *
+ * It is appealing to try to combine this with the GLV optimization: the idea that a scalar
+ * s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that
+ * lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the
+ * secp256k1_scalar_split_lambda function which performs such a split with the resulting s1
+ * and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting:
+ *
+ * To compute q*A:
+ * - Let s1, s2 = split_lambda(q)
+ * - Let R1 = C_256((s1 + 2^256 - 1) / 2, A)
+ * - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A)
+ * - Return R1 + R2
+ *
+ * The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n)
+ * and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting.
+ *
+ * To make it work, we want to modify the input scalar q first, before splitting, and then only
+ * add a 2^128 offset of the split results (so that they end up in the single 129-bit range
+ * [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick
+ * 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to
+ * compute it from q:
+ *
+ * To compute q*A:
+ * - Compute s = f(q)
+ * - Let s1, s2 = split_lambda(s)
+ * - Let v1 = s1 + 2^128 (mod n)
+ * - Let v2 = s2 + 2^128 (mod n)
+ * - Let R1 = C_l(v1, A)
+ * - Let R2 = C_l(v2, lambda*A)
+ * - Return R1 + R2
+ *
+ * l will thus need to be at least 129, but we may overshoot by a few bits (see
+ * further), so keep it as a variable.
+ *
+ * To solve for s, we reason:
+ * q*A = R1 + R2
+ * <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A)
+ * <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A
+ * <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A
+ * <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
+ * <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
+ * <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n)
+ * <=> f(q) = (q + K) / 2 (mod n)
+ * where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n)
+ *
+ * We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of
+ * ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE
+ * that is not less than 129; this equals ECMULT_CONST_BITS.
+ */
+ /* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */
+ static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0);
+ secp256k1_scalar s, v1, v2;
+ secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE];
+ secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE];
+ secp256k1_fe global_z;
+ int group, i;
+
+ /* We're allowed to be non-constant time in the point, and the code below (in particular,
+ * secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a
+ * constant-time manner anyway. */
if (secp256k1_ge_is_infinity(a)) {
secp256k1_gej_set_infinity(r);
return;
}
- /* build wnaf representation for q. */
- /* 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, scalar);
- skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
- skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
+ /* Compute v1 and v2. */
+ secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K);
+ secp256k1_scalar_half(&s, &s);
+ secp256k1_scalar_split_lambda(&v1, &v2, &s);
+ secp256k1_scalar_add(&v1, &v1, &S_OFFSET);
+ secp256k1_scalar_add(&v2, &v2, &S_OFFSET);
- /* Calculate odd multiples of a.
+#ifdef VERIFY
+ /* Verify that v1 and v2 are in range [0, 2^129-1]. */
+ for (i = 129; i < 256; ++i) {
+ VERIFY_CHECK(secp256k1_scalar_get_bits(&v1, i, 1) == 0);
+ VERIFY_CHECK(secp256k1_scalar_get_bits(&v2, i, 1) == 0);
+ }
+#endif
+
+ /* Calculate odd multiples of A and A*lambda.
* All multiples are brought to the same Z 'denominator', which is stored
- * in Z. Due to secp256k1' isomorphism we can do all operations pretending
+ * in global_z. Due to secp256k1' isomorphism we can do all operations pretending
* that the Z coordinate was 1, use affine addition formulae, and correct
* the Z coordinate of the result once at the end.
*/
- VERIFY_CHECK(!a->infinity);
secp256k1_gej_set_ge(r, a);
- secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
- for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_fe_normalize_weak(&pre_a[i].y);
- }
- for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r);
+ for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) {
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
- /* 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) */
- i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
- secp256k1_gej_set_ge(r, &tmpa);
- i = wnaf_lam[WNAF_SIZE_BITS(128, 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);
- /* remaining loop iterations */
- for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) {
- int n;
+ /* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A).
+ *
+ * We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits
+ * at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2).
+ *
+ * Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal
+ * to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2.
+ * This means that all we need to do is add these looked up values together, multiplied
+ * by 2^(ECMULT_GROUP_SIZE * group).
+ */
+ for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) {
+ /* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */
+ unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
+ unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
+ secp256k1_ge t;
int j;
- for (j = 0; j < WINDOW_A - 1; ++j) {
- secp256k1_gej_double(r, r);
- }
-
- n = wnaf_1[i];
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
- VERIFY_CHECK(n != 0);
- secp256k1_gej_add_ge(r, r, &tmpa);
- n = wnaf_lam[i];
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
- VERIFY_CHECK(n != 0);
- secp256k1_gej_add_ge(r, r, &tmpa);
- }
-
- {
- /* Correct for wNAF skew */
- secp256k1_gej tmpj;
-
- secp256k1_ge_neg(&tmpa, &pre_a[0]);
- secp256k1_gej_add_ge(&tmpj, r, &tmpa);
- secp256k1_gej_cmov(r, &tmpj, skew_1);
- secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
- secp256k1_gej_add_ge(&tmpj, r, &tmpa);
- secp256k1_gej_cmov(r, &tmpj, skew_lam);
+ ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1);
+ if (group == ECMULT_CONST_GROUPS - 1) {
+ /* Directly set r in the first iteration. */
+ secp256k1_gej_set_ge(r, &t);
+ } else {
+ /* Shift the result so far up. */
+ for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) {
+ secp256k1_gej_double(r, r);
+ }
+ secp256k1_gej_add_ge(r, r, &t);
+ }
+ ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2);
+ secp256k1_gej_add_ge(r, r, &t);
}
- secp256k1_fe_mul(&r->z, &r->z, &Z);
+ /* Map the result back to the secp256k1 curve from the isomorphic curve. */
+ secp256k1_fe_mul(&r->z, &r->z, &global_z);
}
static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
@@ -296,9 +347,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
secp256k1_fe_mul(&g, &g, n);
if (d) {
secp256k1_fe b;
-#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d));
-#endif
secp256k1_fe_sqr(&b, d);
VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */
secp256k1_fe_mul_int(&b, SECP256K1_B);
@@ -331,13 +380,9 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
p.infinity = 0;
/* Perform x-only EC multiplication of P with q. */
-#ifdef VERIFY
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
-#endif
secp256k1_ecmult_const(&rj, &p, q);
-#ifdef VERIFY
VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
-#endif
/* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
* (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index ccd228e1ae..bd589bf8a8 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -184,7 +184,8 @@ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
*/
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Set a field element equal to a provided 32-byte big endian value, reducing it.
+/** Set a field element equal to the element represented by a provided 32-byte big endian value
+ * interpreted modulo p.
*
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
* On output, r = a (mod p). It will have magnitude 1, and not be normalized.
@@ -345,8 +346,10 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
/** Check invariants on a field element (no-op unless VERIFY is enabled). */
static void secp256k1_fe_verify(const secp256k1_fe *a);
+#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a)
/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m);
+#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m)
#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 8445db1639..666068c712 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -403,11 +403,7 @@ 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
-#define VERIFY_BITS(x, n) do { } while(0)
-#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
uint64_t c, d;
diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h
deleted file mode 100644
index 04a9af2105..0000000000
--- a/src/secp256k1/src/field_5x52_asm_impl.h
+++ /dev/null
@@ -1,504 +0,0 @@
-/***********************************************************************
- * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
- ***********************************************************************/
-
-/**
- * Changelog:
- * - March 2013, Diederik Huys: original version
- * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm
- * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
- */
-
-#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
-#define SECP256K1_FIELD_INNER5X52_IMPL_H
-
-#include "util.h"
-
-SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
-/**
- * Registers: rdx:rax = multiplication accumulator
- * r9:r8 = c
- * r15:rcx = d
- * r10-r14 = a0-a4
- * rbx = b
- * rdi = r
- * rsi = a / t?
- */
- uint64_t tmp1, tmp2, tmp3;
-__asm__ __volatile__(
- "movq 0(%%rsi),%%r10\n"
- "movq 8(%%rsi),%%r11\n"
- "movq 16(%%rsi),%%r12\n"
- "movq 24(%%rsi),%%r13\n"
- "movq 32(%%rsi),%%r14\n"
-
- /* d += a3 * b0 */
- "movq 0(%%rbx),%%rax\n"
- "mulq %%r13\n"
- "movq %%rax,%%rcx\n"
- "movq %%rdx,%%r15\n"
- /* d += a2 * b1 */
- "movq 8(%%rbx),%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a1 * b2 */
- "movq 16(%%rbx),%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d = a0 * b3 */
- "movq 24(%%rbx),%%rax\n"
- "mulq %%r10\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* c = a4 * b4 */
- "movq 32(%%rbx),%%rax\n"
- "mulq %%r14\n"
- "movq %%rax,%%r8\n"
- "movq %%rdx,%%r9\n"
- /* d += (c & M) * R */
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* c >>= 52 (%%r8 only) */
- "shrdq $52,%%r9,%%r8\n"
- /* t3 (tmp1) = d & M */
- "movq %%rcx,%%rsi\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rsi\n"
- "movq %%rsi,%q1\n"
- /* d >>= 52 */
- "shrdq $52,%%r15,%%rcx\n"
- "xorq %%r15,%%r15\n"
- /* d += a4 * b0 */
- "movq 0(%%rbx),%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a3 * b1 */
- "movq 8(%%rbx),%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a2 * b2 */
- "movq 16(%%rbx),%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a1 * b3 */
- "movq 24(%%rbx),%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a0 * b4 */
- "movq 32(%%rbx),%%rax\n"
- "mulq %%r10\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += c * R */
- "movq %%r8,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* t4 = d & M (%%rsi) */
- "movq %%rcx,%%rsi\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rsi\n"
- /* d >>= 52 */
- "shrdq $52,%%r15,%%rcx\n"
- "xorq %%r15,%%r15\n"
- /* tx = t4 >> 48 (tmp3) */
- "movq %%rsi,%%rax\n"
- "shrq $48,%%rax\n"
- "movq %%rax,%q3\n"
- /* t4 &= (M >> 4) (tmp2) */
- "movq $0xffffffffffff,%%rax\n"
- "andq %%rax,%%rsi\n"
- "movq %%rsi,%q2\n"
- /* c = a0 * b0 */
- "movq 0(%%rbx),%%rax\n"
- "mulq %%r10\n"
- "movq %%rax,%%r8\n"
- "movq %%rdx,%%r9\n"
- /* d += a4 * b1 */
- "movq 8(%%rbx),%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a3 * b2 */
- "movq 16(%%rbx),%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a2 * b3 */
- "movq 24(%%rbx),%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a1 * b4 */
- "movq 32(%%rbx),%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* u0 = d & M (%%rsi) */
- "movq %%rcx,%%rsi\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rsi\n"
- /* d >>= 52 */
- "shrdq $52,%%r15,%%rcx\n"
- "xorq %%r15,%%r15\n"
- /* u0 = (u0 << 4) | tx (%%rsi) */
- "shlq $4,%%rsi\n"
- "movq %q3,%%rax\n"
- "orq %%rax,%%rsi\n"
- /* c += u0 * (R >> 4) */
- "movq $0x1000003d1,%%rax\n"
- "mulq %%rsi\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* r[0] = c & M */
- "movq %%r8,%%rax\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq %%rax,0(%%rdi)\n"
- /* c >>= 52 */
- "shrdq $52,%%r9,%%r8\n"
- "xorq %%r9,%%r9\n"
- /* c += a1 * b0 */
- "movq 0(%%rbx),%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* c += a0 * b1 */
- "movq 8(%%rbx),%%rax\n"
- "mulq %%r10\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d += a4 * b2 */
- "movq 16(%%rbx),%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a3 * b3 */
- "movq 24(%%rbx),%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a2 * b4 */
- "movq 32(%%rbx),%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* c += (d & M) * R */
- "movq %%rcx,%%rax\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d >>= 52 */
- "shrdq $52,%%r15,%%rcx\n"
- "xorq %%r15,%%r15\n"
- /* r[1] = c & M */
- "movq %%r8,%%rax\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq %%rax,8(%%rdi)\n"
- /* c >>= 52 */
- "shrdq $52,%%r9,%%r8\n"
- "xorq %%r9,%%r9\n"
- /* c += a2 * b0 */
- "movq 0(%%rbx),%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* c += a1 * b1 */
- "movq 8(%%rbx),%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* c += a0 * b2 (last use of %%r10 = a0) */
- "movq 16(%%rbx),%%rax\n"
- "mulq %%r10\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */
- "movq %q2,%%rsi\n"
- "movq %q1,%%r10\n"
- /* d += a4 * b3 */
- "movq 24(%%rbx),%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* d += a3 * b4 */
- "movq 32(%%rbx),%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rcx\n"
- "adcq %%rdx,%%r15\n"
- /* c += (d & M) * R */
- "movq %%rcx,%%rax\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d >>= 52 (%%rcx only) */
- "shrdq $52,%%r15,%%rcx\n"
- /* r[2] = c & M */
- "movq %%r8,%%rax\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq %%rax,16(%%rdi)\n"
- /* c >>= 52 */
- "shrdq $52,%%r9,%%r8\n"
- "xorq %%r9,%%r9\n"
- /* c += t3 */
- "addq %%r10,%%r8\n"
- /* c += d * R */
- "movq %%rcx,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* r[3] = c & M */
- "movq %%r8,%%rax\n"
- "movq $0xfffffffffffff,%%rdx\n"
- "andq %%rdx,%%rax\n"
- "movq %%rax,24(%%rdi)\n"
- /* c >>= 52 (%%r8 only) */
- "shrdq $52,%%r9,%%r8\n"
- /* c += t4 (%%r8 only) */
- "addq %%rsi,%%r8\n"
- /* r[4] = c */
- "movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
-: "b"(b), "D"(r)
-: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
-);
-}
-
-SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
-/**
- * Registers: rdx:rax = multiplication accumulator
- * r9:r8 = c
- * rcx:rbx = d
- * r10-r14 = a0-a4
- * r15 = M (0xfffffffffffff)
- * rdi = r
- * rsi = a / t?
- */
- uint64_t tmp1, tmp2, tmp3;
-__asm__ __volatile__(
- "movq 0(%%rsi),%%r10\n"
- "movq 8(%%rsi),%%r11\n"
- "movq 16(%%rsi),%%r12\n"
- "movq 24(%%rsi),%%r13\n"
- "movq 32(%%rsi),%%r14\n"
- "movq $0xfffffffffffff,%%r15\n"
-
- /* d = (a0*2) * a3 */
- "leaq (%%r10,%%r10,1),%%rax\n"
- "mulq %%r13\n"
- "movq %%rax,%%rbx\n"
- "movq %%rdx,%%rcx\n"
- /* d += (a1*2) * a2 */
- "leaq (%%r11,%%r11,1),%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* c = a4 * a4 */
- "movq %%r14,%%rax\n"
- "mulq %%r14\n"
- "movq %%rax,%%r8\n"
- "movq %%rdx,%%r9\n"
- /* d += (c & M) * R */
- "andq %%r15,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* c >>= 52 (%%r8 only) */
- "shrdq $52,%%r9,%%r8\n"
- /* t3 (tmp1) = d & M */
- "movq %%rbx,%%rsi\n"
- "andq %%r15,%%rsi\n"
- "movq %%rsi,%q1\n"
- /* d >>= 52 */
- "shrdq $52,%%rcx,%%rbx\n"
- "xorq %%rcx,%%rcx\n"
- /* a4 *= 2 */
- "addq %%r14,%%r14\n"
- /* d += a0 * a4 */
- "movq %%r10,%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* d+= (a1*2) * a3 */
- "leaq (%%r11,%%r11,1),%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* d += a2 * a2 */
- "movq %%r12,%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* d += c * R */
- "movq %%r8,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* t4 = d & M (%%rsi) */
- "movq %%rbx,%%rsi\n"
- "andq %%r15,%%rsi\n"
- /* d >>= 52 */
- "shrdq $52,%%rcx,%%rbx\n"
- "xorq %%rcx,%%rcx\n"
- /* tx = t4 >> 48 (tmp3) */
- "movq %%rsi,%%rax\n"
- "shrq $48,%%rax\n"
- "movq %%rax,%q3\n"
- /* t4 &= (M >> 4) (tmp2) */
- "movq $0xffffffffffff,%%rax\n"
- "andq %%rax,%%rsi\n"
- "movq %%rsi,%q2\n"
- /* c = a0 * a0 */
- "movq %%r10,%%rax\n"
- "mulq %%r10\n"
- "movq %%rax,%%r8\n"
- "movq %%rdx,%%r9\n"
- /* d += a1 * a4 */
- "movq %%r11,%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* d += (a2*2) * a3 */
- "leaq (%%r12,%%r12,1),%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* u0 = d & M (%%rsi) */
- "movq %%rbx,%%rsi\n"
- "andq %%r15,%%rsi\n"
- /* d >>= 52 */
- "shrdq $52,%%rcx,%%rbx\n"
- "xorq %%rcx,%%rcx\n"
- /* u0 = (u0 << 4) | tx (%%rsi) */
- "shlq $4,%%rsi\n"
- "movq %q3,%%rax\n"
- "orq %%rax,%%rsi\n"
- /* c += u0 * (R >> 4) */
- "movq $0x1000003d1,%%rax\n"
- "mulq %%rsi\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* r[0] = c & M */
- "movq %%r8,%%rax\n"
- "andq %%r15,%%rax\n"
- "movq %%rax,0(%%rdi)\n"
- /* c >>= 52 */
- "shrdq $52,%%r9,%%r8\n"
- "xorq %%r9,%%r9\n"
- /* a0 *= 2 */
- "addq %%r10,%%r10\n"
- /* c += a0 * a1 */
- "movq %%r10,%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d += a2 * a4 */
- "movq %%r12,%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* d += a3 * a3 */
- "movq %%r13,%%rax\n"
- "mulq %%r13\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* c += (d & M) * R */
- "movq %%rbx,%%rax\n"
- "andq %%r15,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d >>= 52 */
- "shrdq $52,%%rcx,%%rbx\n"
- "xorq %%rcx,%%rcx\n"
- /* r[1] = c & M */
- "movq %%r8,%%rax\n"
- "andq %%r15,%%rax\n"
- "movq %%rax,8(%%rdi)\n"
- /* c >>= 52 */
- "shrdq $52,%%r9,%%r8\n"
- "xorq %%r9,%%r9\n"
- /* c += a0 * a2 (last use of %%r10) */
- "movq %%r10,%%rax\n"
- "mulq %%r12\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */
- "movq %q2,%%rsi\n"
- "movq %q1,%%r10\n"
- /* c += a1 * a1 */
- "movq %%r11,%%rax\n"
- "mulq %%r11\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d += a3 * a4 */
- "movq %%r13,%%rax\n"
- "mulq %%r14\n"
- "addq %%rax,%%rbx\n"
- "adcq %%rdx,%%rcx\n"
- /* c += (d & M) * R */
- "movq %%rbx,%%rax\n"
- "andq %%r15,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* d >>= 52 (%%rbx only) */
- "shrdq $52,%%rcx,%%rbx\n"
- /* r[2] = c & M */
- "movq %%r8,%%rax\n"
- "andq %%r15,%%rax\n"
- "movq %%rax,16(%%rdi)\n"
- /* c >>= 52 */
- "shrdq $52,%%r9,%%r8\n"
- "xorq %%r9,%%r9\n"
- /* c += t3 */
- "addq %%r10,%%r8\n"
- /* c += d * R */
- "movq %%rbx,%%rax\n"
- "movq $0x1000003d10,%%rdx\n"
- "mulq %%rdx\n"
- "addq %%rax,%%r8\n"
- "adcq %%rdx,%%r9\n"
- /* r[3] = c & M */
- "movq %%r8,%%rax\n"
- "andq %%r15,%%rax\n"
- "movq %%rax,24(%%rdi)\n"
- /* c >>= 52 (%%r8 only) */
- "shrdq $52,%%r9,%%r8\n"
- /* c += t4 (%%r8 only) */
- "addq %%rsi,%%r8\n"
- /* r[4] = c */
- "movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
-: "D"(r)
-: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
-);
-}
-
-#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index ecb70502c2..76031f755e 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -12,11 +12,7 @@
#include "field.h"
#include "modinv64_impl.h"
-#if defined(USE_ASM_X86_64)
-#include "field_5x52_asm_impl.h"
-#else
#include "field_5x52_int128_impl.h"
-#endif
#ifdef VERIFY
static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index b2a391dec9..f23f8ee1c4 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -12,13 +12,8 @@
#include "int128.h"
#include "util.h"
-#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
-#else
-#define VERIFY_BITS(x, n) do { } while(0)
-#define VERIFY_BITS_128(x, n) do { } while(0)
-#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
secp256k1_uint128 c, d;
@@ -89,18 +84,18 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
secp256k1_u128_accum_mul(&d, a2, b[3]);
secp256k1_u128_accum_mul(&d, a3, b[2]);
secp256k1_u128_accum_mul(&d, a4, b[1]);
- VERIFY_BITS_128(&d, 115);
+ VERIFY_BITS_128(&d, 114);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
- VERIFY_BITS_128(&d, 63);
+ VERIFY_BITS_128(&d, 62);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
secp256k1_u128_accum_mul(&c, u0, R >> 4);
- VERIFY_BITS_128(&c, 115);
+ VERIFY_BITS_128(&c, 113);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
@@ -159,7 +154,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
secp256k1_uint128 c, d;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
- int64_t t3, t4, tx, u0;
+ uint64_t t3, t4, tx, u0;
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
VERIFY_BITS(a[0], 56);
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 80d34b9ef2..989e9cdb2f 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -20,12 +20,11 @@
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
-#ifdef VERIFY
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
- secp256k1_fe_verify_magnitude(a, 1);
- secp256k1_fe_verify_magnitude(b, 31);
-#endif
+ SECP256K1_FE_VERIFY(a);
+ SECP256K1_FE_VERIFY(b);
+ SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
+ SECP256K1_FE_VERIFY_MAGNITUDE(b, 31);
+
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero(&na);
@@ -44,11 +43,9 @@ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j, ret;
-#ifdef VERIFY
VERIFY_CHECK(r != a);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify_magnitude(a, 8);
-#endif
+ SECP256K1_FE_VERIFY(a);
+ SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
@@ -151,11 +148,11 @@ static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)
static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
static void secp256k1_fe_verify(const secp256k1_fe *a) {
/* Magnitude between 0 and 32. */
- secp256k1_fe_verify_magnitude(a, 32);
+ SECP256K1_FE_VERIFY_MAGNITUDE(a, 32);
/* Normalized is 0 or 1. */
VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
/* If normalized, magnitude must be 0 or 1. */
- if (a->normalized) secp256k1_fe_verify_magnitude(a, 1);
+ if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
/* Invoke implementation-specific checks. */
secp256k1_fe_impl_verify(a);
}
@@ -168,59 +165,71 @@ static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) {
static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
secp256k1_fe_impl_normalize(r);
r->magnitude = 1;
r->normalized = 1;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
secp256k1_fe_impl_normalize_weak(r);
r->magnitude = 1;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
secp256k1_fe_impl_normalize_var(r);
r->magnitude = 1;
r->normalized = 1;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
return secp256k1_fe_impl_normalizes_to_zero(r);
}
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
return secp256k1_fe_impl_normalizes_to_zero_var(r);
}
static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+
secp256k1_fe_impl_set_int(r, a);
r->magnitude = (a != 0);
r->normalized = 1;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
secp256k1_fe_impl_add_int(r, a);
r->magnitude += 1;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_clear(secp256k1_fe *a);
@@ -228,29 +237,33 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
a->magnitude = 0;
a->normalized = 1;
secp256k1_fe_impl_clear(a);
- secp256k1_fe_verify(a);
+
+ SECP256K1_FE_VERIFY(a);
}
static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
- secp256k1_fe_verify(a);
+ SECP256K1_FE_VERIFY(a);
VERIFY_CHECK(a->normalized);
+
return secp256k1_fe_impl_is_zero(a);
}
static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
- secp256k1_fe_verify(a);
+ SECP256K1_FE_VERIFY(a);
VERIFY_CHECK(a->normalized);
+
return secp256k1_fe_impl_is_odd(a);
}
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
+ SECP256K1_FE_VERIFY(a);
+ SECP256K1_FE_VERIFY(b);
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
+
return secp256k1_fe_impl_cmp_var(a, b);
}
@@ -259,7 +272,8 @@ SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const uns
secp256k1_fe_impl_set_b32_mod(r, a);
r->magnitude = 1;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
@@ -267,7 +281,7 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un
if (secp256k1_fe_impl_set_b32_limit(r, a)) {
r->magnitude = 1;
r->normalized = 1;
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
return 1;
} else {
/* Mark the output field element as invalid. */
@@ -278,83 +292,97 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
- secp256k1_fe_verify(a);
+ SECP256K1_FE_VERIFY(a);
VERIFY_CHECK(a->normalized);
+
secp256k1_fe_impl_get_b32(r, a);
}
static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
- secp256k1_fe_verify(a);
+ SECP256K1_FE_VERIFY(a);
VERIFY_CHECK(m >= 0 && m <= 31);
- secp256k1_fe_verify_magnitude(a, m);
+ SECP256K1_FE_VERIFY_MAGNITUDE(a, m);
+
secp256k1_fe_impl_negate_unchecked(r, a, m);
r->magnitude = m + 1;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a);
SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) {
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
+
VERIFY_CHECK(a >= 0 && a <= 32);
VERIFY_CHECK(a*r->magnitude <= 32);
secp256k1_fe_impl_mul_int_unchecked(r, a);
r->magnitude *= a;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
- secp256k1_fe_verify(r);
- secp256k1_fe_verify(a);
+ SECP256K1_FE_VERIFY(r);
+ SECP256K1_FE_VERIFY(a);
VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
+
secp256k1_fe_impl_add(r, a);
r->magnitude += a->magnitude;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
- secp256k1_fe_verify_magnitude(a, 8);
- secp256k1_fe_verify_magnitude(b, 8);
+ SECP256K1_FE_VERIFY(a);
+ SECP256K1_FE_VERIFY(b);
+ SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
+ SECP256K1_FE_VERIFY_MAGNITUDE(b, 8);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
+
secp256k1_fe_impl_mul(r, a, b);
r->magnitude = 1;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
- secp256k1_fe_verify(a);
- secp256k1_fe_verify_magnitude(a, 8);
+ SECP256K1_FE_VERIFY(a);
+ SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
+
secp256k1_fe_impl_sqr(r, a);
r->magnitude = 1;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
VERIFY_CHECK(flag == 0 || flag == 1);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(a);
+ SECP256K1_FE_VERIFY(r);
+
secp256k1_fe_impl_cmov(r, a, flag);
if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
if (!a->normalized) r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
- secp256k1_fe_verify(a);
+ SECP256K1_FE_VERIFY(a);
VERIFY_CHECK(a->normalized);
+
secp256k1_fe_impl_to_storage(r, a);
}
@@ -363,36 +391,42 @@ SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const se
secp256k1_fe_impl_from_storage(r, a);
r->magnitude = 1;
r->normalized = 1;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
- secp256k1_fe_verify(x);
+ SECP256K1_FE_VERIFY(x);
+
secp256k1_fe_impl_inv(r, x);
r->magnitude = x->magnitude > 0;
r->normalized = 1;
+
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
- secp256k1_fe_verify(x);
+ SECP256K1_FE_VERIFY(x);
+
secp256k1_fe_impl_inv_var(r, x);
r->magnitude = x->magnitude > 0;
r->normalized = 1;
+
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
- secp256k1_fe_verify(r);
+ SECP256K1_FE_VERIFY(r);
}
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
int ret;
secp256k1_fe tmp = *x, sqrt;
- secp256k1_fe_verify(x);
+ SECP256K1_FE_VERIFY(x);
+
ret = secp256k1_fe_impl_is_square_var(x);
secp256k1_fe_normalize_weak(&tmp);
VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
@@ -403,20 +437,24 @@ static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
VERIFY_CHECK(m >= 0);
VERIFY_CHECK(m <= 32);
+
secp256k1_fe_impl_get_bounds(r, m);
r->magnitude = m;
r->normalized = (m == 0);
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
static void secp256k1_fe_impl_half(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
- secp256k1_fe_verify(r);
- secp256k1_fe_verify_magnitude(r, 31);
+ SECP256K1_FE_VERIFY(r);
+ SECP256K1_FE_VERIFY_MAGNITUDE(r, 31);
+
secp256k1_fe_impl_half(r);
r->magnitude = (r->magnitude >> 1) + 1;
r->normalized = 0;
- secp256k1_fe_verify(r);
+
+ SECP256K1_FE_VERIFY(r);
}
#endif /* defined(VERIFY) */
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index 86eb9e1f82..d81deb4264 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -102,6 +102,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
*/
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
+/** Check two group elements (affine) for equality in variable time. */
+static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b);
+
/** Set a group element (affine) equal to the point at infinity. */
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
@@ -114,6 +117,9 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
/** Check two group elements (jacobian) for equality in variable time. */
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
+/** Check two group elements (jacobian and affine) for equality in variable time. */
+static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b);
+
/** Compare the X coordinate of a group element (jacobian).
* The magnitude of the group element's X coordinate must not exceed 31. */
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
@@ -181,8 +187,10 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
static void secp256k1_ge_verify(const secp256k1_ge *a);
+#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a)
/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
static void secp256k1_gej_verify(const secp256k1_gej *a);
+#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a)
#endif /* SECP256K1_GROUP_H */
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index b9542ce8ae..537be32ff6 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -74,26 +74,22 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
/* End of section generated by sage/gen_exhaustive_groups.sage. */
static void secp256k1_ge_verify(const secp256k1_ge *a) {
-#ifdef VERIFY
- secp256k1_fe_verify(&a->x);
- secp256k1_fe_verify(&a->y);
- secp256k1_fe_verify_magnitude(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX);
- secp256k1_fe_verify_magnitude(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX);
+ SECP256K1_FE_VERIFY(&a->x);
+ SECP256K1_FE_VERIFY(&a->y);
+ SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX);
+ SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
-#endif
(void)a;
}
static void secp256k1_gej_verify(const secp256k1_gej *a) {
-#ifdef VERIFY
- secp256k1_fe_verify(&a->x);
- secp256k1_fe_verify(&a->y);
- secp256k1_fe_verify(&a->z);
- secp256k1_fe_verify_magnitude(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX);
- secp256k1_fe_verify_magnitude(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX);
- secp256k1_fe_verify_magnitude(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX);
+ SECP256K1_FE_VERIFY(&a->x);
+ SECP256K1_FE_VERIFY(&a->y);
+ SECP256K1_FE_VERIFY(&a->z);
+ SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX);
+ SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX);
+ SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
-#endif
(void)a;
}
@@ -101,8 +97,8 @@ static void secp256k1_gej_verify(const secp256k1_gej *a) {
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
- secp256k1_gej_verify(a);
- secp256k1_fe_verify(zi);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_FE_VERIFY(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
@@ -111,15 +107,15 @@ static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, c
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
- secp256k1_ge_verify(a);
- secp256k1_fe_verify(zi);
+ SECP256K1_GE_VERIFY(a);
+ SECP256K1_FE_VERIFY(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
@@ -128,39 +124,39 @@ static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, con
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
- secp256k1_fe_verify(x);
- secp256k1_fe_verify(y);
+ SECP256K1_FE_VERIFY(x);
+ SECP256K1_FE_VERIFY(y);
r->infinity = 0;
r->x = *x;
r->y = *y;
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
- secp256k1_ge_verify(a);
+ SECP256K1_GE_VERIFY(a);
return a->infinity;
}
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
- secp256k1_ge_verify(a);
+ SECP256K1_GE_VERIFY(a);
*r = *a;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(a);
r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z);
@@ -172,13 +168,13 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
r->x = a->x;
r->y = a->y;
- secp256k1_gej_verify(a);
- secp256k1_ge_verify(r);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GE_VERIFY(r);
}
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(a);
if (secp256k1_gej_is_infinity(a)) {
secp256k1_ge_set_infinity(r);
@@ -193,8 +189,8 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_set_int(&a->z, 1);
secp256k1_ge_set_xy(r, &a->x, &a->y);
- secp256k1_gej_verify(a);
- secp256k1_ge_verify(r);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GE_VERIFY(r);
}
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
@@ -203,7 +199,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
size_t last_i = SIZE_MAX;
#ifdef VERIFY
for (i = 0; i < len; i++) {
- secp256k1_gej_verify(&a[i]);
+ SECP256K1_GEJ_VERIFY(&a[i]);
}
#endif
@@ -245,7 +241,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
#ifdef VERIFY
for (i = 0; i < len; i++) {
- secp256k1_ge_verify(&r[i]);
+ SECP256K1_GE_VERIFY(&r[i]);
}
#endif
}
@@ -255,8 +251,8 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
secp256k1_fe zs;
#ifdef VERIFY
for (i = 0; i < len; i++) {
- secp256k1_ge_verify(&a[i]);
- secp256k1_fe_verify(&zr[i]);
+ SECP256K1_GE_VERIFY(&a[i]);
+ SECP256K1_FE_VERIFY(&zr[i]);
}
#endif
@@ -278,7 +274,7 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
#ifdef VERIFY
for (i = 0; i < len; i++) {
- secp256k1_ge_verify(&a[i]);
+ SECP256K1_GE_VERIFY(&a[i]);
}
#endif
}
@@ -289,7 +285,7 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
@@ -297,7 +293,7 @@ static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static void secp256k1_gej_clear(secp256k1_gej *r) {
@@ -306,7 +302,7 @@ static void secp256k1_gej_clear(secp256k1_gej *r) {
secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_ge_clear(secp256k1_ge *r) {
@@ -314,13 +310,13 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
secp256k1_fe x2, x3;
int ret;
- secp256k1_fe_verify(x);
+ SECP256K1_FE_VERIFY(x);
r->x = *x;
secp256k1_fe_sqr(&x2, x);
@@ -333,45 +329,72 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
secp256k1_fe_negate(&r->y, &r->y, 1);
}
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
return ret;
}
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
- secp256k1_ge_verify(a);
+ SECP256K1_GE_VERIFY(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_set_int(&r->z, 1);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej tmp;
- secp256k1_gej_verify(b);
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(b);
+ SECP256K1_GEJ_VERIFY(a);
secp256k1_gej_neg(&tmp, a);
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
return secp256k1_gej_is_infinity(&tmp);
}
+static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) {
+ secp256k1_gej tmp;
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GE_VERIFY(b);
+
+ secp256k1_gej_neg(&tmp, a);
+ secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL);
+ return secp256k1_gej_is_infinity(&tmp);
+}
+
+static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) {
+ secp256k1_fe tmp;
+ SECP256K1_GE_VERIFY(a);
+ SECP256K1_GE_VERIFY(b);
+
+ if (a->infinity != b->infinity) return 0;
+ if (a->infinity) return 1;
+
+ tmp = a->x;
+ secp256k1_fe_normalize_weak(&tmp);
+ if (!secp256k1_fe_equal(&tmp, &b->x)) return 0;
+
+ tmp = a->y;
+ secp256k1_fe_normalize_weak(&tmp);
+ if (!secp256k1_fe_equal(&tmp, &b->y)) return 0;
+
+ return 1;
+}
+
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r;
- secp256k1_fe_verify(x);
- secp256k1_gej_verify(a);
-#ifdef VERIFY
+ SECP256K1_FE_VERIFY(x);
+ SECP256K1_GEJ_VERIFY(a);
VERIFY_CHECK(!a->infinity);
-#endif
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
return secp256k1_fe_equal(&r, &a->x);
}
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(a);
r->infinity = a->infinity;
r->x = a->x;
@@ -380,18 +403,18 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(a);
return a->infinity;
}
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
secp256k1_fe y2, x3;
- secp256k1_ge_verify(a);
+ SECP256K1_GE_VERIFY(a);
if (a->infinity) {
return 0;
@@ -406,7 +429,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
secp256k1_fe l, s, t;
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(a);
r->infinity = a->infinity;
@@ -435,11 +458,11 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(a);
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
@@ -466,14 +489,14 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
secp256k1_gej_double(r, a);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
- secp256k1_gej_verify(a);
- secp256k1_gej_verify(b);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GEJ_VERIFY(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
@@ -530,14 +553,14 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
/* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
- secp256k1_gej_verify(a);
- secp256k1_ge_verify(b);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GE_VERIFY(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
@@ -592,16 +615,16 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
- secp256k1_gej_verify(r);
- if (rzr != NULL) secp256k1_fe_verify(rzr);
+ SECP256K1_GEJ_VERIFY(r);
+ if (rzr != NULL) SECP256K1_FE_VERIFY(rzr);
}
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
/* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
- secp256k1_gej_verify(a);
- secp256k1_ge_verify(b);
- secp256k1_fe_verify(bzinv);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GE_VERIFY(b);
+ SECP256K1_FE_VERIFY(bzinv);
if (a->infinity) {
secp256k1_fe bzinv2, bzinv3;
@@ -611,7 +634,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
secp256k1_fe_mul(&r->x, &b->x, &bzinv2);
secp256k1_fe_mul(&r->y, &b->y, &bzinv3);
secp256k1_fe_set_int(&r->z, 1);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
return;
}
if (b->infinity) {
@@ -663,7 +686,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
@@ -672,8 +695,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
int degenerate;
- secp256k1_gej_verify(a);
- secp256k1_ge_verify(b);
+ SECP256K1_GEJ_VERIFY(a);
+ SECP256K1_GE_VERIFY(b);
VERIFY_CHECK(!b->infinity);
/* In:
@@ -801,17 +824,15 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
/* Operations: 4 mul, 1 sqr */
secp256k1_fe zz;
- secp256k1_gej_verify(r);
- secp256k1_fe_verify(s);
-#ifdef VERIFY
+ SECP256K1_GEJ_VERIFY(r);
+ SECP256K1_FE_VERIFY(s);
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
-#endif
secp256k1_fe_sqr(&zz, s);
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
@@ -819,12 +840,12 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
secp256k1_fe x, y;
- secp256k1_ge_verify(a);
+ SECP256K1_GE_VERIFY(a);
VERIFY_CHECK(!a->infinity);
x = a->x;
@@ -840,19 +861,19 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
secp256k1_fe_from_storage(&r->y, &a->y);
r->infinity = 0;
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
- secp256k1_gej_verify(r);
- secp256k1_gej_verify(a);
+ SECP256K1_GEJ_VERIFY(r);
+ SECP256K1_GEJ_VERIFY(a);
secp256k1_fe_cmov(&r->x, &a->x, flag);
secp256k1_fe_cmov(&r->y, &a->y, flag);
secp256k1_fe_cmov(&r->z, &a->z, flag);
r->infinity ^= (r->infinity ^ a->infinity) & flag;
- secp256k1_gej_verify(r);
+ SECP256K1_GEJ_VERIFY(r);
}
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
@@ -861,19 +882,19 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
}
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
- secp256k1_ge_verify(a);
+ SECP256K1_GE_VERIFY(a);
*r = *a;
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
- secp256k1_ge_verify(r);
+ SECP256K1_GE_VERIFY(r);
}
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
#ifdef EXHAUSTIVE_TEST_ORDER
secp256k1_gej out;
int i;
- secp256k1_ge_verify(ge);
+ SECP256K1_GE_VERIFY(ge);
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
secp256k1_gej_set_infinity(&out);
@@ -885,7 +906,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
}
return secp256k1_gej_is_infinity(&out);
#else
- secp256k1_ge_verify(ge);
+ SECP256K1_GE_VERIFY(ge);
(void)ge;
/* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */
@@ -907,9 +928,8 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
*/
secp256k1_fe r, t;
-#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
-#endif
+
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
diff --git a/src/secp256k1/src/modinv32_impl.h b/src/secp256k1/src/modinv32_impl.h
index 0ea2699863..75eb354ff0 100644
--- a/src/secp256k1/src/modinv32_impl.h
+++ b/src/secp256k1/src/modinv32_impl.h
@@ -144,7 +144,6 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
r->v[7] = r7;
r->v[8] = r8;
-#ifdef VERIFY
VERIFY_CHECK(r0 >> 30 == 0);
VERIFY_CHECK(r1 >> 30 == 0);
VERIFY_CHECK(r2 >> 30 == 0);
@@ -156,7 +155,6 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
VERIFY_CHECK(r8 >> 30 == 0);
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */
-#endif
}
/* Data type for transition matrices (see section 3 of explanation).
@@ -413,14 +411,13 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
int32_t di, ei, md, me, sd, se;
int64_t cd, ce;
int i;
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
-#endif
+
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d->v[8] >> 31;
se = e->v[8] >> 31;
@@ -455,12 +452,11 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
/* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */
d->v[8] = (int32_t)cd;
e->v[8] = (int32_t)ce;
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
-#endif
}
/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
@@ -550,25 +546,23 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m
/* Update d,e using that transition matrix. */
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
+
secp256k1_modinv32_update_fg_30(&f, &g, &t);
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
}
/* At this point sufficient iterations have been performed that g must have reached 0
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
-#ifdef VERIFY
+
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
@@ -578,7 +572,6 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0)));
-#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo);
@@ -607,12 +600,12 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
/* Update d,e using that transition matrix. */
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
+
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
/* If the bottom limb of g is 0, there is a chance g=0. */
if (g.v[0] == 0) {
@@ -637,18 +630,17 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
g.v[len - 2] |= (uint32_t)gn << 30;
--len;
}
-#ifdef VERIFY
+
VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
}
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
-#ifdef VERIFY
+
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
@@ -658,7 +650,6 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0)));
-#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo);
@@ -697,12 +688,11 @@ static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, co
secp256k1_modinv32_trans2x2 t;
eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
/* Update f,g using that transition matrix. */
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
+
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
/* If the bottom limb of f is 1, there is a chance that f=1. */
if (f.v[0] == 1) {
@@ -723,12 +713,11 @@ static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, co
cond |= gn;
/* If so, reduce length. */
if (cond == 0) --len;
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
}
/* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */
diff --git a/src/secp256k1/src/modinv64_impl.h b/src/secp256k1/src/modinv64_impl.h
index c7cef872a4..0dc1e80696 100644
--- a/src/secp256k1/src/modinv64_impl.h
+++ b/src/secp256k1/src/modinv64_impl.h
@@ -144,7 +144,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
r->v[3] = r3;
r->v[4] = r4;
-#ifdef VERIFY
VERIFY_CHECK(r0 >> 62 == 0);
VERIFY_CHECK(r1 >> 62 == 0);
VERIFY_CHECK(r2 >> 62 == 0);
@@ -152,7 +151,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
VERIFY_CHECK(r4 >> 62 == 0);
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */
-#endif
}
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
@@ -216,7 +214,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
-#ifdef VERIFY
+
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
@@ -224,7 +222,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
* 8*identity (which has determinant 2^6) means the overall outputs has determinant
* 2^65. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0));
-#endif
+
return zeta;
}
@@ -301,13 +299,13 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
-#ifdef VERIFY
+
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 62 of them will have determinant 2^62. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0));
-#endif
+
return eta;
}
@@ -392,13 +390,13 @@ static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, u
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
-#ifdef VERIFY
+
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
* the aggregate of 62 of them will have determinant 2^62 or -2^62. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1));
-#endif
+
*jacp = jac;
return eta;
}
@@ -417,14 +415,13 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t md, me, sd, se;
secp256k1_int128 cd, ce;
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */
VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */
-#endif
+
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d4 >> 63;
se = e4 >> 63;
@@ -489,12 +486,11 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
d->v[4] = secp256k1_i128_to_i64(&cd);
e->v[4] = secp256k1_i128_to_i64(&ce);
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
-#endif
}
/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62.
@@ -606,25 +602,23 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m
/* Update d,e using that transition matrix. */
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
+
secp256k1_modinv64_update_fg_62(&f, &g, &t);
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
}
/* At this point sufficient iterations have been performed that g must have reached 0
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
-#ifdef VERIFY
+
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
@@ -634,7 +628,6 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0)));
-#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo);
@@ -663,12 +656,11 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
/* Update d,e using that transition matrix. */
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
+
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
/* If the bottom limb of g is zero, there is a chance that g=0. */
if (g.v[0] == 0) {
@@ -693,18 +685,17 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
g.v[len - 2] |= (uint64_t)gn << 62;
--len;
}
-#ifdef VERIFY
+
VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
}
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
-#ifdef VERIFY
+
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
@@ -714,7 +705,6 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0)));
-#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo);
@@ -753,12 +743,11 @@ static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, co
secp256k1_modinv64_trans2x2 t;
eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
/* Update f,g using that transition matrix. */
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
+
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
/* If the bottom limb of f is 1, there is a chance that f=1. */
if (f.v[0] == 1) {
@@ -779,12 +768,11 @@ static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, co
cond |= gn;
/* If so, reduce length. */
if (cond == 0) --len;
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
-#endif
}
/* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index fa6f232227..6be96eacbe 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -25,32 +25,19 @@ static int ecdh_hash_function_custom(unsigned char *output, const unsigned char
}
static void test_ecdh_api(void) {
- /* Setup context that just counts errors */
- secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_pubkey point;
unsigned char res[32];
unsigned char s_one[32] = { 0 };
- int32_t ecount = 0;
s_one[31] = 1;
- secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
- CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
+ CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
/* Check all NULLs are detected */
- CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
- CHECK(ecount == 3);
-
- /* Cleanup */
- secp256k1_context_destroy(tctx);
+ CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL));
+ CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
}
static void test_ecdh_generator_basepoint(void) {
diff --git a/src/secp256k1/src/modules/ellswift/main_impl.h b/src/secp256k1/src/modules/ellswift/main_impl.h
index 00bb8a3da5..b54ec08a22 100644
--- a/src/secp256k1/src/modules/ellswift/main_impl.h
+++ b/src/secp256k1/src/modules/ellswift/main_impl.h
@@ -126,9 +126,8 @@ static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe
secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */
secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */
secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */
-#ifdef VERIFY
+
VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p));
-#endif
/* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */
}
@@ -193,10 +192,8 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_
secp256k1_fe_normalize_weak(&x);
secp256k1_fe_normalize_weak(&u);
-#ifdef VERIFY
VERIFY_CHECK(c >= 0 && c < 8);
VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x));
-#endif
if (!(c & 2)) {
/* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or
@@ -230,9 +227,7 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_
* that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m)
* test above would have failed). This is a contradiction, and thus the
* assumption s=0 is false. */
-#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s));
-#endif
/* If s is not square, fail. We have not fully computed s yet, but s is square iff
* -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is
@@ -272,7 +267,11 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_
secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */
if (!secp256k1_fe_is_square_var(&q)) return 0;
ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */
+#ifdef VERIFY
VERIFY_CHECK(ret);
+#else
+ (void)ret;
+#endif
/* If (c & 1) = 1 and r = 0, fail. */
if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0;
@@ -320,10 +319,9 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256
buf4[3] = cnt >> 24;
secp256k1_sha256_write(&hash, buf4, 4);
secp256k1_sha256_finalize(&hash, out32);
-#ifdef VERIFY
+
/* Writing and finalizing together should trigger exactly one SHA256 compression. */
VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
-#endif
}
/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate.
@@ -361,9 +359,8 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1
/* Since u is the output of a hash, it should practically never be 0. We could apply the
* u=0 to u=1 correction here too to deal with that case still, but it's such a low
* probability event that we do not bother. */
-#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u));
-#endif
+
/* Find a remainder t, and return it if found. */
if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break;
}
@@ -417,7 +414,11 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64
* BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
secp256k1_ellswift_sha256_init_encode(&hash);
ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1);
+#ifdef VERIFY
VERIFY_CHECK(ser_ret && ser_size == 33);
+#else
+ (void)ser_ret;
+#endif
secp256k1_sha256_write(&hash, p64, sizeof(p64));
secp256k1_sha256_write(&hash, rnd32, 32);
diff --git a/src/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h b/src/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h
index e002a8c008..839c24aee4 100644
--- a/src/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h
+++ b/src/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h
@@ -32,7 +32,7 @@ static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256
/* Decode ellswift pubkey and check that it matches the precomputed group element. */
secp256k1_ellswift_decode(ctx, &pub_decoded, ell64);
secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded);
- ge_equals_ge(&ge_decoded, &group[i]);
+ CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i]));
}
}
diff --git a/src/secp256k1/src/modules/ellswift/tests_impl.h b/src/secp256k1/src/modules/ellswift/tests_impl.h
index 47f443d980..7d1efbc492 100644
--- a/src/secp256k1/src/modules/ellswift/tests_impl.h
+++ b/src/secp256k1/src/modules/ellswift/tests_impl.h
@@ -237,7 +237,7 @@ void run_ellswift_tests(void) {
secp256k1_ellswift_decode(CTX, &pubkey2, ell64);
secp256k1_pubkey_load(CTX, &g2, &pubkey2);
/* Compare with original. */
- ge_equals_ge(&g, &g2);
+ CHECK(secp256k1_ge_eq_var(&g, &g2));
}
/* Verify the behavior of secp256k1_ellswift_create */
for (i = 0; i < 400 * COUNT; i++) {
@@ -259,7 +259,7 @@ void run_ellswift_tests(void) {
secp256k1_ellswift_decode(CTX, &pub, ell64);
secp256k1_pubkey_load(CTX, &dec, &pub);
secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
- ge_equals_gej(&dec, &res);
+ CHECK(secp256k1_gej_eq_ge_var(&res, &dec));
}
/* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */
for (i = 0; i < 800 * COUNT; i++) {
@@ -285,7 +285,7 @@ void run_ellswift_tests(void) {
ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL);
CHECK(ret);
(void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */
- secp256k1_fe_verify(&share_x);
+ SECP256K1_FE_VERIFY(&share_x);
/* Compute seckey*pubkey directly. */
secp256k1_ecmult(&resj, &decj, &sec, NULL);
secp256k1_ge_set_gej(&res, &resj);
diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h
index ae1655923b..45521d1742 100644
--- a/src/secp256k1/src/modules/extrakeys/tests_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h
@@ -9,11 +9,6 @@
#include "../../../include/secp256k1_extrakeys.h"
-static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) {
- secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
- secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
-}
-
static void test_xonly_pubkey(void) {
secp256k1_pubkey pk;
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
@@ -28,10 +23,6 @@ static void test_xonly_pubkey(void) {
int pk_parity;
int i;
- int ecount;
-
- set_counting_callbacks(CTX, &ecount);
-
secp256k1_testrand256(sk);
memset(ones32, 0xFF, 32);
secp256k1_testrand256(xy_sk);
@@ -39,16 +30,12 @@ static void test_xonly_pubkey(void) {
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
/* Test xonly_pubkey_from_pubkey */
- ecount = 0;
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk));
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
- CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL));
memset(&pk, 0, sizeof(pk));
- CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk));
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
memset(sk, 0, sizeof(sk));
@@ -72,28 +59,21 @@ static void test_xonly_pubkey(void) {
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
- ecount = 0;
- CHECK(secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk));
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL));
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
- CHECK(ecount == 2);
{
/* A pubkey filled with 0s will fail to serialize due to pubkey_load
* special casing. */
secp256k1_xonly_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp));
- CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp) == 0);
+ /* pubkey_load calls illegal callback */
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp));
}
- /* pubkey_load called illegal callback */
- CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
- ecount = 0;
- CHECK(secp256k1_xonly_pubkey_parse(CTX, NULL, buf32) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32));
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL));
/* Serialization and parse roundtrip */
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
@@ -125,7 +105,6 @@ static void test_xonly_pubkey(void) {
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1);
}
}
- CHECK(ecount == 2);
}
static void test_xonly_pubkey_comparison(void) {
@@ -139,29 +118,26 @@ static void test_xonly_pubkey_comparison(void) {
};
secp256k1_xonly_pubkey pk1;
secp256k1_xonly_pubkey pk2;
- int ecount = 0;
-
- set_counting_callbacks(CTX, &ecount);
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1);
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1);
- CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0));
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0));
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0);
- CHECK(ecount == 2);
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
- CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
- CHECK(ecount == 5);
- CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
- CHECK(ecount == 6);
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0));
+ {
+ int32_t ecount = 0;
+ secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount);
+ CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
+ CHECK(ecount == 2);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
+ }
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0));
}
static void test_xonly_pubkey_tweak(void) {
@@ -175,30 +151,20 @@ static void test_xonly_pubkey_tweak(void) {
unsigned char tweak[32];
int i;
- int ecount;
-
- set_counting_callbacks(CTX, &ecount);
-
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
- ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
- CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
- CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak));
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak));
/* NULL internal_xonly_pk zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
- CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL));
/* NULL tweak zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
@@ -225,9 +191,7 @@ static void test_xonly_pubkey_tweak(void) {
/* Invalid pk with a valid tweak */
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
secp256k1_testrand256(tweak);
- ecount = 0;
- CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak));
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
}
@@ -244,34 +208,23 @@ static void test_xonly_pubkey_tweak_check(void) {
int pk_parity;
unsigned char tweak[32];
- int ecount;
-
- set_counting_callbacks(CTX, &ecount);
-
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
- ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
- CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
- CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak));
/* invalid pk_parity value */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak));
+ CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL));
memset(tweak, 1, sizeof(tweak));
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1);
@@ -290,7 +243,6 @@ static void test_xonly_pubkey_tweak_check(void) {
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
- CHECK(ecount == 3);
}
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
@@ -335,33 +287,22 @@ static void test_keypair(void) {
secp256k1_pubkey pk, pk_tmp;
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
int pk_parity, pk_parity_tmp;
- int ecount;
-
- set_counting_callbacks(CTX, &ecount);
- set_counting_callbacks(STATIC_CTX, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
memset(overflows, 0xFF, sizeof(overflows));
/* Test keypair_create */
- ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
- CHECK(ecount == 0);
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
- CHECK(ecount == 0);
- CHECK(secp256k1_keypair_create(CTX, NULL, sk) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_keypair_create(CTX, &keypair, NULL) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk));
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL));
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
- CHECK(ecount == 2);
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_keypair_create(STATIC_CTX, &keypair, sk) == 0);
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk));
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
- CHECK(ecount == 3);
/* Invalid secret key */
CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0);
@@ -370,14 +311,11 @@ static void test_keypair(void) {
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
/* Test keypair_pub */
- ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
- CHECK(secp256k1_keypair_pub(CTX, NULL, &keypair) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_keypair_pub(CTX, &pk, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair));
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL));
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* Using an invalid keypair is fine for keypair_pub */
@@ -392,23 +330,19 @@ static void test_keypair(void) {
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
/** Test keypair_xonly_pub **/
- ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
- CHECK(secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair));
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1);
- CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL));
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
* xonly_pk). */
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
memset(&keypair, 0, sizeof(keypair));
- CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair));
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
- CHECK(ecount == 3);
/** keypair holds the same xonly pubkey as pubkey_create **/
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
@@ -419,14 +353,11 @@ static void test_keypair(void) {
CHECK(pk_parity == pk_parity_tmp);
/* Test keypair_seckey */
- ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
- CHECK(secp256k1_keypair_sec(CTX, NULL, &keypair) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_keypair_sec(CTX, sk_tmp, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair));
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL));
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
/* keypair returns the same seckey it got */
@@ -439,9 +370,6 @@ static void test_keypair(void) {
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
-
- secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
- secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
}
static void test_keypair_add(void) {
@@ -451,9 +379,6 @@ static void test_keypair_add(void) {
unsigned char zeros96[96] = { 0 };
unsigned char tweak[32];
int i;
- int ecount = 0;
-
- set_counting_callbacks(CTX, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
secp256k1_testrand256(sk);
@@ -462,14 +387,10 @@ static void test_keypair_add(void) {
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
- CHECK(ecount == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
- CHECK(ecount == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak));
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL));
/* This does not set the keypair to zeroes */
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
@@ -503,20 +424,16 @@ static void test_keypair_add(void) {
/* Invalid keypair with a valid tweak */
memset(&keypair, 0, sizeof(keypair));
secp256k1_testrand256(tweak);
- ecount = 0;
- CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* Only seckey part of keypair invalid */
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memset(&keypair, 0, 32);
- CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
/* Only pubkey part of keypair invalid */
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memset(&keypair.data[32], 0, 64);
- CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
/* Check that the keypair_tweak_add implementation is correct */
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h
index 3502c71ffe..728ccfed8d 100644
--- a/src/secp256k1/src/modules/recovery/tests_impl.h
+++ b/src/secp256k1/src/modules/recovery/tests_impl.h
@@ -36,7 +36,6 @@ static void test_ecdsa_recovery_api(void) {
secp256k1_ecdsa_recoverable_signature recsig;
unsigned char privkey[32] = { 1 };
unsigned char message[32] = { 2 };
- int32_t ecount = 0;
int recid = 0;
unsigned char sig[74];
unsigned char zero_privkey[32] = { 0 };
@@ -45,86 +44,52 @@ static void test_ecdsa_recovery_api(void) {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
-
/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
/* Check bad contexts and NULLs for signing */
- ecount = 0;
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL) == 0);
- CHECK(ecount == 4);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL));
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL));
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL);
- CHECK(ecount == 4);
/* These will all fail, but not in ARG_CHECK way */
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0);
/* This one will succeed. */
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
- CHECK(ecount == 4);
/* Check signing with a goofy nonce function */
/* Check bad contexts and NULLs for recovery */
- ecount = 0;
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_recover(CTX, NULL, &recsig, message) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL));
/* Check NULLs for conversion */
CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1);
- ecount = 0;
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL));
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1);
/* Check NULLs for de/serialization */
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
- ecount = 0;
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL));
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid) == 0);
- CHECK(ecount == 4);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid) == 0);
- CHECK(ecount == 5);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1) == 0);
- CHECK(ecount == 6);
- CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5) == 0);
- CHECK(ecount == 7);
- /* overflow in signature will fail but not affect ecount */
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5));
+ /* overflow in signature will not result in calling illegal_callback */
memcpy(sig, over_privkey, 32);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0);
- CHECK(ecount == 7);
-
- /* cleanup */
- secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
- secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
}
static void test_ecdsa_recovery_end_to_end(void) {
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
index 90337ff03e..8ada90a87b 100644
--- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
@@ -116,14 +116,6 @@ static void test_schnorrsig_api(void) {
secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
- /** setup **/
- int ecount = 0;
-
- secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
-
secp256k1_testrand256(sk1);
secp256k1_testrand256(sk2);
secp256k1_testrand256(sk3);
@@ -137,57 +129,30 @@ static void test_schnorrsig_api(void) {
memset(&zero_pk, 0, sizeof(zero_pk));
/** main test body **/
- ecount = 0;
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL) == 0);
- CHECK(ecount == 4);
- CHECK(secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL) == 0);
- CHECK(ecount == 5);
-
- ecount = 0;
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL));
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL));
+
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams));
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
- CHECK(ecount == 4);
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams));
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
- CHECK(ecount == 4);
- CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
- CHECK(ecount == 5);
- CHECK(secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
- CHECK(ecount == 6);
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams));
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams));
- ecount = 0;
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]));
CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk) == 0);
- CHECK(ecount == 4);
-
- secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
- secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk));
}
/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index 4b3c2998bb..98b1287bb5 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -25,7 +25,7 @@ static void secp256k1_scalar_clear(secp256k1_scalar *r);
/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */
static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
-/** Access bits from a scalar. Not constant time. */
+/** Access bits from a scalar. Not constant time in offset and count. */
static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`.
@@ -54,10 +54,6 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
/** Multiply two scalars (modulo the group order). */
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);
-/** Shift a scalar right by some amount strictly between 0 and 16, returning
- * the low bits that were shifted off */
-static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);
-
/** Compute the inverse of a scalar (modulo the group order). */
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);
@@ -67,6 +63,9 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
/** Compute the complement of a scalar (modulo the group order). */
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a);
+/** Multiply a scalar with the multiplicative inverse of 2. */
+static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a);
+
/** Check whether a scalar equals zero. */
static int secp256k1_scalar_is_zero(const secp256k1_scalar *a);
@@ -101,5 +100,6 @@ static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a
/** Check invariants on a scalar (no-op unless VERIFY is enabled). */
static void secp256k1_scalar_verify(const secp256k1_scalar *r);
+#define SECP256K1_SCALAR_VERIFY(r) secp256k1_scalar_verify(r)
#endif /* SECP256K1_SCALAR_H */
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 715cc12ee5..7b9c542f07 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -42,18 +42,18 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
r->d[2] = 0;
r->d[3] = 0;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
@@ -93,15 +93,15 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigne
secp256k1_u128_accum_u64(&t, r->d[3]);
r->d[3] = secp256k1_u128_to_u64(&t);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return overflow;
}
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
secp256k1_uint128 t;
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
secp256k1_u128_from_u64(&t, a->d[0]);
secp256k1_u128_accum_u64(&t, b->d[0]);
@@ -119,14 +119,14 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return overflow;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
secp256k1_uint128 t;
volatile int vflag = flag;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(bit < 256);
bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
@@ -143,10 +143,8 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
r->d[3] = secp256k1_u128_to_u64(&t);
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0);
-#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
@@ -160,11 +158,11 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
*overflow = over;
}
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
secp256k1_write_be64(&bin[0], a->d[3]);
secp256k1_write_be64(&bin[8], a->d[2]);
@@ -173,7 +171,7 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar*
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0;
}
@@ -181,7 +179,7 @@ SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a)
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0);
secp256k1_uint128 t;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
secp256k1_u128_from_u64(&t, ~a->d[0]);
secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1);
@@ -196,11 +194,52 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar
secp256k1_u128_accum_u64(&t, SECP256K1_N_3);
r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
+}
+
+static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ /* Writing `/` for field division and `//` for integer division, we compute
+ *
+ * a/2 = (a - (a&1))/2 + (a&1)/2
+ * = (a >> 1) + (a&1 ? 1/2 : 0)
+ * = (a >> 1) + (a&1 ? n//2+1 : 0),
+ *
+ * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n).
+ * For n//2, we have the constants SECP256K1_N_H_0, ...
+ *
+ * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here:
+ * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2
+ * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2
+ * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n.
+ */
+ uint64_t mask = -(uint64_t)(a->d[0] & 1U);
+ secp256k1_uint128 t;
+ SECP256K1_SCALAR_VERIFY(a);
+
+ secp256k1_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63));
+ secp256k1_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask);
+ r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63));
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_H_1 & mask);
+ r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ secp256k1_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63));
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_H_2 & mask);
+ r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
+ r->d[3] = secp256k1_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask);
+#ifdef VERIFY
+ /* The line above only computed the bottom 64 bits of r->d[3]; redo the computation
+ * in full 128 bits to make sure the top 64 bits are indeed zero. */
+ secp256k1_u128_accum_u64(&t, a->d[3] >> 1);
+ secp256k1_u128_accum_u64(&t, SECP256K1_N_H_3 & mask);
+ secp256k1_u128_rshift(&t, 64);
+ VERIFY_CHECK(secp256k1_u128_to_u64(&t) == 0);
+
+ SECP256K1_SCALAR_VERIFY(r);
+#endif
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0;
}
@@ -208,7 +247,7 @@ SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
no |= (a->d[3] < SECP256K1_N_H_3);
yes |= (a->d[3] > SECP256K1_N_H_3) & ~no;
@@ -226,7 +265,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
uint64_t mask = -vflag;
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
secp256k1_uint128 t;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask);
@@ -241,7 +280,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask);
r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return 2 * (mask == 0) - 1;
}
@@ -800,33 +839,17 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
uint64_t l[8];
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
- secp256k1_scalar_verify(r);
-}
-
-static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
- int ret;
- secp256k1_scalar_verify(r);
- VERIFY_CHECK(n > 0);
- VERIFY_CHECK(n < 16);
-
- ret = r->d[0] & ((1 << n) - 1);
- r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n));
- r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n));
- r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n));
- r->d[3] = (r->d[3] >> n);
-
- secp256k1_scalar_verify(r);
- return ret;
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
- secp256k1_scalar_verify(k);
+ SECP256K1_SCALAR_VERIFY(k);
r1->d[0] = k->d[0];
r1->d[1] = k->d[1];
@@ -837,13 +860,13 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r
r2->d[2] = 0;
r2->d[3] = 0;
- secp256k1_scalar_verify(r1);
- secp256k1_scalar_verify(r2);
+ SECP256K1_SCALAR_VERIFY(r1);
+ SECP256K1_SCALAR_VERIFY(r2);
}
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0;
}
@@ -853,8 +876,8 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
unsigned int shiftlimbs;
unsigned int shiftlow;
unsigned int shifthigh;
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
VERIFY_CHECK(shift >= 256);
secp256k1_scalar_mul_512(l, a, b);
@@ -867,13 +890,13 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0;
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint64_t mask0, mask1;
volatile int vflag = flag;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
mask0 = vflag + ~((uint64_t)0);
@@ -883,7 +906,7 @@ static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const se
r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1);
r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_modinv64_signed62 *a) {
@@ -903,13 +926,13 @@ static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_
r->d[2] = a2 >> 4 | a3 << 58;
r->d[3] = a3 >> 6 | a4 << 56;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_scalar *a) {
const uint64_t M62 = UINT64_MAX >> 2;
const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3];
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
r->v[0] = a0 & M62;
r->v[1] = (a0 >> 62 | a1 << 2) & M62;
@@ -928,16 +951,14 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
#ifdef VERIFY
int zero_in = secp256k1_scalar_is_zero(x);
#endif
- secp256k1_scalar_verify(x);
+ SECP256K1_SCALAR_VERIFY(x);
secp256k1_scalar_to_signed62(&s, x);
secp256k1_modinv64(&s, &secp256k1_const_modinfo_scalar);
secp256k1_scalar_from_signed62(r, &s);
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
-#endif
}
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
@@ -945,20 +966,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
#ifdef VERIFY
int zero_in = secp256k1_scalar_is_zero(x);
#endif
- secp256k1_scalar_verify(x);
+ SECP256K1_SCALAR_VERIFY(x);
secp256k1_scalar_to_signed62(&s, x);
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_scalar);
secp256k1_scalar_from_signed62(r, &s);
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
-#endif
}
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return !(a->d[0] & 1);
}
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index 5ca1342273..58ae51bc02 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -59,18 +59,18 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
r->d[6] = 0;
r->d[7] = 0;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
@@ -121,15 +121,15 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_
t += (uint64_t)r->d[7];
r->d[7] = t & 0xFFFFFFFFUL;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return overflow;
}
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
uint64_t t = (uint64_t)a->d[0] + b->d[0];
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[1] + b->d[1];
@@ -150,14 +150,14 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return overflow;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint64_t t;
volatile int vflag = flag;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(bit < 256);
bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
@@ -178,10 +178,8 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F));
r->d[7] = t & 0xFFFFFFFFULL;
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK((t >> 32) == 0);
-#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
@@ -199,11 +197,11 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
*overflow = over;
}
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
secp256k1_write_be32(&bin[0], a->d[7]);
secp256k1_write_be32(&bin[4], a->d[6]);
@@ -216,7 +214,7 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar*
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
}
@@ -224,7 +222,7 @@ SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a)
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0);
uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
r->d[0] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[1]) + SECP256K1_N_1;
@@ -242,11 +240,59 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar
t += (uint64_t)(~a->d[7]) + SECP256K1_N_7;
r->d[7] = t & nonzero;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
+}
+
+static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ /* Writing `/` for field division and `//` for integer division, we compute
+ *
+ * a/2 = (a - (a&1))/2 + (a&1)/2
+ * = (a >> 1) + (a&1 ? 1/2 : 0)
+ * = (a >> 1) + (a&1 ? n//2+1 : 0),
+ *
+ * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n).
+ * For n//2, we have the constants SECP256K1_N_H_0, ...
+ *
+ * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here:
+ * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2
+ * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2
+ * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n.
+ */
+ uint32_t mask = -(uint32_t)(a->d[0] & 1U);
+ uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31));
+ SECP256K1_SCALAR_VERIFY(a);
+
+ t += (SECP256K1_N_H_0 + 1U) & mask;
+ r->d[0] = t; t >>= 32;
+ t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31));
+ t += SECP256K1_N_H_1 & mask;
+ r->d[1] = t; t >>= 32;
+ t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31));
+ t += SECP256K1_N_H_2 & mask;
+ r->d[2] = t; t >>= 32;
+ t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31));
+ t += SECP256K1_N_H_3 & mask;
+ r->d[3] = t; t >>= 32;
+ t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31));
+ t += SECP256K1_N_H_4 & mask;
+ r->d[4] = t; t >>= 32;
+ t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31));
+ t += SECP256K1_N_H_5 & mask;
+ r->d[5] = t; t >>= 32;
+ t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31));
+ t += SECP256K1_N_H_6 & mask;
+ r->d[6] = t; t >>= 32;
+ r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask);
+
+ /* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation
+ * in full 64 bits to make sure the top 32 bits are indeed zero. */
+ VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0);
+
+ SECP256K1_SCALAR_VERIFY(r);
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
}
@@ -254,7 +300,7 @@ SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
no |= (a->d[7] < SECP256K1_N_H_7);
yes |= (a->d[7] > SECP256K1_N_H_7) & ~no;
@@ -278,7 +324,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
uint32_t mask = -vflag;
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
r->d[0] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
@@ -296,7 +342,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask);
r->d[7] = t & nonzero;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return 2 * (mask == 0) - 1;
}
@@ -604,37 +650,17 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
uint32_t l[16];
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
- secp256k1_scalar_verify(r);
-}
-
-static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
- int ret;
- secp256k1_scalar_verify(r);
- VERIFY_CHECK(n > 0);
- VERIFY_CHECK(n < 16);
-
- ret = r->d[0] & ((1 << n) - 1);
- r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n));
- r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n));
- r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n));
- r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n));
- r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n));
- r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n));
- r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n));
- r->d[7] = (r->d[7] >> n);
-
- secp256k1_scalar_verify(r);
- return ret;
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
- secp256k1_scalar_verify(k);
+ SECP256K1_SCALAR_VERIFY(k);
r1->d[0] = k->d[0];
r1->d[1] = k->d[1];
@@ -653,13 +679,13 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r
r2->d[6] = 0;
r2->d[7] = 0;
- secp256k1_scalar_verify(r1);
- secp256k1_scalar_verify(r2);
+ SECP256K1_SCALAR_VERIFY(r1);
+ SECP256K1_SCALAR_VERIFY(r2);
}
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
}
@@ -669,8 +695,8 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
unsigned int shiftlimbs;
unsigned int shiftlow;
unsigned int shifthigh;
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
VERIFY_CHECK(shift >= 256);
secp256k1_scalar_mul_512(l, a, b);
@@ -687,13 +713,13 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0;
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
volatile int vflag = flag;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
mask0 = vflag + ~((uint32_t)0);
@@ -707,7 +733,7 @@ static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const se
r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1);
r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_modinv32_signed30 *a) {
@@ -736,14 +762,14 @@ static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_
r->d[6] = a6 >> 12 | a7 << 18;
r->d[7] = a7 >> 14 | a8 << 16;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_scalar *a) {
const uint32_t M30 = UINT32_MAX >> 2;
const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3],
a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7];
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
r->v[0] = a0 & M30;
r->v[1] = (a0 >> 30 | a1 << 2) & M30;
@@ -766,16 +792,14 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
#ifdef VERIFY
int zero_in = secp256k1_scalar_is_zero(x);
#endif
- secp256k1_scalar_verify(x);
+ SECP256K1_SCALAR_VERIFY(x);
secp256k1_scalar_to_signed30(&s, x);
secp256k1_modinv32(&s, &secp256k1_const_modinfo_scalar);
secp256k1_scalar_from_signed30(r, &s);
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
-#endif
}
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
@@ -783,20 +807,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
#ifdef VERIFY
int zero_in = secp256k1_scalar_is_zero(x);
#endif
- secp256k1_scalar_verify(x);
+ SECP256K1_SCALAR_VERIFY(x);
secp256k1_scalar_to_signed30(&s, x);
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_scalar);
secp256k1_scalar_from_signed30(r, &s);
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
-#endif
}
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return !(a->d[0] & 1);
}
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 3eca23b4f9..bbba83e937 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -31,14 +31,12 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c
int overflow;
secp256k1_scalar_set_b32(r, bin, &overflow);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return (!overflow) & (!secp256k1_scalar_is_zero(r));
}
static void secp256k1_scalar_verify(const secp256k1_scalar *r) {
-#ifdef VERIFY
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
-#endif
(void)r;
}
@@ -63,7 +61,7 @@ static void secp256k1_scalar_verify(const secp256k1_scalar *r) {
* (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n).
*/
static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) {
- secp256k1_scalar_verify(k);
+ SECP256K1_SCALAR_VERIFY(k);
VERIFY_CHECK(r1 != k);
VERIFY_CHECK(r2 != k);
VERIFY_CHECK(r1 != r2);
@@ -71,8 +69,8 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
*r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER;
*r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
- secp256k1_scalar_verify(r1);
- secp256k1_scalar_verify(r2);
+ SECP256K1_SCALAR_VERIFY(r1);
+ SECP256K1_SCALAR_VERIFY(r2);
}
#else
/**
@@ -155,7 +153,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL,
0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL
);
- secp256k1_scalar_verify(k);
+ SECP256K1_SCALAR_VERIFY(k);
VERIFY_CHECK(r1 != k);
VERIFY_CHECK(r2 != k);
VERIFY_CHECK(r1 != r2);
@@ -170,8 +168,8 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
secp256k1_scalar_negate(r1, r1);
secp256k1_scalar_add(r1, r1, k);
- secp256k1_scalar_verify(r1);
- secp256k1_scalar_verify(r2);
+ SECP256K1_SCALAR_VERIFY(r1);
+ SECP256K1_SCALAR_VERIFY(r2);
#ifdef VERIFY
secp256k1_scalar_split_lambda_verify(r1, r2, k);
#endif
diff --git a/src/secp256k1/src/scalar_low.h b/src/secp256k1/src/scalar_low.h
index 67051bd30b..2711eb932d 100644
--- a/src/secp256k1/src/scalar_low.h
+++ b/src/secp256k1/src/scalar_low.h
@@ -1,5 +1,5 @@
/***********************************************************************
- * Copyright (c) 2015 Andrew Poelstra *
+ * Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
@@ -12,6 +12,13 @@
/** A scalar modulo the group order of the secp256k1 curve. */
typedef uint32_t secp256k1_scalar;
-#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) (d0)
+/* A compile-time constant equal to 2^32 (modulo order). */
+#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U)
+
+/* Compute a*2^32 + b (modulo order). */
+#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER)
+
+/* Evaluates to the provided 256-bit constant reduced modulo order. */
+#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0))
#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
index e2356a5be1..0895db6a17 100644
--- a/src/secp256k1/src/scalar_low_impl.h
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -14,7 +14,7 @@
#include <string.h>
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return !(*a & 1);
}
@@ -24,11 +24,11 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r =
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
*r = v % EXHAUSTIVE_TEST_ORDER;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
if (offset < 32)
return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
@@ -37,7 +37,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_s
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return secp256k1_scalar_get_bits(a, offset, count);
}
@@ -45,27 +45,25 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
*r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return *r < *b;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
if (flag && bit < 32)
*r += ((uint32_t)1 << bit);
- secp256k1_scalar_verify(r);
-#ifdef VERIFY
+ SECP256K1_SCALAR_VERIFY(r);
VERIFY_CHECK(bit < 32);
/* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */
VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER);
-#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
@@ -81,24 +79,24 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
}
if (overflow) *overflow = over;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
memset(bin, 0, 32);
bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return *a == 0;
}
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
if (*a == 0) {
*r = 0;
@@ -106,65 +104,52 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar
*r = EXHAUSTIVE_TEST_ORDER - *a;
}
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return *a == 1;
}
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
return *a > EXHAUSTIVE_TEST_ORDER / 2;
}
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
if (flag) secp256k1_scalar_negate(r, r);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
return flag ? -1 : 1;
}
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
*r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
- secp256k1_scalar_verify(r);
-}
-
-static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
- int ret;
- secp256k1_scalar_verify(r);
- VERIFY_CHECK(n > 0);
- VERIFY_CHECK(n < 16);
-
- ret = *r & ((1 << n) - 1);
- *r >>= n;
-
- secp256k1_scalar_verify(r);
- return ret;
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
*r1 = *a;
*r2 = 0;
- secp256k1_scalar_verify(r1);
- secp256k1_scalar_verify(r2);
+ SECP256K1_SCALAR_VERIFY(r1);
+ SECP256K1_SCALAR_VERIFY(r2);
}
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
- secp256k1_scalar_verify(a);
- secp256k1_scalar_verify(b);
+ SECP256K1_SCALAR_VERIFY(a);
+ SECP256K1_SCALAR_VERIFY(b);
return *a == *b;
}
@@ -172,37 +157,45 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
volatile int vflag = flag;
- secp256k1_scalar_verify(a);
+ SECP256K1_SCALAR_VERIFY(a);
SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r));
mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
*r = (*r & mask0) | (*a & mask1);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
}
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
int i;
*r = 0;
- secp256k1_scalar_verify(x);
+ SECP256K1_SCALAR_VERIFY(x);
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
*r = i;
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
/* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
* have a composite group order; fix it in exhaustive_tests.c). */
VERIFY_CHECK(*r != 0);
}
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
- secp256k1_scalar_verify(x);
+ SECP256K1_SCALAR_VERIFY(x);
secp256k1_scalar_inverse(r, x);
- secp256k1_scalar_verify(r);
+ SECP256K1_SCALAR_VERIFY(r);
+}
+
+static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ SECP256K1_SCALAR_VERIFY(a);
+
+ *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1;
+
+ SECP256K1_SCALAR_VERIFY(r);
}
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index d3959406c7..bec1c45585 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -23,6 +23,7 @@
#include "../include/secp256k1_preallocated.h"
#include "testrand_impl.h"
#include "checkmem.h"
+#include "testutil.h"
#include "util.h"
#include "../contrib/lax_der_parsing.c"
@@ -52,26 +53,32 @@ static int all_bytes_equal(const void* s, unsigned char value, size_t n) {
return 1;
}
-/* TODO Use CHECK_ILLEGAL(_VOID) everywhere and get rid of the uncounting callback */
-/* CHECK that expr_or_stmt calls the illegal callback of ctx exactly once
- *
- * For checking functions that use ARG_CHECK_VOID */
-#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) do { \
- int32_t _calls_to_illegal_callback = 0; \
- secp256k1_callback _saved_illegal_cb = ctx->illegal_callback; \
- secp256k1_context_set_illegal_callback(ctx, \
- counting_illegal_callback_fn, &_calls_to_illegal_callback); \
+#define CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, callback, callback_setter) do { \
+ int32_t _calls_to_callback = 0; \
+ secp256k1_callback _saved_callback = ctx->callback; \
+ callback_setter(ctx, counting_callback_fn, &_calls_to_callback); \
{ expr_or_stmt; } \
- ctx->illegal_callback = _saved_illegal_cb; \
- CHECK(_calls_to_illegal_callback == 1); \
+ ctx->callback = _saved_callback; \
+ CHECK(_calls_to_callback == 1); \
} while(0);
-/* CHECK that expr calls the illegal callback of ctx exactly once and that expr == 0
+/* CHECK that expr_or_stmt calls the error or illegal callback of ctx exactly once
+ *
+ * Useful for checking functions that return void (e.g., API functions that use ARG_CHECK_VOID) */
+#define CHECK_ERROR_VOID(ctx, expr_or_stmt) \
+ CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, error_callback, secp256k1_context_set_error_callback)
+#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) \
+ CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, illegal_callback, secp256k1_context_set_illegal_callback)
+
+/* CHECK that
+ * - expr calls the illegal callback of ctx exactly once and,
+ * - expr == 0 (or equivalently, expr == NULL)
*
- * For checking functions that use ARG_CHECK */
+ * Useful for checking functions that return an integer or a pointer. */
#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0))
+#define CHECK_ERROR(ctx, expr) CHECK_ERROR_VOID(ctx, CHECK((expr) == 0))
-static void counting_illegal_callback_fn(const char* str, void* data) {
+static void counting_callback_fn(const char* str, void* data) {
/* Dummy callback function that just counts. */
int32_t *p;
(void)str;
@@ -273,55 +280,34 @@ static void run_deprecated_context_flags_test(void) {
}
static void run_ec_illegal_argument_tests(void) {
- int ecount = 0;
- int ecount2 = 10;
secp256k1_pubkey pubkey;
secp256k1_pubkey zero_pubkey;
secp256k1_ecdsa_signature sig;
unsigned char ctmp[32];
/* Setup */
- secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount2);
memset(ctmp, 1, 32);
memset(&zero_pubkey, 0, sizeof(zero_pubkey));
/* Verify context-type checking illegal-argument errors. */
- CHECK(secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp));
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL));
SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig));
CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1);
SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig));
- CHECK(ecount2 == 10);
CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1);
- CHECK(ecount2 == 10);
CHECK(secp256k1_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1);
- CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1);
- CHECK(ecount2 == 10);
CHECK(secp256k1_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1);
- CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1);
- CHECK(ecount2 == 10);
CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1);
- CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey) == 1);
- CHECK(ecount == 2);
- CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey) == 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_ec_pubkey_negate(CTX, NULL) == 0);
- CHECK(ecount2 == 11);
+ CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey));
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_negate(CTX, NULL));
CHECK(secp256k1_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1);
- CHECK(ecount == 3);
-
- /* Clean up */
- secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
static void run_static_context_tests(int use_prealloc) {
@@ -356,8 +342,8 @@ static void run_static_context_tests(int use_prealloc) {
{
/* Verify that setting and resetting illegal callback works */
int32_t dummy = 0;
- secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy);
- CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn);
+ secp256k1_context_set_illegal_callback(STATIC_CTX, counting_callback_fn, &dummy);
+ CHECK(STATIC_CTX->illegal_callback.fn == counting_callback_fn);
CHECK(STATIC_CTX->illegal_callback.data == &dummy);
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
@@ -448,8 +434,8 @@ static void run_proper_context_tests(int use_prealloc) {
CHECK(context_eq(my_ctx, my_ctx_fresh));
/* Verify that setting and resetting illegal callback works */
- secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy);
- CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn);
+ secp256k1_context_set_illegal_callback(my_ctx, counting_callback_fn, &dummy);
+ CHECK(my_ctx->illegal_callback.fn == counting_callback_fn);
CHECK(my_ctx->illegal_callback.data == &dummy);
secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL);
CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
@@ -490,19 +476,14 @@ static void run_proper_context_tests(int use_prealloc) {
static void run_scratch_tests(void) {
const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
- int32_t ecount = 0;
size_t checkpoint;
size_t checkpoint_2;
secp256k1_scratch_space *scratch;
secp256k1_scratch_space local_scratch;
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
- secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
-
/* Test public API */
scratch = secp256k1_scratch_space_create(CTX, 1000);
CHECK(scratch != NULL);
- CHECK(ecount == 0);
/* Test internal API */
CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000);
@@ -535,22 +516,16 @@ static void run_scratch_tests(void) {
/* try to apply a bad checkpoint */
checkpoint_2 = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch);
secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint);
- CHECK(ecount == 0);
- secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */
- CHECK(ecount == 1);
- secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */
- CHECK(ecount == 2);
+ CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */
+ CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */
/* try to use badly initialized scratch space */
secp256k1_scratch_space_destroy(CTX, scratch);
memset(&local_scratch, 0, sizeof(local_scratch));
scratch = &local_scratch;
- CHECK(!secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0));
- CHECK(ecount == 3);
- CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) == NULL);
- CHECK(ecount == 4);
- secp256k1_scratch_space_destroy(CTX, scratch);
- CHECK(ecount == 5);
+ CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0));
+ CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500));
+ CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch));
/* Test that large integers do not wrap around in a bad way */
scratch = secp256k1_scratch_space_create(CTX, 1000);
@@ -566,9 +541,6 @@ static void run_scratch_tests(void) {
/* cleanup */
secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */
-
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
- secp256k1_context_set_error_callback(CTX, NULL, NULL);
}
static void run_ctz_tests(void) {
@@ -848,7 +820,6 @@ static void run_rfc6979_hmac_sha256_tests(void) {
}
static void run_tagged_sha256_tests(void) {
- int ecount = 0;
unsigned char tag[32] = { 0 };
unsigned char msg[32] = { 0 };
unsigned char hash32[32];
@@ -859,16 +830,11 @@ static void run_tagged_sha256_tests(void) {
0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3
};
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
-
/* API test */
CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1);
- CHECK(secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg)) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg)));
+ CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg)));
+ CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0));
/* Static test vector */
memcpy(tag, "tag", 3);
@@ -2215,20 +2181,6 @@ static void scalar_test(void) {
}
{
- /* test secp256k1_scalar_shr_int */
- secp256k1_scalar r;
- int i;
- random_scalar_order_test(&r);
- for (i = 0; i < 100; ++i) {
- int low;
- int shift = 1 + secp256k1_testrand_int(15);
- int expected = r.d[0] % (1ULL << shift);
- low = secp256k1_scalar_shr_int(&r, shift);
- CHECK(expected == low);
- }
- }
-
- {
/* Test commutativity of add. */
secp256k1_scalar r1, r2;
secp256k1_scalar_add(&r1, &s1, &s2);
@@ -2319,6 +2271,13 @@ static void scalar_test(void) {
CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero));
}
+ {
+ /* Test halving. */
+ secp256k1_scalar r;
+ secp256k1_scalar_add(&r, &s, &s);
+ secp256k1_scalar_half(&r, &r);
+ CHECK(secp256k1_scalar_eq(&r, &s));
+ }
}
static void run_scalar_set_b32_seckey_tests(void) {
@@ -2372,6 +2331,38 @@ static void run_scalar_tests(void) {
}
{
+ /* Test that halving and doubling roundtrips on some fixed values. */
+ static const secp256k1_scalar HALF_TESTS[] = {
+ /* 0 */
+ SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0),
+ /* 1 */
+ SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1),
+ /* -1 */
+ SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd0364140ul),
+ /* -2 (largest odd value) */
+ SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd036413Ful),
+ /* Half the secp256k1 order */
+ SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a0ul),
+ /* Half the secp256k1 order + 1 */
+ SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a1ul),
+ /* 2^255 */
+ SECP256K1_SCALAR_CONST(0x80000000ul, 0, 0, 0, 0, 0, 0, 0),
+ /* 2^255 - 1 */
+ SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful),
+ };
+ unsigned n;
+ for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) {
+ secp256k1_scalar s;
+ secp256k1_scalar_half(&s, &HALF_TESTS[n]);
+ secp256k1_scalar_add(&s, &s, &s);
+ CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n]));
+ secp256k1_scalar_add(&s, &s, &s);
+ secp256k1_scalar_half(&s, &s);
+ CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n]));
+ }
+ }
+
+ {
/* Does check_overflow check catch all ones? */
static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
@@ -2956,29 +2947,6 @@ static void run_scalar_tests(void) {
/***** FIELD TESTS *****/
-static void random_fe(secp256k1_fe *x) {
- unsigned char bin[32];
- do {
- secp256k1_testrand256(bin);
- if (secp256k1_fe_set_b32_limit(x, bin)) {
- return;
- }
- } while(1);
-}
-
-static void random_fe_non_zero(secp256k1_fe *nz) {
- int tries = 10;
- while (--tries >= 0) {
- random_fe(nz);
- secp256k1_fe_normalize(nz);
- if (!secp256k1_fe_is_zero(nz)) {
- break;
- }
- }
- /* Infinitesimal probability of spurious failure here */
- CHECK(tries >= 0);
-}
-
static void random_fe_non_square(secp256k1_fe *ns) {
secp256k1_fe r;
random_fe_non_zero(ns);
@@ -3698,15 +3666,6 @@ static void run_inverse_tests(void)
/***** GROUP TESTS *****/
-static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
- CHECK(a->infinity == b->infinity);
- if (a->infinity) {
- return;
- }
- CHECK(secp256k1_fe_equal(&a->x, &b->x));
- CHECK(secp256k1_fe_equal(&a->y, &b->y));
-}
-
/* This compares jacobian points including their Z, not just their geometric meaning. */
static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej a2;
@@ -3729,23 +3688,6 @@ static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {
return ret;
}
-static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
- secp256k1_fe z2s;
- secp256k1_fe u1, u2, s1, s2;
- CHECK(a->infinity == b->infinity);
- if (a->infinity) {
- return;
- }
- /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
- secp256k1_fe_sqr(&z2s, &b->z);
- secp256k1_fe_mul(&u1, &a->x, &z2s);
- u2 = b->x;
- secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
- s2 = b->y;
- CHECK(secp256k1_fe_equal(&u1, &u2));
- CHECK(secp256k1_fe_equal(&s1, &s2));
-}
-
static void test_ge(void) {
int i, i1;
int runs = 6;
@@ -3764,11 +3706,12 @@ static void test_ge(void) {
secp256k1_ge_clear(&ge[0]);
secp256k1_ge_set_gej_var(&ge[0], &gej[0]);
for (i = 0; i < runs; i++) {
- int j;
+ int j, k;
secp256k1_ge g;
random_group_element_test(&g);
if (i >= runs - 2) {
secp256k1_ge_mul_lambda(&g, &ge[1]);
+ CHECK(!secp256k1_ge_eq_var(&g, &ge[1]));
}
if (i >= runs - 1) {
secp256k1_ge_mul_lambda(&g, &g);
@@ -3788,6 +3731,16 @@ static void test_ge(void) {
random_gej_y_magnitude(&gej[1 + j + 4 * i]);
random_gej_z_magnitude(&gej[1 + j + 4 * i]);
}
+
+ for (j = 0; j < 4; ++j) {
+ for (k = 0; k < 4; ++k) {
+ int expect_equal = (j >> 1) == (k >> 1);
+ CHECK(secp256k1_ge_eq_var(&ge[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal);
+ CHECK(secp256k1_gej_eq_var(&gej[1 + j + 4 * i], &gej[1 + k + 4 * i]) == expect_equal);
+ CHECK(secp256k1_gej_eq_ge_var(&gej[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal);
+ CHECK(secp256k1_gej_eq_ge_var(&gej[1 + k + 4 * i], &ge[1 + j + 4 * i]) == expect_equal);
+ }
+ }
}
/* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */
@@ -3817,7 +3770,7 @@ static void test_ge(void) {
/* Test gej + ge with Z ratio result (var). */
secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr);
- ge_equals_gej(&ref, &resj);
+ CHECK(secp256k1_gej_eq_ge_var(&resj, &ref));
if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) {
secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z);
CHECK(secp256k1_fe_equal(&zrz, &resj.z));
@@ -3831,14 +3784,14 @@ static void test_ge(void) {
random_ge_x_magnitude(&ge2_zfi);
random_ge_y_magnitude(&ge2_zfi);
secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf);
- ge_equals_gej(&ref, &resj);
+ CHECK(secp256k1_gej_eq_ge_var(&resj, &ref));
}
/* Test gej + ge (const). */
if (i2 != 0) {
/* secp256k1_gej_add_ge does not support its second argument being infinity. */
secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]);
- ge_equals_gej(&ref, &resj);
+ CHECK(secp256k1_gej_eq_ge_var(&resj, &ref));
}
/* Test doubling (var). */
@@ -3846,16 +3799,16 @@ static void test_ge(void) {
secp256k1_fe zr2;
/* Normal doubling with Z ratio result. */
secp256k1_gej_double_var(&resj, &gej[i1], &zr2);
- ge_equals_gej(&ref, &resj);
+ CHECK(secp256k1_gej_eq_ge_var(&resj, &ref));
/* Check Z ratio. */
secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z);
CHECK(secp256k1_fe_equal(&zr2, &resj.z));
/* Normal doubling. */
secp256k1_gej_double_var(&resj, &gej[i2], NULL);
- ge_equals_gej(&ref, &resj);
+ CHECK(secp256k1_gej_eq_ge_var(&resj, &ref));
/* Constant-time doubling. */
secp256k1_gej_double(&resj, &gej[i2]);
- ge_equals_gej(&ref, &resj);
+ CHECK(secp256k1_gej_eq_ge_var(&resj, &ref));
}
/* Test adding opposites. */
@@ -3867,12 +3820,12 @@ static void test_ge(void) {
if (i1 == 0) {
CHECK(secp256k1_ge_is_infinity(&ge[i1]));
CHECK(secp256k1_gej_is_infinity(&gej[i1]));
- ge_equals_gej(&ref, &gej[i2]);
+ CHECK(secp256k1_gej_eq_ge_var(&gej[i2], &ref));
}
if (i2 == 0) {
CHECK(secp256k1_ge_is_infinity(&ge[i2]));
CHECK(secp256k1_gej_is_infinity(&gej[i2]));
- ge_equals_gej(&ref, &gej[i1]);
+ CHECK(secp256k1_gej_eq_ge_var(&gej[i1], &ref));
}
}
}
@@ -3907,7 +3860,7 @@ static void test_ge(void) {
secp256k1_fe s;
random_fe_non_zero(&s);
secp256k1_gej_rescale(&gej[i], &s);
- ge_equals_gej(&ge_set_all[i], &gej[i]);
+ CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i]));
}
free(ge_set_all);
}
@@ -3951,7 +3904,7 @@ static void test_ge(void) {
secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1);
/* check result */
for (i = 0; i < 4 * runs + 1; i++) {
- ge_equals_gej(&ge[i], &gej[i]);
+ CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge[i]));
}
/* Test batch gej -> ge conversion with all infinities. */
@@ -4050,15 +4003,15 @@ static void test_add_neg_y_diff_x(void) {
secp256k1_gej_add_var(&resj, &aj, &bj, NULL);
secp256k1_ge_set_gej(&res, &resj);
- ge_equals_gej(&res, &sumj);
+ CHECK(secp256k1_gej_eq_ge_var(&sumj, &res));
secp256k1_gej_add_ge(&resj, &aj, &b);
secp256k1_ge_set_gej(&res, &resj);
- ge_equals_gej(&res, &sumj);
+ CHECK(secp256k1_gej_eq_ge_var(&sumj, &res));
secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL);
secp256k1_ge_set_gej(&res, &resj);
- ge_equals_gej(&res, &sumj);
+ CHECK(secp256k1_gej_eq_ge_var(&sumj, &res));
}
static void run_ge(void) {
@@ -4351,10 +4304,10 @@ static void test_point_times_order(const secp256k1_gej *point) {
CHECK(secp256k1_ge_is_infinity(&res3));
secp256k1_ecmult(&res1, point, &secp256k1_scalar_one, &secp256k1_scalar_zero);
secp256k1_ge_set_gej(&res3, &res1);
- ge_equals_gej(&res3, point);
+ CHECK(secp256k1_gej_eq_ge_var(point, &res3));
secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one);
secp256k1_ge_set_gej(&res3, &res1);
- ge_equals_ge(&res3, &secp256k1_ge_const_g);
+ CHECK(secp256k1_ge_eq_var(&secp256k1_ge_const_g, &res3));
}
/* These scalars reach large (in absolute value) outputs when fed to secp256k1_scalar_split_lambda.
@@ -4482,7 +4435,7 @@ static void ecmult_const_random_mult(void) {
secp256k1_ecmult_const(&b, &a, &xn);
CHECK(secp256k1_ge_is_valid_var(&a));
- ge_equals_gej(&expected_b, &b);
+ CHECK(secp256k1_gej_eq_ge_var(&b, &expected_b));
}
static void ecmult_const_commutativity(void) {
@@ -4503,27 +4456,76 @@ static void ecmult_const_commutativity(void) {
secp256k1_ecmult_const(&res2, &mid2, &a);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
- ge_equals_ge(&mid1, &mid2);
+ CHECK(secp256k1_ge_eq_var(&mid1, &mid2));
}
static void ecmult_const_mult_zero_one(void) {
+ secp256k1_scalar s;
secp256k1_scalar negone;
secp256k1_gej res1;
secp256k1_ge res2;
secp256k1_ge point;
- secp256k1_scalar_negate(&negone, &secp256k1_scalar_one);
+ secp256k1_ge inf;
+ random_scalar_order_test(&s);
+ secp256k1_scalar_negate(&negone, &secp256k1_scalar_one);
random_group_element_test(&point);
+ secp256k1_ge_set_infinity(&inf);
+
+ /* 0*point */
secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_zero);
- secp256k1_ge_set_gej(&res2, &res1);
- CHECK(secp256k1_ge_is_infinity(&res2));
+ CHECK(secp256k1_gej_is_infinity(&res1));
+
+ /* s*inf */
+ secp256k1_ecmult_const(&res1, &inf, &s);
+ CHECK(secp256k1_gej_is_infinity(&res1));
+
+ /* 1*point */
secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_one);
secp256k1_ge_set_gej(&res2, &res1);
- ge_equals_ge(&res2, &point);
+ CHECK(secp256k1_ge_eq_var(&res2, &point));
+
+ /* -1*point */
secp256k1_ecmult_const(&res1, &point, &negone);
secp256k1_gej_neg(&res1, &res1);
secp256k1_ge_set_gej(&res2, &res1);
- ge_equals_ge(&res2, &point);
+ CHECK(secp256k1_ge_eq_var(&res2, &point));
+}
+
+static void ecmult_const_check_result(const secp256k1_ge *A, const secp256k1_scalar* q, const secp256k1_gej *res) {
+ secp256k1_gej pointj, res2j;
+ secp256k1_ge res2;
+ secp256k1_gej_set_ge(&pointj, A);
+ secp256k1_ecmult(&res2j, &pointj, q, &secp256k1_scalar_zero);
+ secp256k1_ge_set_gej(&res2, &res2j);
+ CHECK(secp256k1_gej_eq_ge_var(res, &res2));
+}
+
+static void ecmult_const_edges(void) {
+ secp256k1_scalar q;
+ secp256k1_ge point;
+ secp256k1_gej res;
+ size_t i;
+ size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]);
+
+ /* We are trying to reach the following edge cases (variables are defined as
+ * in ecmult_const_impl.h):
+ * 1. i = 0: s = 0 <=> q = -K
+ * 2. i > 0: v1, v2 large values
+ * <=> s1, s2 large values
+ * <=> s = scalars_near_split_bounds[i]
+ * <=> q = 2*scalars_near_split_bounds[i] - K
+ */
+ for (i = 0; i < cases; ++i) {
+ secp256k1_scalar_negate(&q, &secp256k1_ecmult_const_K);
+ if (i > 0) {
+ secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]);
+ secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]);
+ }
+ random_group_element_test(&point);
+ secp256k1_ecmult_const(&res, &point, &q);
+ ecmult_const_check_result(&point, &q, &res);
+ }
}
static void ecmult_const_mult_xonly(void) {
@@ -4604,11 +4606,12 @@ static void ecmult_const_chain_multiply(void) {
secp256k1_ecmult_const(&point, &tmp, &scalar);
}
secp256k1_ge_set_gej(&res, &point);
- ge_equals_gej(&res, &expected_point);
+ CHECK(secp256k1_gej_eq_ge_var(&expected_point, &res));
}
static void run_ecmult_const_tests(void) {
ecmult_const_mult_zero_one();
+ ecmult_const_edges();
ecmult_const_random_mult();
ecmult_const_commutativity();
ecmult_const_chain_multiply();
@@ -5269,73 +5272,17 @@ static void test_wnaf(const secp256k1_scalar *number, int w) {
CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */
}
-static void test_constant_wnaf_negate(const secp256k1_scalar *number) {
- secp256k1_scalar neg1 = *number;
- secp256k1_scalar neg2 = *number;
- int sign1 = 1;
- int sign2 = 1;
-
- if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) {
- secp256k1_scalar_negate(&neg1, &neg1);
- sign1 = -1;
- }
- sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2));
- CHECK(sign1 == sign2);
- CHECK(secp256k1_scalar_eq(&neg1, &neg2));
-}
-
-static void test_constant_wnaf(const secp256k1_scalar *number, int w) {
- secp256k1_scalar x, shift;
- int wnaf[256] = {0};
- int i;
- int skew;
- int bits = 256;
- secp256k1_scalar num = *number;
- secp256k1_scalar scalar_skew;
-
- secp256k1_scalar_set_int(&x, 0);
- secp256k1_scalar_set_int(&shift, 1 << w);
- for (i = 0; i < 16; ++i) {
- secp256k1_scalar_shr_int(&num, 8);
- }
- bits = 128;
- skew = secp256k1_wnaf_const(wnaf, &num, w, bits);
-
- for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) {
- secp256k1_scalar t;
- int v = wnaf[i];
- CHECK(v != 0); /* check nonzero */
- CHECK(v & 1); /* check parity */
- CHECK(v > -(1 << w)); /* check range above */
- CHECK(v < (1 << w)); /* check range below */
-
- secp256k1_scalar_mul(&x, &x, &shift);
- if (v >= 0) {
- secp256k1_scalar_set_int(&t, v);
- } else {
- secp256k1_scalar_set_int(&t, -v);
- secp256k1_scalar_negate(&t, &t);
- }
- secp256k1_scalar_add(&x, &x, &t);
- }
- /* Skew num because when encoding numbers as odd we use an offset */
- secp256k1_scalar_set_int(&scalar_skew, skew);
- secp256k1_scalar_add(&num, &num, &scalar_skew);
- CHECK(secp256k1_scalar_eq(&x, &num));
-}
-
static void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, shift;
int wnaf[256] = {0};
int i;
int skew;
- secp256k1_scalar num = *number;
+ secp256k1_scalar num, unused;
secp256k1_scalar_set_int(&x, 0);
secp256k1_scalar_set_int(&shift, 1 << w);
- for (i = 0; i < 16; ++i) {
- secp256k1_scalar_shr_int(&num, 8);
- }
+ /* Make num a 128-bit scalar. */
+ secp256k1_scalar_split_128(&num, &unused, number);
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
for (i = WNAF_SIZE(w)-1; i >= 0; --i) {
@@ -5427,32 +5374,7 @@ static void test_fixed_wnaf_small(void) {
static void run_wnaf(void) {
int i;
- secp256k1_scalar n = {{0}};
-
- test_constant_wnaf(&n, 4);
- /* Sanity check: 1 and 2 are the smallest odd and even numbers and should
- * have easier-to-diagnose failure modes */
- n.d[0] = 1;
- test_constant_wnaf(&n, 4);
- n.d[0] = 2;
- test_constant_wnaf(&n, 4);
- /* Test -1, because it's a special case in wnaf_const */
- n = secp256k1_scalar_one;
- secp256k1_scalar_negate(&n, &n);
- test_constant_wnaf(&n, 4);
-
- /* Test -2, which may not lead to overflows in wnaf_const */
- secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one);
- secp256k1_scalar_negate(&n, &n);
- test_constant_wnaf(&n, 4);
-
- /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1
- as corner cases of negation handling in wnaf_const */
- secp256k1_scalar_inverse(&n, &n);
- test_constant_wnaf(&n, 4);
-
- secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one);
- test_constant_wnaf(&n, 4);
+ secp256k1_scalar n;
/* Test 0 for fixed wnaf */
test_fixed_wnaf_small();
@@ -5460,8 +5382,6 @@ static void run_wnaf(void) {
for (i = 0; i < COUNT; i++) {
random_scalar_order(&n);
test_wnaf(&n, 4+(i%10));
- test_constant_wnaf_negate(&n);
- test_constant_wnaf(&n, 4 + (i % 10));
test_fixed_wnaf(&n, 4 + (i % 10));
}
secp256k1_scalar_set_int(&n, 0);
@@ -5494,11 +5414,11 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar
secp256k1_ecmult_multi_var(NULL, scratch, &rj5, &secp256k1_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1);
secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x);
secp256k1_ge_set_gej_var(&r, &rj1);
- ge_equals_gej(&r, &rj2);
- ge_equals_gej(&r, &rj3);
- ge_equals_gej(&r, &rj4);
- ge_equals_gej(&r, &rj5);
- ge_equals_gej(&r, &rj6);
+ CHECK(secp256k1_gej_eq_ge_var(&rj2, &r));
+ CHECK(secp256k1_gej_eq_ge_var(&rj3, &r));
+ CHECK(secp256k1_gej_eq_ge_var(&rj4, &r));
+ CHECK(secp256k1_gej_eq_ge_var(&rj5, &r));
+ CHECK(secp256k1_gej_eq_ge_var(&rj6, &r));
if (secp256k1_ge_is_infinity(&r)) {
/* Store infinity as 0x00 */
const unsigned char zerobyte[1] = {0};
@@ -5652,7 +5572,7 @@ static void test_ecmult_gen_blind(void) {
CHECK(!gej_xyz_equals_gej(&pgej, &pgej2));
CHECK(!gej_xyz_equals_gej(&i, &CTX->ecmult_gen_ctx.initial));
secp256k1_ge_set_gej(&pge, &pgej);
- ge_equals_gej(&pge, &pgej2);
+ CHECK(secp256k1_gej_eq_ge_var(&pgej2, &pge));
}
static void test_ecmult_gen_blind_reset(void) {
@@ -5729,9 +5649,7 @@ static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, in
secp256k1_pubkey pubkey;
secp256k1_ge ge;
size_t pubkeyclen;
- int32_t ecount;
- ecount = 0;
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
+
for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) {
/* Smaller sizes are tested exhaustively elsewhere. */
int32_t i;
@@ -5756,7 +5674,6 @@ static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, in
size_t outl;
memset(&pubkey, 0, sizeof(pubkey));
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
- ecount = 0;
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
outl = 65;
@@ -5782,21 +5699,16 @@ static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, in
CHECK(pubkeyo[0] == 4);
CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0);
}
- CHECK(ecount == 0);
} else {
/* These cases must fail to parse. */
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
}
}
}
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
static void run_ec_pubkey_parse_test(void) {
@@ -5979,142 +5891,99 @@ static void run_ec_pubkey_parse_test(void) {
0xB8, 0x00
};
unsigned char sout[65];
- unsigned char shortkey[2];
+ unsigned char shortkey[2] = { 0 };
secp256k1_ge ge;
secp256k1_pubkey pubkey;
size_t len;
int32_t i;
- int32_t ecount;
- int32_t ecount2;
- ecount = 0;
+
/* Nothing should be reading this far into pubkeyc. */
SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1);
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
/* Zero length claimed, fail, zeroize, no illegal arg error. */
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2);
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
/* Length one claimed, fail, zeroize, no illegal arg error. */
for (i = 0; i < 256 ; i++) {
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
shortkey[0] = i;
SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1);
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
}
/* Length two claimed, fail, zeroize, no illegal arg error. */
for (i = 0; i < 65536 ; i++) {
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
shortkey[0] = i & 255;
shortkey[1] = i >> 8;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
}
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
/* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
/* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */
- CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65));
/* NULL input string. Illegal arg and zeroize output. */
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65));
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 1);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
/* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
/* 66 bytes claimed, fail, zeroize output, no illegal arg error. */
memset(&pubkey, 0xfe, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
- CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey));
/* Valid parse. */
memset(&pubkey, 0, sizeof(pubkey));
- ecount = 0;
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1);
CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey));
- CHECK(ecount == 0);
SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge));
CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1);
SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x));
SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y));
SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity));
- ge_equals_ge(&secp256k1_ge_const_g, &ge);
- CHECK(ecount == 0);
+ CHECK(secp256k1_ge_eq_var(&ge, &secp256k1_ge_const_g));
/* secp256k1_ec_pubkey_serialize illegal args. */
- ecount = 0;
len = 65;
- CHECK(secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED));
CHECK(len == 0);
- CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED));
len = 65;
SECP256K1_CHECKMEM_UNDEFINE(sout, 65);
- CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED));
SECP256K1_CHECKMEM_CHECK(sout, 65);
- CHECK(ecount == 3);
CHECK(len == 0);
len = 65;
- CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0) == 0);
- CHECK(ecount == 4);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0));
CHECK(len == 0);
len = 65;
SECP256K1_CHECKMEM_UNDEFINE(sout, 65);
CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
SECP256K1_CHECKMEM_CHECK(sout, 65);
- CHECK(ecount == 4);
CHECK(len == 65);
/* Multiple illegal args. Should still set arg error only once. */
- ecount = 0;
- ecount2 = 11;
- CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65) == 0);
- CHECK(ecount == 1);
- /* Does the illegal arg callback actually change the behavior? */
- secp256k1_context_set_illegal_callback(CTX, uncounting_illegal_callback_fn, &ecount2);
- CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65) == 0);
- CHECK(ecount == 1);
- CHECK(ecount2 == 10);
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65));
/* Try a bunch of prefabbed points with all possible encodings. */
for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) {
ec_pubkey_parse_pointtest(valid[i], 1, 1);
@@ -6143,7 +6012,6 @@ static void run_eckey_edge_case_test(void) {
secp256k1_pubkey pubkey_negone;
const secp256k1_pubkey *pubkeys[3];
size_t len;
- int32_t ecount;
/* Group order is too large, reject. */
CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0);
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
@@ -6265,88 +6133,59 @@ static void run_eckey_edge_case_test(void) {
ctmp2[31] = 2;
CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
- /* Test argument errors. */
- ecount = 0;
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
- CHECK(ecount == 0);
/* Zeroize pubkey on parse error. */
memset(&pubkey, 0, 32);
- CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0);
memcpy(&pubkey, &pubkey2, sizeof(pubkey));
memset(&pubkey2, 0, 32);
- CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2));
CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0);
/* Plain argument errors. */
- ecount = 0;
CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ec_seckey_verify(CTX, NULL) == 0);
- CHECK(ecount == 1);
- ecount = 0;
+ CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_verify(CTX, NULL));
memset(ctmp2, 0, 32);
ctmp2[31] = 4;
- CHECK(secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL) == 0);
- CHECK(ecount == 2);
- ecount = 0;
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2));
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL));
memset(ctmp2, 0, 32);
ctmp2[31] = 4;
- CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL) == 0);
- CHECK(ecount == 2);
- ecount = 0;
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2));
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL));
memset(ctmp2, 0, 32);
- CHECK(secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL) == 0);
- CHECK(ecount == 2);
- ecount = 0;
+ CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2));
+ CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL));
memset(ctmp2, 0, 32);
ctmp2[31] = 1;
- CHECK(secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL) == 0);
- CHECK(ecount == 2);
- ecount = 0;
- CHECK(secp256k1_ec_pubkey_create(CTX, NULL, ctmp) == 0);
- CHECK(ecount == 1);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2));
+ CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, NULL, ctmp));
memset(&pubkey, 1, sizeof(pubkey));
- CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, NULL) == 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
/* secp256k1_ec_pubkey_combine tests. */
- ecount = 0;
pubkeys[0] = &pubkey_one;
SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *));
SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *));
SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *));
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0));
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
- CHECK(ecount == 2);
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
- CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1) == 0);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1));
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
- CHECK(ecount == 3);
pubkeys[0] = &pubkey_negone;
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
- CHECK(ecount == 3);
len = 33;
CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1);
@@ -6359,7 +6198,6 @@ static void run_eckey_edge_case_test(void) {
CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);
- CHECK(ecount == 3);
/* Passes through infinity but comes out one. */
pubkeys[2] = &pubkey_one;
memset(&pubkey, 255, sizeof(secp256k1_pubkey));
@@ -6367,7 +6205,6 @@ static void run_eckey_edge_case_test(void) {
CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
- CHECK(ecount == 3);
len = 33;
CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1);
@@ -6379,8 +6216,6 @@ static void run_eckey_edge_case_test(void) {
CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1);
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
- CHECK(ecount == 3);
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
static void run_eckey_negate_test(void) {
@@ -6697,7 +6532,7 @@ static void test_random_pubkeys(void) {
CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0));
CHECK(size == 65);
CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size));
- ge_equals_ge(&elem,&elem2);
+ CHECK(secp256k1_ge_eq_var(&elem2, &elem));
/* Check that the X9.62 hybrid type is checked. */
in[0] = secp256k1_testrand_bits(1) ? 6 : 7;
res = secp256k1_eckey_pubkey_parse(&elem2, in, size);
@@ -6709,7 +6544,7 @@ static void test_random_pubkeys(void) {
}
}
if (res) {
- ge_equals_ge(&elem,&elem2);
+ CHECK(secp256k1_ge_eq_var(&elem, &elem2));
CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0));
CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0);
}
@@ -6729,34 +6564,30 @@ static void run_pubkey_comparison(void) {
};
secp256k1_pubkey pk1;
secp256k1_pubkey pk2;
- int32_t ecount = 0;
CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1);
CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1);
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
- CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0);
- CHECK(ecount == 2);
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0));
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0));
CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0);
CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0);
CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0);
CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0);
- CHECK(ecount == 2);
{
secp256k1_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */
- CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0);
- CHECK(ecount == 3);
- CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0);
- CHECK(ecount == 5);
- CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0);
- CHECK(ecount == 6);
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0));
+ {
+ int32_t ecount = 0;
+ secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount);
+ CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0);
+ CHECK(ecount == 2);
+ secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
+ }
+ CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0));
}
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
-
/* Make pk2 the same as pk1 but with 3 rather than 2. Note that in
* an uncompressed encoding, these would have the opposite ordering */
pk1_ser[0] = 3;
@@ -7226,7 +7057,6 @@ static void test_ecdsa_edge_cases(void) {
{
secp256k1_pubkey pubkey;
size_t siglen;
- int32_t ecount;
unsigned char signature[72];
static const unsigned char nonce[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -7252,72 +7082,42 @@ static void test_ecdsa_edge_cases(void) {
0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
};
- ecount = 0;
- secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0);
CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0);
msg[31] = 0xaa;
CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1);
- CHECK(ecount == 0);
- CHECK(secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2));
CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1);
- CHECK(secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey) == 0);
- CHECK(ecount == 4);
- CHECK(secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey) == 0);
- CHECK(ecount == 5);
- CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, NULL) == 0);
- CHECK(ecount == 6);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, NULL));
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1);
- CHECK(ecount == 6);
- CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, NULL) == 0);
- CHECK(ecount == 7);
+ CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL));
/* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */
- CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 0);
- CHECK(ecount == 8);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey));
siglen = 72;
- CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig) == 0);
- CHECK(ecount == 9);
- CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig) == 0);
- CHECK(ecount == 10);
- CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL) == 0);
- CHECK(ecount == 11);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL));
CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1);
- CHECK(ecount == 11);
- CHECK(secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen) == 0);
- CHECK(ecount == 12);
- CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen) == 0);
- CHECK(ecount == 13);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen));
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1);
- CHECK(ecount == 13);
siglen = 10;
/* Too little room for a signature does not fail via ARGCHECK. */
CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0);
- CHECK(ecount == 13);
- ecount = 0;
- CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL) == 0);
- CHECK(ecount == 1);
- CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig) == 0);
- CHECK(ecount == 2);
- CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL) == 0);
- CHECK(ecount == 3);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL));
CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1);
- CHECK(ecount == 3);
- CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature) == 0);
- CHECK(ecount == 4);
- CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL) == 0);
- CHECK(ecount == 5);
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature));
+ CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL));
CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1);
- CHECK(ecount == 5);
memset(signature, 255, 64);
CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0);
- CHECK(ecount == 5);
- secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
/* Nonce function corner cases. */
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index 3af8ec1ee5..1a8be57d07 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -28,61 +28,11 @@
#include "testrand_impl.h"
#include "ecmult_compute_table_impl.h"
#include "ecmult_gen_compute_table_impl.h"
+#include "testutil.h"
#include "util.h"
static int count = 2;
-/** stolen from tests.c */
-static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
- CHECK(a->infinity == b->infinity);
- if (a->infinity) {
- return;
- }
- CHECK(secp256k1_fe_equal(&a->x, &b->x));
- CHECK(secp256k1_fe_equal(&a->y, &b->y));
-}
-
-static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
- secp256k1_fe z2s;
- secp256k1_fe u1, u2, s1, s2;
- CHECK(a->infinity == b->infinity);
- if (a->infinity) {
- return;
- }
- /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
- secp256k1_fe_sqr(&z2s, &b->z);
- secp256k1_fe_mul(&u1, &a->x, &z2s);
- u2 = b->x;
- secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
- s2 = b->y;
- CHECK(secp256k1_fe_equal(&u1, &u2));
- CHECK(secp256k1_fe_equal(&s1, &s2));
-}
-
-static void random_fe(secp256k1_fe *x) {
- unsigned char bin[32];
- do {
- secp256k1_testrand256(bin);
- if (secp256k1_fe_set_b32_limit(x, bin)) {
- return;
- }
- } while(1);
-}
-
-static void random_fe_non_zero(secp256k1_fe *nz) {
- int tries = 10;
- while (--tries >= 0) {
- random_fe(nz);
- secp256k1_fe_normalize(nz);
- if (!secp256k1_fe_is_zero(nz)) {
- break;
- }
- }
- /* Infinitesimal probability of spurious failure here */
- CHECK(tries >= 0);
-}
-/** END stolen from tests.c */
-
static uint32_t num_cores = 1;
static uint32_t this_core = 0;
@@ -117,7 +67,7 @@ static void test_exhaustive_endomorphism(const secp256k1_ge *group) {
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
secp256k1_ge res;
secp256k1_ge_mul_lambda(&res, &group[i]);
- ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res);
+ CHECK(secp256k1_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res));
}
}
@@ -143,21 +93,21 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_
secp256k1_gej tmp;
/* add_var */
secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL);
- ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
/* add_ge */
if (j > 0) {
secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]);
- ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
}
/* add_ge_var */
secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL);
- ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
/* add_zinv_var */
zless_gej.infinity = groupj[j].infinity;
zless_gej.x = groupj[j].x;
zless_gej.y = groupj[j].y;
secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv);
- ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
}
}
@@ -165,9 +115,9 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
secp256k1_gej tmp;
secp256k1_gej_double(&tmp, &groupj[i]);
- ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER]));
secp256k1_gej_double_var(&tmp, &groupj[i], NULL);
- ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER]));
}
/* Check negation */
@@ -175,9 +125,9 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_
secp256k1_ge tmp;
secp256k1_gej tmpj;
secp256k1_ge_neg(&tmp, &group[i]);
- ge_equals_ge(&group[EXHAUSTIVE_TEST_ORDER - i], &tmp);
+ CHECK(secp256k1_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i]));
secp256k1_gej_neg(&tmpj, &groupj[i]);
- ge_equals_gej(&group[EXHAUSTIVE_TEST_ORDER - i], &tmpj);
+ CHECK(secp256k1_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i]));
}
}
@@ -194,8 +144,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
secp256k1_scalar_set_int(&ng, j);
secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng);
- ge_equals_gej(&group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
-
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER]));
}
}
}
@@ -213,7 +162,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
/* Test secp256k1_ecmult_const. */
secp256k1_ecmult_const(&tmp, &group[i], &ng);
- ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER]));
if (i != 0 && j != 0) {
/* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */
@@ -265,7 +214,7 @@ static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const sec
data.pt[1] = group[y];
secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2);
- ge_equals_gej(&group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER], &tmp);
+ CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER]));
}
}
}
diff --git a/src/secp256k1/src/testutil.h b/src/secp256k1/src/testutil.h
new file mode 100644
index 0000000000..4e2cb7d5b3
--- /dev/null
+++ b/src/secp256k1/src/testutil.h
@@ -0,0 +1,29 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_TESTUTIL_H
+#define SECP256K1_TESTUTIL_H
+
+#include "field.h"
+#include "testrand.h"
+#include "util.h"
+
+static void random_fe(secp256k1_fe *x) {
+ unsigned char bin[32];
+ do {
+ secp256k1_testrand256(bin);
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
+ return;
+ }
+ } while(1);
+}
+
+static void random_fe_non_zero(secp256k1_fe *nz) {
+ do {
+ random_fe(nz);
+ } while (secp256k1_fe_is_zero(nz));
+}
+
+#endif /* SECP256K1_TESTUTIL_H */
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index cf7e5d1af5..187bf1c5e0 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -132,16 +132,11 @@ static const secp256k1_callback default_error_callback = {
} while(0)
#endif
-/* Like assert(), but when VERIFY is defined, and side-effect safe. */
-#if defined(COVERAGE)
-#define VERIFY_CHECK(check)
-#define VERIFY_SETUP(stmt)
-#elif defined(VERIFY)
+/* Like assert(), but when VERIFY is defined. */
+#if defined(VERIFY)
#define VERIFY_CHECK CHECK
-#define VERIFY_SETUP(stmt) do { stmt; } while(0)
#else
-#define VERIFY_CHECK(cond) do { (void)(cond); } while(0)
-#define VERIFY_SETUP(stmt)
+#define VERIFY_CHECK(cond)
#endif
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
diff --git a/src/secp256k1/tools/check-abi.sh b/src/secp256k1/tools/check-abi.sh
new file mode 100755
index 0000000000..8f6119cd8e
--- /dev/null
+++ b/src/secp256k1/tools/check-abi.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+set -eu
+
+default_base_version="$(git describe --match "v*.*.*" --abbrev=0)"
+default_new_version="master"
+
+display_help_and_exit() {
+ echo "Usage: $0 <base_ver> <new_ver>"
+ echo ""
+ echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI"
+ echo " of a new version of libsecp256k1 has changed in a backward-incompatible way."
+ echo ""
+ echo "Options:"
+ echo " base_ver Specify the base version (default: $default_base_version)"
+ echo " new_ver Specify the new version (default: $default_new_version)"
+ echo " -h, --help Display this help message"
+ exit 0
+}
+
+if [ "$#" -eq 0 ]; then
+ base_version="$default_base_version"
+ new_version="$default_new_version"
+elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then
+ display_help_and_exit
+elif [ "$#" -eq 2 ]; then
+ base_version="$1"
+ new_version="$2"
+else
+ echo "Invalid usage. See help:"
+ echo ""
+ display_help_and_exit
+fi
+
+checkout_and_build() {
+ git worktree add -d "$1" "$2"
+ cd "$1"
+ mkdir build && cd build
+ cmake -S .. --preset dev-mode \
+ -DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \
+ -DSECP256K1_BUILD_BENCHMARK=OFF \
+ -DSECP256K1_BUILD_TESTS=OFF \
+ -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \
+ -DSECP256K1_BUILD_CTIME_TESTS=OFF \
+ -DSECP256K1_BUILD_EXAMPLES=OFF
+ cmake --build . -j "$(nproc)"
+ abi-dumper src/libsecp256k1.so -o ABI.dump -lver "$2"
+}
+
+echo "Comparing $base_version (base version) to $new_version (new version)"
+echo
+
+original_dir="$(pwd)"
+
+base_source_dir=$(mktemp -d)
+checkout_and_build "$base_source_dir" "$base_version"
+
+new_source_dir=$(mktemp -d)
+checkout_and_build "$new_source_dir" "$new_version"
+
+cd "$original_dir"
+abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump"
+git worktree remove "$base_source_dir"
+git worktree remove "$new_source_dir"
diff --git a/src/serialize.h b/src/serialize.h
index 263b781f21..19585c630a 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -271,10 +271,9 @@ template<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_wri
template<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); }
template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); }
template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }
-template<typename Stream, int N> inline void Serialize(Stream& s, const char (&a)[N]) { s.write(MakeByteSpan(a)); }
-template<typename Stream, int N> inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(MakeByteSpan(a)); }
-template <typename Stream, typename B, std::size_t N> void Serialize(Stream& s, const std::array<B, N>& a) { (void)/* force byte-type */UCharCast(a.data()); s.write(MakeByteSpan(a)); }
-template <typename Stream, typename B> void Serialize(Stream& s, Span<B> span) { (void)/* force byte-type */UCharCast(span.data()); s.write(AsBytes(span)); }
+template <typename Stream, BasicByte B, int N> void Serialize(Stream& s, const B (&a)[N]) { s.write(MakeByteSpan(a)); }
+template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, const std::array<B, N>& a) { s.write(MakeByteSpan(a)); }
+template <typename Stream, BasicByte B> void Serialize(Stream& s, Span<B> span) { s.write(AsBytes(span)); }
#ifndef CHAR_EQUALS_INT8
template <typename Stream> void Unserialize(Stream&, char) = delete; // char serialization forbidden. Use uint8_t or int8_t
@@ -288,10 +287,9 @@ template<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a =
template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); }
template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); }
template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }
-template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
-template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
-template <typename Stream, typename B, std::size_t N> void Unserialize(Stream& s, std::array<B, N>& a) { (void)/* force byte-type */UCharCast(a.data()); s.read(MakeWritableByteSpan(a)); }
-template <typename Stream, typename B> void Unserialize(Stream& s, Span<B> span) { (void)/* force byte-type */UCharCast(span.data()); s.read(AsWritableBytes(span)); }
+template <typename Stream, BasicByte B, int N> void Unserialize(Stream& s, B (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
+template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::array<B, N>& a) { s.read(MakeWritableByteSpan(a)); }
+template <typename Stream, BasicByte B> void Unserialize(Stream& s, Span<B> span) { s.read(AsWritableBytes(span)); }
template <typename Stream> inline void Serialize(Stream& s, bool a) { uint8_t f = a; ser_writedata8(s, f); }
template <typename Stream> inline void Unserialize(Stream& s, bool& a) { uint8_t f = ser_readdata8(s); a = f; }
@@ -755,18 +753,23 @@ template<typename Stream, typename T> void Serialize(Stream& os, const std::uniq
template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);
-
/**
* If none of the specialized versions above matched, default to calling member function.
*/
-template<typename Stream, typename T>
-inline void Serialize(Stream& os, const T& a)
+template <class T, class Stream>
+concept Serializable = requires(T a, Stream s) { a.Serialize(s); };
+template <typename Stream, typename T>
+ requires Serializable<T, Stream>
+void Serialize(Stream& os, const T& a)
{
a.Serialize(os);
}
-template<typename Stream, typename T>
-inline void Unserialize(Stream& is, T&& a)
+template <class T, class Stream>
+concept Unserializable = requires(T a, Stream s) { a.Unserialize(s); };
+template <typename Stream, typename T>
+ requires Unserializable<T, Stream>
+void Unserialize(Stream& is, T&& a)
{
a.Unserialize(is);
}
diff --git a/src/shutdown.cpp b/src/shutdown.cpp
deleted file mode 100644
index fc18ccd207..0000000000
--- a/src/shutdown.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2022 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 <shutdown.h>
-
-#include <kernel/context.h>
-#include <logging.h>
-#include <util/check.h>
-#include <util/signalinterrupt.h>
-
-#include <assert.h>
-#include <system_error>
-
-void StartShutdown()
-{
- try {
- Assert(kernel::g_context)->interrupt();
- } catch (const std::system_error&) {
- LogPrintf("Sending shutdown token failed\n");
- assert(0);
- }
-}
-
-void AbortShutdown()
-{
- Assert(kernel::g_context)->interrupt.reset();
-}
-
-bool ShutdownRequested()
-{
- return bool{Assert(kernel::g_context)->interrupt};
-}
-
-void WaitForShutdown()
-{
- try {
- Assert(kernel::g_context)->interrupt.wait();
- } catch (const std::system_error&) {
- LogPrintf("Reading shutdown token failed\n");
- assert(0);
- }
-}
diff --git a/src/shutdown.h b/src/shutdown.h
deleted file mode 100644
index 2d6ace8d93..0000000000
--- a/src/shutdown.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_SHUTDOWN_H
-#define BITCOIN_SHUTDOWN_H
-
-/** Request shutdown of the application. */
-void StartShutdown();
-
-/** Clear shutdown flag. Only use this during init (before calling WaitForShutdown in any
- * thread), or in the unit tests. Calling it in other circumstances will cause a race condition.
- */
-void AbortShutdown();
-
-/** Returns true if a shutdown is requested, false otherwise. */
-bool ShutdownRequested();
-
-/** Wait for StartShutdown to be called in any thread. This can only be used
- * from a single thread.
- */
-void WaitForShutdown();
-
-#endif // BITCOIN_SHUTDOWN_H
diff --git a/src/span.h b/src/span.h
index 2e8da27cde..2c27a54fc7 100644
--- a/src/span.h
+++ b/src/span.h
@@ -8,6 +8,7 @@
#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <span>
#include <type_traits>
#ifdef DEBUG
@@ -283,13 +284,16 @@ Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
return AsWritableBytes(Span{std::forward<V>(v)});
}
-// Helper functions to safely cast to unsigned char pointers.
+// Helper functions to safely cast basic byte pointers to unsigned char pointers.
inline unsigned char* UCharCast(char* c) { return reinterpret_cast<unsigned char*>(c); }
inline unsigned char* UCharCast(unsigned char* c) { return c; }
inline unsigned char* UCharCast(std::byte* c) { return reinterpret_cast<unsigned char*>(c); }
inline const unsigned char* UCharCast(const char* c) { return reinterpret_cast<const unsigned char*>(c); }
inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }
+// Helper concept for the basic byte types.
+template <typename B>
+concept BasicByte = requires { UCharCast(std::span<B>{}.data()); };
// Helper function to safely convert a Span to a Span<[const] unsigned char>.
template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index 3815a5bba6..e5ab1cfb90 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -85,6 +85,32 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34));
// Maximum size in bytes, should not crash
CFeeRate(MAX_MONEY, std::numeric_limits<uint32_t>::max()).GetFeePerK();
+
+ // check multiplication operator
+ // check multiplying by zero
+ feeRate = CFeeRate(1000);
+ BOOST_CHECK(0 * feeRate == CFeeRate(0));
+ BOOST_CHECK(feeRate * 0 == CFeeRate(0));
+ // check multiplying by a positive integer
+ BOOST_CHECK(3 * feeRate == CFeeRate(3000));
+ BOOST_CHECK(feeRate * 3 == CFeeRate(3000));
+ // check multiplying by a negative integer
+ BOOST_CHECK(-3 * feeRate == CFeeRate(-3000));
+ BOOST_CHECK(feeRate * -3 == CFeeRate(-3000));
+ // check commutativity
+ BOOST_CHECK(2 * feeRate == feeRate * 2);
+ // check with large numbers
+ int largeNumber = 1000000;
+ BOOST_CHECK(largeNumber * feeRate == feeRate * largeNumber);
+ // check boundary values
+ int maxInt = std::numeric_limits<int>::max();
+ feeRate = CFeeRate(maxInt);
+ BOOST_CHECK(feeRate * 2 == CFeeRate(static_cast<int64_t>(maxInt) * 2));
+ BOOST_CHECK(2 * feeRate == CFeeRate(static_cast<int64_t>(maxInt) * 2));
+ // check with zero fee rate
+ feeRate = CFeeRate(0);
+ BOOST_CHECK(feeRate * 5 == CFeeRate(0));
+ BOOST_CHECK(5 * feeRate == CFeeRate(0));
}
BOOST_AUTO_TEST_CASE(BinaryOperatorTest)
diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp
index b590467a43..be515a9eac 100644
--- a/src/test/blockchain_tests.cpp
+++ b/src/test/blockchain_tests.cpp
@@ -41,7 +41,7 @@ static void RejectDifficultyMismatch(double difficulty, double expected_difficul
static void TestDifficulty(uint32_t nbits, double expected_difficulty)
{
CBlockIndex* block_index = CreateBlockIndexWithNbits(nbits);
- double difficulty = GetDifficulty(block_index);
+ double difficulty = GetDifficulty(*block_index);
delete block_index;
RejectDifficultyMismatch(difficulty, expected_difficulty);
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 97ea5cfbf3..d44d84af93 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -143,7 +143,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
BOOST_REQUIRE(filter_index.StartBackgroundSync());
// Allow filter index to catch up with the block index.
- IndexWaitSynced(filter_index);
+ IndexWaitSynced(filter_index, *Assert(m_node.shutdown));
// Check that filter index has all blocks that were in the chain before it started.
{
@@ -162,9 +162,8 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
LOCK(cs_main);
tip = m_node.chainman->ActiveChain().Tip();
}
- CKey coinbase_key_A, coinbase_key_B;
- coinbase_key_A.MakeNewKey(true);
- coinbase_key_B.MakeNewKey(true);
+ CKey coinbase_key_A = GenerateRandomKey();
+ CKey coinbase_key_B = GenerateRandomKey();
CScript coinbase_script_pub_key_A = GetScriptForDestination(PKHash(coinbase_key_A.GetPubKey()));
CScript coinbase_script_pub_key_B = GetScriptForDestination(PKHash(coinbase_key_B.GetPubKey()));
std::vector<std::shared_ptr<CBlock>> chainA, chainB;
diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp
index e1b31c20f4..d7ac0bf823 100644
--- a/src/test/blockmanager_tests.cpp
+++ b/src/test/blockmanager_tests.cpp
@@ -27,13 +27,13 @@ BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
{
const auto params {CreateChainParams(ArgsManager{}, ChainType::MAIN)};
- KernelNotifications notifications{m_node.exit_status};
+ KernelNotifications notifications{*Assert(m_node.shutdown), m_node.exit_status};
const BlockManager::Options blockman_opts{
.chainparams = *params,
.blocks_dir = m_args.GetBlocksDirPath(),
.notifications = notifications,
};
- BlockManager blockman{m_node.kernel->interrupt, blockman_opts};
+ BlockManager blockman{*Assert(m_node.shutdown), blockman_opts};
// simulate adding a genesis block normally
BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
// simulate what happens during reindex
@@ -134,13 +134,13 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_block_data_availability, TestChain100Setup)
BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
{
- KernelNotifications notifications{m_node.exit_status};
+ KernelNotifications notifications{*Assert(m_node.shutdown), m_node.exit_status};
node::BlockManager::Options blockman_opts{
.chainparams = Params(),
.blocks_dir = m_args.GetBlocksDirPath(),
.notifications = notifications,
};
- BlockManager blockman{m_node.kernel->interrupt, blockman_opts};
+ BlockManager blockman{*Assert(m_node.shutdown), blockman_opts};
// Test blocks with no transactions, not even a coinbase
CBlock block1;
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index 50f3f7d833..cc1ec49d41 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
BOOST_REQUIRE(coin_stats_index.StartBackgroundSync());
- IndexWaitSynced(coin_stats_index);
+ IndexWaitSynced(coin_stats_index, *Assert(m_node.shutdown));
// Check that CoinStatsIndex works for genesis block.
const CBlockIndex* genesis_block_index;
@@ -86,7 +86,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
BOOST_REQUIRE(index.Init());
BOOST_REQUIRE(index.StartBackgroundSync());
- IndexWaitSynced(index);
+ IndexWaitSynced(index, *Assert(m_node.shutdown));
std::shared_ptr<const CBlock> new_block;
CBlockIndex* new_block_index = nullptr;
{
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index b56629ae40..264b47b07c 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -65,8 +65,7 @@ BOOST_AUTO_TEST_CASE(compress_amounts)
BOOST_AUTO_TEST_CASE(compress_script_to_ckey_id)
{
// case CKeyID
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
CPubKey pubkey = key.GetPubKey();
CScript script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
@@ -101,8 +100,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_cscript_id)
BOOST_AUTO_TEST_CASE(compress_script_to_compressed_pubkey_id)
{
- CKey key;
- key.MakeNewKey(true); // case compressed PubKeyID
+ CKey key = GenerateRandomKey(); // case compressed PubKeyID
CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // COMPRESSED_PUBLIC_KEY_SIZE (33)
BOOST_CHECK_EQUAL(script.size(), 35U);
@@ -119,8 +117,7 @@ BOOST_AUTO_TEST_CASE(compress_script_to_compressed_pubkey_id)
BOOST_AUTO_TEST_CASE(compress_script_to_uncompressed_pubkey_id)
{
- CKey key;
- key.MakeNewKey(false); // case uncompressed PubKeyID
+ CKey key = GenerateRandomKey(/*compressed=*/false); // case uncompressed PubKeyID
CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // PUBLIC_KEY_SIZE (65)
BOOST_CHECK_EQUAL(script.size(), 67U); // 1 char code + 65 char pubkey + OP_CHECKSIG
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index f4f4e39f40..c779bf6f73 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -592,9 +592,9 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
CheckUnparsable("raw(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh or tr.");
CheckUnparsable("", "tr(034D2224bbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb40,{{{{{{{{{{{{{{{{{{{{{{multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008')", "'multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008'' is not a valid descriptor function");
// No uncompressed keys allowed
- CheckUnparsable("", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(049228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4))),after(10)))", "A function is needed within P2WSH");
+ CheckUnparsable("", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(049228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4))),after(10)))", "Uncompressed keys are not allowed");
// No hybrid keys allowed
- CheckUnparsable("", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(069228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4))),after(10)))", "A function is needed within P2WSH");
+ CheckUnparsable("", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(069228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4))),after(10)))", "Hybrid public keys are not allowed");
// Insane at top level
CheckUnparsable("wsh(and_b(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "wsh(and_b(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "and_b(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)) is invalid");
// Invalid sub
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 7cfecb2b22..c237963af3 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -5,7 +5,6 @@
#include <test/util/setup_common.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
-#include <util/getuniquepath.h>
#include <boost/test/unit_test.hpp>
@@ -18,9 +17,12 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_pathtostring)
{
std::string u8_str = "fs_tests_₿_🏃";
+ std::u8string str8{u8"fs_tests_₿_🏃"};
BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(u8_str)), u8_str);
- BOOST_CHECK_EQUAL(fs::u8path(u8_str).u8string(), u8_str);
- BOOST_CHECK_EQUAL(fs::PathFromString(u8_str).u8string(), u8_str);
+ BOOST_CHECK_EQUAL(fs::u8path(u8_str).utf8string(), u8_str);
+ BOOST_CHECK_EQUAL(fs::path(str8).utf8string(), u8_str);
+ BOOST_CHECK(fs::path(str8).u8string() == str8);
+ BOOST_CHECK_EQUAL(fs::PathFromString(u8_str).utf8string(), u8_str);
BOOST_CHECK_EQUAL(fs::PathToString(fs::u8path(u8_str)), u8_str);
#ifndef WIN32
// On non-windows systems, verify that arbitrary byte strings containing
@@ -47,7 +49,7 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
fs::path tmpfolder = m_args.GetDataDirBase();
// tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / fs::u8path("fs_tests_₿_🏃");
- fs::path tmpfile2 = tmpfolder / fs::u8path("fs_tests_₿_🏃");
+ fs::path tmpfile2 = tmpfolder / fs::path(u8"fs_tests_₿_🏃");
{
std::ofstream file{tmpfile1};
file << "bitcoin";
@@ -101,29 +103,14 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, ""));
BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, {}));
}
- {
- fs::path p1 = GetUniquePath(tmpfolder);
- fs::path p2 = GetUniquePath(tmpfolder);
- fs::path p3 = GetUniquePath(tmpfolder);
-
- // Ensure that the parent path is always the same.
- BOOST_CHECK_EQUAL(tmpfolder, p1.parent_path());
- BOOST_CHECK_EQUAL(tmpfolder, p2.parent_path());
- BOOST_CHECK_EQUAL(tmpfolder, p3.parent_path());
-
- // Ensure that generated paths are actually different.
- BOOST_CHECK(p1 != p2);
- BOOST_CHECK(p2 != p3);
- BOOST_CHECK(p1 != p3);
- }
}
BOOST_AUTO_TEST_CASE(rename)
{
const fs::path tmpfolder{m_args.GetDataDirBase()};
- const fs::path path1{GetUniquePath(tmpfolder)};
- const fs::path path2{GetUniquePath(tmpfolder)};
+ const fs::path path1{tmpfolder / "a"};
+ const fs::path path2{tmpfolder / "b"};
const std::string path1_contents{"1111"};
const std::string path2_contents{"2222"};
@@ -158,13 +145,13 @@ BOOST_AUTO_TEST_CASE(create_directories)
// Test fs::create_directories workaround.
const fs::path tmpfolder{m_args.GetDataDirBase()};
- const fs::path dir{GetUniquePath(tmpfolder)};
+ const fs::path dir{tmpfolder / "a"};
fs::create_directory(dir);
BOOST_CHECK(fs::exists(dir));
BOOST_CHECK(fs::is_directory(dir));
BOOST_CHECK(!fs::create_directories(dir));
- const fs::path symlink{GetUniquePath(tmpfolder)};
+ const fs::path symlink{tmpfolder / "b"};
fs::create_directory_symlink(dir, symlink);
BOOST_CHECK(fs::exists(symlink));
BOOST_CHECK(fs::is_symlink(symlink));
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index 5474b38204..6ea315d4e2 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -67,6 +67,11 @@ void initialize_mocked_descriptor_parse()
FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
{
+ // Key derivation is expensive. Deriving deep derivation paths take a lot of compute and we'd
+ // rather spend time elsewhere in this target, like on the actual descriptor syntax. So rule
+ // out strings which could correspond to a descriptor containing a too large derivation path.
+ if (HasDeepDerivPath(buffer)) return;
+
const std::string mocked_descriptor{buffer.begin(), buffer.end()};
if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) {
FlatSigningProvider signing_provider;
@@ -78,6 +83,9 @@ FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse)
{
+ // See comment above for rationale.
+ if (HasDeepDerivPath(buffer)) return;
+
const std::string descriptor(buffer.begin(), buffer.end());
FlatSigningProvider signing_provider;
std::string error;
diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp
index 9928c4a1ab..f13f1c72a5 100644
--- a/src/test/fuzz/http_request.cpp
+++ b/src/test/fuzz/http_request.cpp
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <event2/buffer.h>
@@ -47,7 +48,8 @@ FUZZ_TARGET(http_request)
return;
}
- HTTPRequest http_request{evreq, true};
+ util::SignalInterrupt interrupt;
+ HTTPRequest http_request{evreq, interrupt, true};
const HTTPRequest::RequestMethod request_method = http_request.GetRequestMethod();
(void)RequestMethodString(request_method);
(void)http_request.GetURI();
diff --git a/src/test/fuzz/minisketch.cpp b/src/test/fuzz/minisketch.cpp
index a17be73f6c..698cb15fc9 100644
--- a/src/test/fuzz/minisketch.cpp
+++ b/src/test/fuzz/minisketch.cpp
@@ -12,14 +12,27 @@
#include <map>
#include <numeric>
-using node::MakeMinisketch32;
+namespace {
+
+Minisketch MakeFuzzMinisketch32(size_t capacity, uint32_t impl)
+{
+ return Assert(Minisketch(32, impl, capacity));
+}
+
+} // namespace
FUZZ_TARGET(minisketch)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
const auto capacity{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 200)};
- Minisketch sketch_a{Assert(MakeMinisketch32(capacity))};
- Minisketch sketch_b{Assert(MakeMinisketch32(capacity))};
+ const uint32_t impl{fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, Minisketch::MaxImplementation())};
+ if (!Minisketch::ImplementationSupported(32, impl)) return;
+
+ Minisketch sketch_a{MakeFuzzMinisketch32(capacity, impl)};
+ Minisketch sketch_b{MakeFuzzMinisketch32(capacity, impl)};
+ sketch_a.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ sketch_b.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
// Fill two sets and keep the difference in a map
std::map<uint32_t, bool> diff;
@@ -47,8 +60,11 @@ FUZZ_TARGET(minisketch)
}
const auto num_diff{std::accumulate(diff.begin(), diff.end(), size_t{0}, [](auto n, const auto& e) { return n + e.second; })};
- Minisketch sketch_ar{MakeMinisketch32(capacity)};
- Minisketch sketch_br{MakeMinisketch32(capacity)};
+ Minisketch sketch_ar{MakeFuzzMinisketch32(capacity, impl)};
+ Minisketch sketch_br{MakeFuzzMinisketch32(capacity, impl)};
+ sketch_ar.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ sketch_br.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+
sketch_ar.Deserialize(sketch_a.Serialize());
sketch_br.Deserialize(sketch_b.Serialize());
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 40a1fc80f0..a4e1947b9f 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -45,12 +45,14 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
}
const CTransaction tx{*mtx};
const CTxMemPoolEntry& entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, tx);
+ const auto tx_submitted_in_package = fuzzed_data_provider.ConsumeBool();
+ const auto tx_has_mempool_parents = fuzzed_data_provider.ConsumeBool();
const auto tx_info = NewMempoolTransactionInfo(entry.GetSharedTx(), entry.GetFee(),
entry.GetTxSize(), entry.GetHeight(),
- /* m_from_disconnected_block */ false,
- /* m_submitted_in_package */ false,
- /* m_chainstate_is_current */ true,
- /* m_has_no_mempool_parents */ fuzzed_data_provider.ConsumeBool());
+ /*mempool_limit_bypassed=*/false,
+ tx_submitted_in_package,
+ /*chainstate_is_current=*/true,
+ tx_has_mempool_parents);
block_policy_estimator.processTransaction(tx_info);
if (fuzzed_data_provider.ConsumeBool()) {
(void)block_policy_estimator.removeTx(tx.GetHash());
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index acb03ac5fc..56b391ed5c 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2022 The Bitcoin Core developers
+// Copyright (c) 2020-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,9 +8,6 @@
#include <primitives/transaction.h>
#include <protocol.h>
#include <script/script.h>
-#include <serialize.h>
-#include <span.h>
-#include <streams.h>
#include <sync.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -20,13 +17,10 @@
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
-#include <util/chaintype.h>
#include <util/check.h>
#include <util/time.h>
-#include <validation.h>
#include <validationinterface.h>
-#include <atomic>
#include <cstdlib>
#include <iostream>
#include <memory>
@@ -81,8 +75,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message)
CSerializedNetMsg net_msg;
net_msg.m_type = random_message_type;
- // fuzzed_data_provider is fully consumed after this call, don't use it
- net_msg.data = fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>();
+ net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider, MAX_PROTOCOL_MESSAGE_LENGTH);
connman.FlushSendBuffer(p2p_node);
(void)connman.ReceiveMsgFrom(p2p_node, std::move(net_msg));
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 3f722f60ee..6b264907b5 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -16,7 +16,6 @@
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
-#include <util/chaintype.h>
#include <util/time.h>
#include <validationinterface.h>
@@ -72,7 +71,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages)
CSerializedNetMsg net_msg;
net_msg.m_type = random_message_type;
- net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider, MAX_PROTOCOL_MESSAGE_LENGTH);
CNode& random_node = *PickValue(fuzzed_data_provider, peers);
diff --git a/src/test/fuzz/util/descriptor.cpp b/src/test/fuzz/util/descriptor.cpp
index 5bfd2721ce..df78bdf314 100644
--- a/src/test/fuzz/util/descriptor.cpp
+++ b/src/test/fuzz/util/descriptor.cpp
@@ -70,3 +70,17 @@ std::optional<std::string> MockedDescriptorConverter::GetDescriptor(std::string_
return desc;
}
+
+bool HasDeepDerivPath(const FuzzBufferType& buff, const int max_depth)
+{
+ auto depth{0};
+ for (const auto& ch: buff) {
+ if (ch == ',') {
+ // A comma is always present between two key expressions, so we use that as a delimiter.
+ depth = 0;
+ } else if (ch == '/') {
+ if (++depth > max_depth) return true;
+ }
+ }
+ return false;
+}
diff --git a/src/test/fuzz/util/descriptor.h b/src/test/fuzz/util/descriptor.h
index 6289b91b07..cd41dbafa3 100644
--- a/src/test/fuzz/util/descriptor.h
+++ b/src/test/fuzz/util/descriptor.h
@@ -8,6 +8,7 @@
#include <key_io.h>
#include <util/strencodings.h>
#include <script/descriptor.h>
+#include <test/fuzz/fuzz.h>
#include <functional>
@@ -45,4 +46,13 @@ public:
std::optional<std::string> GetDescriptor(std::string_view mocked_desc) const;
};
+//! Default maximum number of derivation indexes in a single derivation path when limiting its depth.
+constexpr int MAX_DEPTH{2};
+
+/**
+ * Whether the buffer, if it represents a valid descriptor, contains a derivation path deeper than
+ * a given maximum depth. Note this may also be hit for deriv paths in origins.
+ */
+bool HasDeepDerivPath(const FuzzBufferType& buff, const int max_depth = MAX_DEPTH);
+
#endif // BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 13ec89663a..ede73c6895 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -70,10 +70,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
feeV[j],
virtual_size,
entry.nHeight,
- /* m_from_disconnected_block */ false,
- /* m_submitted_in_package */ false,
- /* m_chainstate_is_current */ true,
- /* m_has_no_mempool_parents */ true)};
+ /*mempool_limit_bypassed=*/false,
+ /*submitted_in_package=*/false,
+ /*chainstate_is_current=*/true,
+ /*has_no_mempool_parents=*/true)};
GetMainSignals().TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
}
uint256 hash = tx.GetHash();
@@ -112,6 +112,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
}
+ // Wait for fee estimator to catch up
+ SyncWithValidationInterfaceQueue();
+
std::vector<CAmount> origFeeEst;
// Highest feerate is 10*baseRate and gets in all blocks,
// second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
@@ -168,10 +171,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
feeV[j],
virtual_size,
entry.nHeight,
- /* m_from_disconnected_block */ false,
- /* m_submitted_in_package */ false,
- /* m_chainstate_is_current */ true,
- /* m_has_no_mempool_parents */ true)};
+ /*mempool_limit_bypassed=*/false,
+ /*submitted_in_package=*/false,
+ /*chainstate_is_current=*/true,
+ /*has_no_mempool_parents=*/true)};
GetMainSignals().TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
}
uint256 hash = tx.GetHash();
@@ -232,10 +235,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
feeV[j],
virtual_size,
entry.nHeight,
- /* m_from_disconnected_block */ false,
- /* m_submitted_in_package */ false,
- /* m_chainstate_is_current */ true,
- /* m_has_no_mempool_parents */ true)};
+ /*mempool_limit_bypassed=*/false,
+ /*submitted_in_package=*/false,
+ /*chainstate_is_current=*/true,
+ /*has_no_mempool_parents=*/true)};
GetMainSignals().TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
}
uint256 hash = tx.GetHash();
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index 739ab75de3..54dcc218b9 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -18,9 +18,15 @@
#include <boost/test/unit_test.hpp>
// Helpers:
+static bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason)
+{
+ return IsStandardTx(tx, std::nullopt, permit_bare_multisig, CFeeRate{DUST_RELAY_TX_FEE}, reason);
+}
+
static bool IsStandardTx(const CTransaction& tx, std::string& reason)
{
- return IsStandardTx(tx, std::nullopt, DEFAULT_PERMIT_BAREMULTISIG, CFeeRate{DUST_RELAY_TX_FEE}, reason);
+ return IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/true, CFeeRate{DUST_RELAY_TX_FEE}, reason) &&
+ IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason);
}
static std::vector<unsigned char> Serialize(const CScript& s)
@@ -201,7 +207,9 @@ BOOST_AUTO_TEST_CASE(set)
{
SignatureData empty;
BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
- BOOST_CHECK_MESSAGE(IsStandardTx(CTransaction(txTo[i]), reason), strprintf("txTo[%d].IsStandard", i));
+ BOOST_CHECK_MESSAGE(IsStandardTx(CTransaction(txTo[i]), /*permit_bare_multisig=*/true, reason), strprintf("txTo[%d].IsStandard", i));
+ bool no_pbms_is_std = IsStandardTx(CTransaction(txTo[i]), /*permit_bare_multisig=*/false, reason);
+ BOOST_CHECK_MESSAGE((i == 0 ? no_pbms_is_std : !no_pbms_is_std), strprintf("txTo[%d].IsStandard(permbaremulti=false)", i));
}
}
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 58bdb37b7c..29e2d4a569 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -136,10 +136,8 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
{
- CKey key;
- CPubKey pubkey;
- key.MakeNewKey(true);
- pubkey = key.GetPubKey();
+ CKey key = GenerateRandomKey();
+ CPubKey pubkey = key.GetPubKey();
CScript s;
std::vector<std::vector<unsigned char> > solutions;
@@ -192,10 +190,8 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
{
- CKey key;
- CPubKey pubkey;
- key.MakeNewKey(true);
- pubkey = key.GetPubKey();
+ CKey key = GenerateRandomKey();
+ CPubKey pubkey = key.GetPubKey();
CScript s;
CTxDestination address;
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index e988ce2194..1f674408b2 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1051,10 +1051,9 @@ sign_multisig(const CScript& scriptPubKey, const CKey& key, const CTransaction&
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
{
ScriptError err;
- CKey key1, key2, key3;
- key1.MakeNewKey(true);
- key2.MakeNewKey(false);
- key3.MakeNewKey(true);
+ CKey key1 = GenerateRandomKey();
+ CKey key2 = GenerateRandomKey(/*compressed=*/false);
+ CKey key3 = GenerateRandomKey();
CScript scriptPubKey12;
scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
@@ -1081,11 +1080,10 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
{
ScriptError err;
- CKey key1, key2, key3, key4;
- key1.MakeNewKey(true);
- key2.MakeNewKey(false);
- key3.MakeNewKey(true);
- key4.MakeNewKey(false);
+ CKey key1 = GenerateRandomKey();
+ CKey key2 = GenerateRandomKey(/*compressed=*/false);
+ CKey key3 = GenerateRandomKey();
+ CKey key4 = GenerateRandomKey(/*compressed=*/false);
CScript scriptPubKey23;
scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
@@ -1165,8 +1163,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
std::vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++)
{
- CKey key;
- key.MakeNewKey(i%2 == 1);
+ CKey key = GenerateRandomKey(/*compressed=*/i%2 == 1);
keys.push_back(key);
pubkeys.push_back(key.GetPubKey());
BOOST_CHECK(keystore.AddKey(key));
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index c0bed50e1d..2081acdf4d 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -50,8 +50,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
std::vector<CPubKey> keys;
for (int i = 0; i < 3; i++)
{
- CKey k;
- k.MakeNewKey(true);
+ CKey k = GenerateRandomKey();
keys.push_back(k.GetPubKey());
}
CScript s2 = GetScriptForMultisig(1, keys);
@@ -120,8 +119,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
// Create key
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
CPubKey pubkey = key.GetPubKey();
// Default flags
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 5329c6ac99..d1cb2531aa 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -487,8 +487,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
CMutableTransaction mtx;
mtx.nVersion = 1;
- CKey key;
- key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
+ CKey key = GenerateRandomKey(); // Need to use compressed keys in segwit or the signing will fail
FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKeyPubKey(key, key.GetPubKey()));
CKeyID hash = key.GetPubKey().GetID();
@@ -564,18 +563,16 @@ SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutabl
BOOST_AUTO_TEST_CASE(test_witness)
{
FillableSigningProvider keystore, keystore2;
- CKey key1, key2, key3, key1L, key2L;
- CPubKey pubkey1, pubkey2, pubkey3, pubkey1L, pubkey2L;
- key1.MakeNewKey(true);
- key2.MakeNewKey(true);
- key3.MakeNewKey(true);
- key1L.MakeNewKey(false);
- key2L.MakeNewKey(false);
- pubkey1 = key1.GetPubKey();
- pubkey2 = key2.GetPubKey();
- pubkey3 = key3.GetPubKey();
- pubkey1L = key1L.GetPubKey();
- pubkey2L = key2L.GetPubKey();
+ CKey key1 = GenerateRandomKey();
+ CKey key2 = GenerateRandomKey();
+ CKey key3 = GenerateRandomKey();
+ CKey key1L = GenerateRandomKey(/*compressed=*/false);
+ CKey key2L = GenerateRandomKey(/*compressed=*/false);
+ CPubKey pubkey1 = key1.GetPubKey();
+ CPubKey pubkey2 = key2.GetPubKey();
+ CPubKey pubkey3 = key3.GetPubKey();
+ CPubKey pubkey1L = key1L.GetPubKey();
+ CPubKey pubkey2L = key2L.GetPubKey();
BOOST_CHECK(keystore.AddKeyPubKey(key1, pubkey1));
BOOST_CHECK(keystore.AddKeyPubKey(key2, pubkey2));
BOOST_CHECK(keystore.AddKeyPubKey(key1L, pubkey1L));
@@ -756,8 +753,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
t.vout.resize(1);
t.vout[0].nValue = 90*CENT;
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
constexpr auto CheckIsStandard = [](const auto& t) {
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 9fa59bab57..e2432a4718 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -33,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
BOOST_REQUIRE(txindex.StartBackgroundSync());
// Allow tx index to catch up with the block index.
- IndexWaitSynced(txindex);
+ IndexWaitSynced(txindex, *Assert(m_node.shutdown));
// Check that txindex excludes genesis block transactions.
const CBlock& genesis_block = Params().GenesisBlock();
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index 637f92bd0f..f6456526bb 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -116,8 +116,7 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
unsigned int initialPoolSize = m_node.mempool->size();
// Parent and Child Package
- CKey parent_key;
- parent_key.MakeNewKey(true);
+ CKey parent_key = GenerateRandomKey();
CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
@@ -125,8 +124,7 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
/*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
- CKey child_key;
- child_key.MakeNewKey(true);
+ CKey child_key = GenerateRandomKey();
CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
/*input_height=*/101, /*input_signing_key=*/parent_key,
@@ -170,11 +168,9 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
{
// The signatures won't be verified so we can just use a placeholder
- CKey placeholder_key;
- placeholder_key.MakeNewKey(true);
+ CKey placeholder_key = GenerateRandomKey();
CScript spk = GetScriptForDestination(PKHash(placeholder_key.GetPubKey()));
- CKey placeholder_key_2;
- placeholder_key_2.MakeNewKey(true);
+ CKey placeholder_key_2 = GenerateRandomKey();
CScript spk2 = GetScriptForDestination(PKHash(placeholder_key_2.GetPubKey()));
// Parent and Child Package
@@ -266,8 +262,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
{
LOCK(cs_main);
unsigned int expected_pool_size = m_node.mempool->size();
- CKey parent_key;
- parent_key.MakeNewKey(true);
+ CKey parent_key = GenerateRandomKey();
CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
// Unrelated transactions are not allowed in package submission.
@@ -298,8 +293,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
package_parent_child.push_back(tx_parent);
package_3gen.push_back(tx_parent);
- CKey child_key;
- child_key.MakeNewKey(true);
+ CKey child_key = GenerateRandomKey();
CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
/*input_height=*/101, /*input_signing_key=*/parent_key,
@@ -309,8 +303,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
package_parent_child.push_back(tx_child);
package_3gen.push_back(tx_child);
- CKey grandchild_key;
- grandchild_key.MakeNewKey(true);
+ CKey grandchild_key = GenerateRandomKey();
CScript grandchild_locking_script = GetScriptForDestination(PKHash(grandchild_key.GetPubKey()));
auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/tx_child, /*input_vout=*/0,
/*input_height=*/101, /*input_signing_key=*/child_key,
@@ -434,8 +427,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
witness2.stack.emplace_back(2);
witness2.stack.emplace_back(witnessScript.begin(), witnessScript.end());
- CKey child_key;
- child_key.MakeNewKey(true);
+ CKey child_key = GenerateRandomKey();
CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
CMutableTransaction mtx_child1;
mtx_child1.nVersion = 1;
@@ -504,8 +496,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
// This tests a potential censorship vector in which an attacker broadcasts a competing package
// where a parent's witness is mutated. The honest package should be accepted despite the fact
// that we don't allow witness replacement.
- CKey grandchild_key;
- grandchild_key.MakeNewKey(true);
+ CKey grandchild_key = GenerateRandomKey();
CScript grandchild_locking_script = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/ptx_child2, /*input_vout=*/0,
/*input_height=*/0, /*input_signing_key=*/child_key,
@@ -595,8 +586,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*ptx_parent3)) <= low_fee_amt);
// child spends parent1, parent2, and parent3
- CKey mixed_grandchild_key;
- mixed_grandchild_key.MakeNewKey(true);
+ CKey mixed_grandchild_key = GenerateRandomKey();
CScript mixed_child_spk = GetScriptForDestination(WitnessV0KeyHash(mixed_grandchild_key.GetPubKey()));
CMutableTransaction mtx_mixed_child;
@@ -648,11 +638,9 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
MockMempoolMinFee(CFeeRate(5000));
LOCK(::cs_main);
size_t expected_pool_size = m_node.mempool->size();
- CKey child_key;
- child_key.MakeNewKey(true);
+ CKey child_key = GenerateRandomKey();
CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
- CKey grandchild_key;
- grandchild_key.MakeNewKey(true);
+ CKey grandchild_key = GenerateRandomKey();
CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
// low-fee parent and high-fee child package
diff --git a/src/test/util/index.cpp b/src/test/util/index.cpp
index e653d5dbf0..cfeba35756 100644
--- a/src/test/util/index.cpp
+++ b/src/test/util/index.cpp
@@ -5,16 +5,16 @@
#include <test/util/index.h>
#include <index/base.h>
-#include <shutdown.h>
#include <util/check.h>
+#include <util/signalinterrupt.h>
#include <util/time.h>
-void IndexWaitSynced(const BaseIndex& index)
+void IndexWaitSynced(const BaseIndex& index, const util::SignalInterrupt& interrupt)
{
while (!index.BlockUntilSyncedToCurrentChain()) {
// Assert shutdown was not requested to abort the test, instead of looping forever, in case
// there was an unexpected error in the index that caused it to stop syncing and request a shutdown.
- Assert(!ShutdownRequested());
+ Assert(!interrupt);
UninterruptibleSleep(100ms);
}
diff --git a/src/test/util/index.h b/src/test/util/index.h
index 95309f6273..a3bd1dddc3 100644
--- a/src/test/util/index.h
+++ b/src/test/util/index.h
@@ -6,8 +6,11 @@
#define BITCOIN_TEST_UTIL_INDEX_H
class BaseIndex;
+namespace util {
+class SignalInterrupt;
+} // namespace util
/** Block until the index is synced to the current chain */
-void IndexWaitSynced(const BaseIndex& index);
+void IndexWaitSynced(const BaseIndex& index, const util::SignalInterrupt& interrupt);
#endif // BITCOIN_TEST_UTIL_INDEX_H
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index bc639da4dd..8789e86196 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -40,7 +40,6 @@
#include <rpc/server.h>
#include <scheduler.h>
#include <script/sigcache.h>
-#include <shutdown.h>
#include <streams.h>
#include <test/util/net.h>
#include <test/util/random.h>
@@ -102,6 +101,7 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto
: m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()},
m_args{}
{
+ m_node.shutdown = &m_interrupt;
m_node.args = &gArgs;
std::vector<const char*> arguments = Cat(
{
@@ -179,7 +179,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
m_cache_sizes = CalculateCacheSizes(m_args);
- m_node.notifications = std::make_unique<KernelNotifications>(m_node.exit_status);
+ m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status);
const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
@@ -194,7 +194,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
.blocks_dir = m_args.GetBlocksDirPath(),
.notifications = chainman_opts.notifications,
};
- m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
+ m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts);
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{
.path = m_args.GetDataDirNet() / "blocks" / "index",
.cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index c3a4df28bf..9ff4c372a5 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -47,6 +47,7 @@ static constexpr CAmount CENT{1000000};
* This just configures logging, data dir and chain parameters.
*/
struct BasicTestingSetup {
+ util::SignalInterrupt m_interrupt;
node::NodeContext m_node; // keep as first member to be destructed last
explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, const std::vector<const char*>& extra_args = {});
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 4d812544bd..47808a2a58 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -12,7 +12,6 @@
#include <util/bitdeque.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
-#include <util/getuniquepath.h>
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
#include <util/moneystr.h>
#include <util/overflow.h>
@@ -1106,15 +1105,16 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
BOOST_CHECK(!ParseFixedPoint("31.999999999999999999999", 3, &amount));
}
-static void TestOtherThread(fs::path dirname, fs::path lockname, bool *result)
-{
- *result = LockDirectory(dirname, lockname);
-}
-
#ifndef WIN32 // Cannot do this test on WIN32 due to lack of fork()
static constexpr char LockCommand = 'L';
static constexpr char UnlockCommand = 'U';
static constexpr char ExitCommand = 'X';
+enum : char {
+ ResSuccess = 2, // Start with 2 to avoid accidental collision with common values 0 and 1
+ ResErrorWrite,
+ ResErrorLock,
+ ResUnlockSuccess,
+};
[[noreturn]] static void TestOtherProcess(fs::path dirname, fs::path lockname, int fd)
{
@@ -1122,15 +1122,22 @@ static constexpr char ExitCommand = 'X';
while (true) {
int rv = read(fd, &ch, 1); // Wait for command
assert(rv == 1);
- switch(ch) {
+ switch (ch) {
case LockCommand:
- ch = LockDirectory(dirname, lockname);
+ ch = [&] {
+ switch (util::LockDirectory(dirname, lockname)) {
+ case util::LockResult::Success: return ResSuccess;
+ case util::LockResult::ErrorWrite: return ResErrorWrite;
+ case util::LockResult::ErrorLock: return ResErrorLock;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+ }();
rv = write(fd, &ch, 1);
assert(rv == 1);
break;
case UnlockCommand:
ReleaseDirectoryLocks();
- ch = true; // Always succeeds
+ ch = ResUnlockSuccess; // Always succeeds
rv = write(fd, &ch, 1);
assert(rv == 1);
break;
@@ -1165,53 +1172,58 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
TestOtherProcess(dirname, lockname, fd[0]);
}
BOOST_CHECK_EQUAL(close(fd[0]), 0); // Parent: close child end
+
+ char ch;
+ // Lock on non-existent directory should fail
+ BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
+ BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
+ BOOST_CHECK_EQUAL(ch, ResErrorWrite);
#endif
// Lock on non-existent directory should fail
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), false);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::ErrorWrite);
fs::create_directories(dirname);
// Probing lock on new directory should succeed
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
// Persistent lock on new directory should succeed
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::Success);
// Another lock on the directory from the same thread should succeed
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::Success);
// Another lock on the directory from a different thread within the same process should succeed
- bool threadresult;
- std::thread thr(TestOtherThread, dirname, lockname, &threadresult);
+ util::LockResult threadresult;
+ std::thread thr([&] { threadresult = util::LockDirectory(dirname, lockname); });
thr.join();
- BOOST_CHECK_EQUAL(threadresult, true);
+ BOOST_CHECK_EQUAL(threadresult, util::LockResult::Success);
#ifndef WIN32
// Try to acquire lock in child process while we're holding it, this should fail.
- char ch;
BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
- BOOST_CHECK_EQUAL((bool)ch, false);
+ BOOST_CHECK_EQUAL(ch, ResErrorLock);
// Give up our lock
ReleaseDirectoryLocks();
// Probing lock from our side now should succeed, but not hold on to the lock.
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
// Try to acquire the lock in the child process, this should be successful.
BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
- BOOST_CHECK_EQUAL((bool)ch, true);
+ BOOST_CHECK_EQUAL(ch, ResSuccess);
// When we try to probe the lock now, it should fail.
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), false);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::ErrorLock);
// Unlock the lock in the child process
BOOST_CHECK_EQUAL(write(fd[1], &UnlockCommand, 1), 1);
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
- BOOST_CHECK_EQUAL((bool)ch, true);
+ BOOST_CHECK_EQUAL(ch, ResUnlockSuccess);
// When we try to probe the lock now, it should succeed.
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
// Re-lock the lock in the child process, then wait for it to exit, check
// successful return. After that, we check that exiting the process
@@ -1224,7 +1236,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_CHECK_EQUAL(write(fd[1], &ExitCommand, 1), 1);
BOOST_CHECK_EQUAL(waitpid(pid, &processstatus, 0), pid);
BOOST_CHECK_EQUAL(processstatus, 0);
- BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
+ BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
// Restore SIGCHLD
signal(SIGCHLD, old_handler);
@@ -1235,22 +1247,6 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
fs::remove_all(dirname);
}
-BOOST_AUTO_TEST_CASE(test_DirIsWritable)
-{
- // Should be able to write to the data dir.
- fs::path tmpdirname = m_args.GetDataDirBase();
- BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
-
- // Should not be able to write to a non-existent dir.
- tmpdirname = GetUniquePath(tmpdirname);
- BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), false);
-
- fs::create_directory(tmpdirname);
- // Should be able to write to it now.
- BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
- fs::remove(tmpdirname);
-}
-
BOOST_AUTO_TEST_CASE(test_ToLower)
{
BOOST_CHECK_EQUAL(ToLower('@'), '@');
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 6969822ad7..368ba8bee4 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -379,7 +379,7 @@ struct SnapshotTestSetup : TestChain100Setup {
LOCK(::cs_main);
chainman.ResetChainstates();
BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
- m_node.notifications = std::make_unique<KernelNotifications>(m_node.exit_status);
+ m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status);
const ChainstateManager::Options chainman_opts{
.chainparams = ::Params(),
.datadir = chainman.m_options.datadir,
@@ -394,7 +394,7 @@ struct SnapshotTestSetup : TestChain100Setup {
// For robustness, ensure the old manager is destroyed before creating a
// new one.
m_node.chainman.reset();
- m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
+ m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts);
}
return *Assert(m_node.chainman);
}
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index b783181bb8..acee56fe78 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -196,25 +196,20 @@ util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateAncestorsAndCheckLimit
return ancestors;
}
-bool CTxMemPool::CheckPackageLimits(const Package& package,
- const int64_t total_vsize,
- std::string &errString) const
+util::Result<void> CTxMemPool::CheckPackageLimits(const Package& package,
+ const int64_t total_vsize) const
{
size_t pack_count = package.size();
// Package itself is busting mempool limits; should be rejected even if no staged_ancestors exist
if (pack_count > static_cast<uint64_t>(m_limits.ancestor_count)) {
- errString = strprintf("package count %u exceeds ancestor count limit [limit: %u]", pack_count, m_limits.ancestor_count);
- return false;
+ return util::Error{Untranslated(strprintf("package count %u exceeds ancestor count limit [limit: %u]", pack_count, m_limits.ancestor_count))};
} else if (pack_count > static_cast<uint64_t>(m_limits.descendant_count)) {
- errString = strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_count, m_limits.descendant_count);
- return false;
+ return util::Error{Untranslated(strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_count, m_limits.descendant_count))};
} else if (total_vsize > m_limits.ancestor_size_vbytes) {
- errString = strprintf("package size %u exceeds ancestor size limit [limit: %u]", total_vsize, m_limits.ancestor_size_vbytes);
- return false;
+ return util::Error{Untranslated(strprintf("package size %u exceeds ancestor size limit [limit: %u]", total_vsize, m_limits.ancestor_size_vbytes))};
} else if (total_vsize > m_limits.descendant_size_vbytes) {
- errString = strprintf("package size %u exceeds descendant size limit [limit: %u]", total_vsize, m_limits.descendant_size_vbytes);
- return false;
+ return util::Error{Untranslated(strprintf("package size %u exceeds descendant size limit [limit: %u]", total_vsize, m_limits.descendant_size_vbytes))};
}
CTxMemPoolEntry::Parents staged_ancestors;
@@ -224,8 +219,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
if (piter) {
staged_ancestors.insert(**piter);
if (staged_ancestors.size() + package.size() > static_cast<uint64_t>(m_limits.ancestor_count)) {
- errString = strprintf("too many unconfirmed parents [limit: %u]", m_limits.ancestor_count);
- return false;
+ return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", m_limits.ancestor_count))};
}
}
}
@@ -236,8 +230,8 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
const auto ancestors{CalculateAncestorsAndCheckLimits(total_vsize, package.size(),
staged_ancestors, m_limits)};
// It's possible to overestimate the ancestor/descendant totals.
- if (!ancestors.has_value()) errString = "possibly " + util::ErrorString(ancestors).original;
- return ancestors.has_value();
+ if (!ancestors.has_value()) return util::Error{Untranslated("possibly " + util::ErrorString(ancestors).original)};
+ return {};
}
util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateMemPoolAncestors(
diff --git a/src/txmempool.h b/src/txmempool.h
index bac7a445d6..9da51756e6 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -605,11 +605,10 @@ public:
* to mempool. The transactions need not be direct
* ancestors/descendants of each other.
* @param[in] total_vsize Sum of virtual sizes for all transactions in package.
- * @param[out] errString Populated with error reason if a limit is hit.
+ * @returns {} or the error reason if a limit is hit.
*/
- bool CheckPackageLimits(const Package& package,
- int64_t total_vsize,
- std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ util::Result<void> CheckPackageLimits(const Package& package,
+ int64_t total_vsize) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Populate setDescendants with all in-mempool descendants of hash.
* Assumes that setDescendants includes all in-mempool descendants of anything
diff --git a/src/util/fs.cpp b/src/util/fs.cpp
index 14f7a44661..348c1b3383 100644
--- a/src/util/fs.cpp
+++ b/src/util/fs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022 The Bitcoin Core developers
+// Copyright (c) 2017-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,7 @@
#endif
#include <cassert>
+#include <cerrno>
#include <string>
namespace fsbridge {
@@ -130,4 +131,4 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e)
#endif
}
-} // fsbridge
+} // namespace fsbridge
diff --git a/src/util/fs.h b/src/util/fs.h
index 7e2803b6aa..f841e0d76c 100644
--- a/src/util/fs.h
+++ b/src/util/fs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022 The Bitcoin Core developers
+// Copyright (c) 2017-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,6 +14,8 @@
#include <ios>
#include <ostream>
#include <string>
+#include <system_error>
+#include <type_traits>
#include <utility>
/** Filesystem operations and types */
@@ -35,7 +37,7 @@ public:
// Allow path objects arguments for compatibility.
path(std::filesystem::path path) : std::filesystem::path::path(std::move(path)) {}
path& operator=(std::filesystem::path path) { std::filesystem::path::operator=(std::move(path)); return *this; }
- path& operator/=(std::filesystem::path path) { std::filesystem::path::operator/=(path); return *this; }
+ path& operator/=(const std::filesystem::path& path) { std::filesystem::path::operator/=(path); return *this; }
// Allow literal string arguments, which are safe as long as the literals are ASCII.
path(const char* c) : std::filesystem::path(c) {}
@@ -52,12 +54,15 @@ public:
// Disallow std::string conversion method to avoid locale-dependent encoding on windows.
std::string string() const = delete;
- std::string u8string() const
+ /**
+ * Return a UTF-8 representation of the path as a std::string, for
+ * compatibility with code using std::string. For code using the newer
+ * std::u8string type, it is more efficient to call the inherited
+ * std::filesystem::path::u8string method instead.
+ */
+ std::string utf8string() const
{
- const auto& utf8_str{std::filesystem::path::u8string()};
- // utf8_str might either be std::string (C++17) or std::u8string
- // (C++20). Convert both to std::string. This method can be removed
- // after switching to C++20.
+ const std::u8string& utf8_str{std::filesystem::path::u8string()};
return std::string{utf8_str.begin(), utf8_str.end()};
}
@@ -69,11 +74,7 @@ public:
static inline path u8path(const std::string& utf8_str)
{
-#if __cplusplus < 202002L
- return std::filesystem::u8path(utf8_str);
-#else
return std::filesystem::path(std::u8string{utf8_str.begin(), utf8_str.end()});
-#endif
}
// Disallow implicit std::string conversion for absolute to avoid
@@ -97,9 +98,9 @@ static inline auto quoted(const std::string& s)
}
// Allow safe path append operations.
-static inline path operator/(path p1, path p2)
+static inline path operator/(path p1, const path& p2)
{
- p1 /= std::move(p2);
+ p1 /= p2;
return p1;
}
static inline path operator/(path p1, const char* p2)
@@ -140,7 +141,7 @@ static inline bool copy_file(const path& from, const path& to, copy_options opti
* Because \ref PathToString and \ref PathFromString functions don't specify an
* encoding, they are meant to be used internally, not externally. They are not
* appropriate to use in applications requiring UTF-8, where
- * fs::path::u8string() and fs::u8path() methods should be used instead. Other
+ * fs::path::u8string() / fs::path::utf8string() and fs::u8path() methods should be used instead. Other
* applications could require still different encodings. For example, JSON, XML,
* or URI applications might prefer to use higher-level escapes (\uXXXX or
* &XXXX; or %XX) instead of multibyte encoding. Rust, Python, Java applications
@@ -154,13 +155,13 @@ static inline std::string PathToString(const path& path)
// use here, because these methods encode the path using C++'s narrow
// multibyte encoding, which on Windows corresponds to the current "code
// page", which is unpredictable and typically not able to represent all
- // valid paths. So fs::path::u8string() and
+ // valid paths. So fs::path::utf8string() and
// fs::u8path() functions are used instead on Windows. On
- // POSIX, u8string/u8path functions are not safe to use because paths are
+ // POSIX, u8string/utf8string/u8path functions are not safe to use because paths are
// not always valid UTF-8, so plain string methods which do not transform
// the path there are used.
#ifdef WIN32
- return path.u8string();
+ return path.utf8string();
#else
static_assert(std::is_same<path::string_type, std::string>::value, "PathToString not implemented on this platform");
return path.std::filesystem::path::string();
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
index 8aa7493aa8..4de8833a3f 100644
--- a/src/util/fs_helpers.cpp
+++ b/src/util/fs_helpers.cpp
@@ -12,7 +12,6 @@
#include <logging.h>
#include <sync.h>
#include <util/fs.h>
-#include <util/getuniquepath.h>
#include <util/syserror.h>
#include <cerrno>
@@ -51,31 +50,35 @@ static GlobalMutex cs_dir_locks;
* is called.
*/
static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks);
-
-bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only)
+namespace util {
+LockResult LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only)
{
LOCK(cs_dir_locks);
fs::path pathLockFile = directory / lockfile_name;
// If a lock for this directory already exists in the map, don't try to re-lock it
if (dir_locks.count(fs::PathToString(pathLockFile))) {
- return true;
+ return LockResult::Success;
}
// Create empty lock file if it doesn't exist.
- FILE* file = fsbridge::fopen(pathLockFile, "a");
- if (file) fclose(file);
+ if (auto created{fsbridge::fopen(pathLockFile, "a")}) {
+ std::fclose(created);
+ } else {
+ return LockResult::ErrorWrite;
+ }
auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
if (!lock->TryLock()) {
- return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
+ error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
+ return LockResult::ErrorLock;
}
if (!probe_only) {
// Lock successful and we're not just probing, put it into the map
dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
}
- return true;
+ return LockResult::Success;
}
-
+} // namespace util
void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name)
{
LOCK(cs_dir_locks);
@@ -88,19 +91,6 @@ void ReleaseDirectoryLocks()
dir_locks.clear();
}
-bool DirIsWritable(const fs::path& directory)
-{
- fs::path tmpFile = GetUniquePath(directory);
-
- FILE* file = fsbridge::fopen(tmpFile, "a");
- if (!file) return false;
-
- fclose(file);
- remove(tmpFile);
-
- return true;
-}
-
bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)
{
constexpr uint64_t min_disk_space = 52428800; // 50 MiB
diff --git a/src/util/fs_helpers.h b/src/util/fs_helpers.h
index e7db01a89b..ea3778eac3 100644
--- a/src/util/fs_helpers.h
+++ b/src/util/fs_helpers.h
@@ -35,9 +35,15 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length);
*/
[[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
-bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only = false);
+namespace util {
+enum class LockResult {
+ Success,
+ ErrorWrite,
+ ErrorLock,
+};
+[[nodiscard]] LockResult LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only = false);
+} // namespace util
void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name);
-bool DirIsWritable(const fs::path& directory);
bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
/** Get the size of a file by scanning it.
diff --git a/src/util/getuniquepath.cpp b/src/util/getuniquepath.cpp
deleted file mode 100644
index 105b4d52d2..0000000000
--- a/src/util/getuniquepath.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2021-2022 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 <random.h>
-#include <util/fs.h>
-#include <util/strencodings.h>
-
-fs::path GetUniquePath(const fs::path& base)
-{
- FastRandomContext rnd;
- fs::path tmpFile = base / fs::u8path(HexStr(rnd.randbytes(8)));
- return tmpFile;
-} \ No newline at end of file
diff --git a/src/util/getuniquepath.h b/src/util/getuniquepath.h
deleted file mode 100644
index 1563652300..0000000000
--- a/src/util/getuniquepath.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_UTIL_GETUNIQUEPATH_H
-#define BITCOIN_UTIL_GETUNIQUEPATH_H
-
-#include <util/fs.h>
-
-/**
- * Helper function for getting a unique path
- *
- * @param[in] base Base path
- * @returns base joined with a random 8-character long string.
- * @post Returned path is unique with high probability.
- */
-fs::path GetUniquePath(const fs::path& base);
-
-#endif // BITCOIN_UTIL_GETUNIQUEPATH_H \ No newline at end of file
diff --git a/src/util/signalinterrupt.cpp b/src/util/signalinterrupt.cpp
index c551ba8044..f36f3dbf9e 100644
--- a/src/util/signalinterrupt.cpp
+++ b/src/util/signalinterrupt.cpp
@@ -30,15 +30,16 @@ SignalInterrupt::operator bool() const
return m_flag;
}
-void SignalInterrupt::reset()
+bool SignalInterrupt::reset()
{
// Cancel existing interrupt by waiting for it, this will reset condition flags and remove
// the token from the pipe.
- if (*this) wait();
+ if (*this && !wait()) return false;
m_flag = false;
+ return true;
}
-void SignalInterrupt::operator()()
+bool SignalInterrupt::operator()()
{
#ifdef WIN32
std::unique_lock<std::mutex> lk(m_mutex);
@@ -52,13 +53,14 @@ void SignalInterrupt::operator()()
// Write an arbitrary byte to the write end of the pipe.
int res = m_pipe_w.TokenWrite('x');
if (res != 0) {
- throw std::ios_base::failure("Could not write interrupt token");
+ return false;
}
}
#endif
+ return true;
}
-void SignalInterrupt::wait()
+bool SignalInterrupt::wait()
{
#ifdef WIN32
std::unique_lock<std::mutex> lk(m_mutex);
@@ -66,9 +68,10 @@ void SignalInterrupt::wait()
#else
int res = m_pipe_r.TokenRead();
if (res != 'x') {
- throw std::ios_base::failure("Did not read expected interrupt token");
+ return false;
}
#endif
+ return true;
}
} // namespace util
diff --git a/src/util/signalinterrupt.h b/src/util/signalinterrupt.h
index ca02feda91..605d124206 100644
--- a/src/util/signalinterrupt.h
+++ b/src/util/signalinterrupt.h
@@ -30,9 +30,9 @@ class SignalInterrupt
public:
SignalInterrupt();
explicit operator bool() const;
- void operator()();
- void reset();
- void wait();
+ [[nodiscard]] bool operator()();
+ [[nodiscard]] bool reset();
+ [[nodiscard]] bool wait();
private:
std::atomic<bool> m_flag;
diff --git a/src/validation.cpp b/src/validation.cpp
index 0501499004..0f3d5d1454 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -51,6 +51,7 @@
#include <util/hasher.h>
#include <util/moneystr.h>
#include <util/rbf.h>
+#include <util/result.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/time.h>
@@ -1024,10 +1025,10 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
assert(std::all_of(txns.cbegin(), txns.cend(), [this](const auto& tx)
{ return !m_pool.exists(GenTxid::Txid(tx->GetHash()));}));
- std::string err_string;
- if (!m_pool.CheckPackageLimits(txns, total_vsize, err_string)) {
+ auto result = m_pool.CheckPackageLimits(txns, total_vsize);
+ if (!result) {
// This is a package-wide error, separate from an individual transaction error.
- return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", err_string);
+ return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", util::ErrorString(result).original);
}
return true;
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index e1d6869fab..d9292ae2c9 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -150,7 +150,7 @@ protected:
virtual void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex) {}
/**
* Notifies listeners of a block being disconnected
- * Provides the block that was connected.
+ * Provides the block that was disconnected.
*
* Called on a background thread. Only called for the active chainstate, since
* background chainstates should never disconnect blocks.
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 9ea43ca67c..cbf6c9b1ea 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -149,7 +149,7 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
fs::path pathIn = fs::PathFromString(strPath);
TryCreateDirectories(pathIn);
- if (!LockDirectory(pathIn, ".walletlock")) {
+ if (util::LockDirectory(pathIn, ".walletlock") != util::LockResult::Success) {
LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance may be using it.\n", strPath);
err = strprintf(_("Error initializing wallet database environment %s!"), fs::quoted(fs::PathToString(Directory())));
return false;
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index c6ed0fe11c..6a8453965b 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -316,7 +316,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
// We cannot source new unconfirmed inputs(bip125 rule 2)
new_coin_control.m_min_depth = 1;
- auto res = CreateTransaction(wallet, recipients, std::nullopt, new_coin_control, false);
+ auto res = CreateTransaction(wallet, recipients, /*change_pos=*/std::nullopt, new_coin_control, false);
if (!res) {
errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + util::ErrorString(res));
return Result::WALLET_ERROR;
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 3e1ec667e0..99c548bf1d 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -734,7 +734,7 @@ RPCHelpMan dumpwallet()
* It may also avoid other security issues.
*/
if (fs::exists(filepath)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.u8string() + " already exists. If you are sure this is what you want, move it out of the way first");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.utf8string() + " already exists. If you are sure this is what you want, move it out of the way first");
}
std::ofstream file;
@@ -828,7 +828,7 @@ RPCHelpMan dumpwallet()
file.close();
UniValue reply(UniValue::VOBJ);
- reply.pushKV("filename", filepath.u8string());
+ reply.pushKV("filename", filepath.utf8string());
return reply;
},
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index b121c8e1a7..5a13b5ac8e 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -155,7 +155,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
std::shuffle(recipients.begin(), recipients.end(), FastRandomContext());
// Send
- auto res = CreateTransaction(wallet, recipients, std::nullopt, coin_control, true);
+ auto res = CreateTransaction(wallet, recipients, /*change_pos=*/std::nullopt, coin_control, true);
if (!res) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original);
}
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 164ce9afed..391153a2a1 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -69,6 +69,7 @@ static RPCHelpMan getwalletinfo()
{RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
+ {RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
RESULT_LAST_PROCESSED_BLOCK,
}},
},
@@ -132,6 +133,9 @@ static RPCHelpMan getwalletinfo()
obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
+ if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
+ obj.pushKV("birthtime", birthtime);
+ }
AppendLastProcessedBlock(obj, *pwallet);
return obj;
@@ -165,7 +169,7 @@ static RPCHelpMan listwalletdir()
UniValue wallets(UniValue::VARR);
for (const auto& path : ListDatabases(GetWalletDir())) {
UniValue wallet(UniValue::VOBJ);
- wallet.pushKV("name", path.u8string());
+ wallet.pushKV("name", path.utf8string());
wallets.push_back(wallet);
}
@@ -802,7 +806,7 @@ static RPCHelpMan migratewallet()
if (res->solvables_wallet) {
r.pushKV("solvables_name", res->solvables_wallet->GetName());
}
- r.pushKV("backup_path", res->backup_path.u8string());
+ r.pushKV("backup_path", res->backup_path.utf8string());
return r;
},
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 0b4800b848..8f0b72c2b0 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -710,7 +710,7 @@ void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime)
// Cannot determine birthday information, so set the wallet birthday to
// the beginning of time.
nTimeFirstKey = 1;
- } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
+ } else if (nTimeFirstKey == UNKNOWN_TIME || nCreateTime < nTimeFirstKey) {
nTimeFirstKey = nCreateTime;
}
@@ -1183,8 +1183,7 @@ bool LegacyScriptPubKeyMan::CanGenerateKeys() const
CPubKey LegacyScriptPubKeyMan::GenerateNewSeed()
{
assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
return DeriveNewSeed(key);
}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index dccbf3ced6..449a75eb6b 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -51,6 +51,9 @@ public:
virtual bool IsLocked() const = 0;
};
+//! Constant representing an unknown spkm creation time
+static constexpr int64_t UNKNOWN_TIME = std::numeric_limits<int64_t>::max();
+
//! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
@@ -286,7 +289,8 @@ private:
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
- int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = 0;
+ // By default, do not scan any block until keys/scripts are generated/imported
+ int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = UNKNOWN_TIME;
//! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
int64_t m_keypool_size GUARDED_BY(cs_KeyStore){DEFAULT_KEYPOOL_SIZE};
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 5b28d38c37..b51cd6332f 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -694,9 +694,12 @@ util::Result<SelectionResult> ChooseSelectionResult(interfaces::Chain& chain, co
// Maximum allowed weight
int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR);
- if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) {
- results.push_back(*bnb_result);
- } else append_error(bnb_result);
+ // SFFO frequently causes issues in the context of changeless input sets: skip BnB when SFFO is active
+ if (!coin_selection_params.m_subtract_fee_outputs) {
+ if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) {
+ results.push_back(*bnb_result);
+ } else append_error(bnb_result);
+ }
// As Knapsack and SRD can create change, also deduce change weight.
max_inputs_weight -= (coin_selection_params.change_output_size * WITNESS_SCALE_FACTOR);
@@ -1293,8 +1296,9 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
- if (!wallet.chain().checkChainLimits(tx)) {
- return util::Error{_("Transaction has too long of a mempool chain")};
+ auto result = wallet.chain().checkChainLimits(tx);
+ if (!result) {
+ return util::Error{util::ErrorString(result)};
}
}
@@ -1302,6 +1306,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
// accidental reuse.
reservedest.KeepDestination();
+ wallet.WalletLogPrintf("Coin Selection: Algorithm:%s, Waste Metric Score:%d\n", GetAlgorithmName(result.GetAlgo()), result.GetWaste());
wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
current_fee, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
feeCalc.est.pass.start, feeCalc.est.pass.end,
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index 504c078b80..3bd37cfd0e 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -216,7 +216,7 @@ struct CreatedTransactionResult
/**
* Create a new transaction paying the recipients with a set of coins
* selected by SelectCoins(); Also create the change output, when needed
- * @note passing change_pos as -1 will result in setting a random position
+ * @note passing change_pos as std::nullopt will result in setting a random position
*/
util::Result<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, std::optional<unsigned int> change_pos, const CCoinControl& coin_control, bool sign = true);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index fa0dfa5556..9fea14145f 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -320,7 +320,6 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_output_size);
coin_selection_params_bnb.m_cost_of_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size) + coin_selection_params_bnb.m_change_fee;
coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size);
- coin_selection_params_bnb.m_subtract_fee_outputs = true;
{
std::unique_ptr<CWallet> wallet = NewWallet(m_node);
@@ -345,6 +344,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
CoinsResult available_coins;
+ coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
add_coin(available_coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
add_coin(available_coins, *wallet, 3 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
add_coin(available_coins, *wallet, 2 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
@@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
PreSelectedInputs selected_input;
selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
- coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
+
LOCK(wallet->cs_wallet);
const auto result10 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(result10);
@@ -370,12 +370,14 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ CAmount input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(10 * CENT, 2, expected_result);
+ add_coin(10 * CENT + input_fee, 2, expected_result);
CCoinControl coin_control;
const auto result11 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result11));
@@ -385,13 +387,15 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(3000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(5000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(9 * CENT, 2, expected_result);
- add_coin(1 * CENT, 2, expected_result);
+ add_coin(9 * CENT + input_fee, 2, expected_result);
+ add_coin(1 * CENT + input_fee, 2, expected_result);
const auto result12 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result12));
available_coins.Clear();
@@ -400,13 +404,15 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(9 * CENT, 2, expected_result);
- add_coin(1 * CENT, 2, expected_result);
+ add_coin(9 * CENT + input_fee, 2, expected_result);
+ add_coin(1 * CENT + input_fee, 2, expected_result);
coin_control.m_allow_other_inputs = true;
COutput select_coin = available_coins.All().at(1); // pre select 9 coin
coin_control.Select(select_coin.outpoint);
@@ -449,6 +455,44 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
}
}
+BOOST_AUTO_TEST_CASE(bnb_sffo_restriction)
+{
+ // Verify the coin selection process does not produce a BnB solution when SFFO is enabled.
+ // This is currently problematic because it could require a change output. And BnB is specialized on changeless solutions.
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+ WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(300, uint256{})); // set a high block so internal UTXOs are selectable
+
+ FastRandomContext rand{};
+ CoinSelectionParams params{
+ rand,
+ /*change_output_size=*/ 31, // unused value, p2wpkh output size (wallet default change type)
+ /*change_spend_size=*/ 68, // unused value, p2wpkh input size (high-r signature)
+ /*min_change_target=*/ 0, // dummy, set later
+ /*effective_feerate=*/ CFeeRate(3000),
+ /*long_term_feerate=*/ CFeeRate(1000),
+ /*discard_feerate=*/ CFeeRate(1000),
+ /*tx_noinputs_size=*/ 0,
+ /*avoid_partial=*/ false,
+ };
+ params.m_subtract_fee_outputs = true;
+ params.m_change_fee = params.m_effective_feerate.GetFee(params.change_output_size);
+ params.m_cost_of_change = params.m_discard_feerate.GetFee(params.change_spend_size) + params.m_change_fee;
+ params.m_min_change_target = params.m_cost_of_change + 1;
+ // Add spendable coin at the BnB selection upper bound
+ CoinsResult available_coins;
+ add_coin(available_coins, *wallet, COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ add_coin(available_coins, *wallet, 0.5 * COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ add_coin(available_coins, *wallet, 0.5 * COIN, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ // Knapsack will only find a changeless solution on an exact match to the satoshi, SRD doesn’t look for changeless
+ // If BnB were run, it would produce a single input solution with the best waste score
+ auto result = WITH_LOCK(wallet->cs_wallet, return SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, COIN, /*coin_control=*/{}, params));
+ BOOST_CHECK(result.has_value());
+ BOOST_CHECK_NE(result->GetAlgo(), SelectionAlgorithm::BNB);
+ BOOST_CHECK(result->GetInputSet().size() == 2);
+ // We have only considered BnB, SRD, and Knapsack. Test needs to be reevaluated if new algo is added
+ BOOST_CHECK(result->GetAlgo() == SelectionAlgorithm::SRD || result->GetAlgo() == SelectionAlgorithm::KNAPSACK);
+}
+
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
FastRandomContext rand{};
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 4caf96b18d..87d419493b 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -86,7 +86,6 @@ FUZZ_TARGET(coinselection)
const CFeeRate effective_fee_rate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
// Discard feerate must be at least dust relay feerate
const CFeeRate discard_fee_rate{fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(DUST_RELAY_TX_FEE, COIN)};
- const CAmount min_viable_change{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
const CAmount target{fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(1, MAX_MONEY)};
const bool subtract_fee_outputs{fuzzed_data_provider.ConsumeBool()};
@@ -95,12 +94,15 @@ FUZZ_TARGET(coinselection)
coin_params.m_subtract_fee_outputs = subtract_fee_outputs;
coin_params.m_long_term_feerate = long_term_fee_rate;
coin_params.m_effective_feerate = effective_fee_rate;
- coin_params.min_viable_change = min_viable_change;
- coin_params.change_output_size = fuzzed_data_provider.ConsumeIntegralInRange<int>(10, 1000);
+ coin_params.change_output_size = fuzzed_data_provider.ConsumeIntegralInRange(1, MAX_SCRIPT_SIZE);
coin_params.m_change_fee = effective_fee_rate.GetFee(coin_params.change_output_size);
coin_params.m_discard_feerate = discard_fee_rate;
coin_params.change_spend_size = fuzzed_data_provider.ConsumeIntegralInRange<int>(41, 1000);
- coin_params.m_cost_of_change = coin_params.m_change_fee + coin_params.m_discard_feerate.GetFee(coin_params.change_spend_size);
+ const auto change_spend_fee{coin_params.m_discard_feerate.GetFee(coin_params.change_spend_size)};
+ coin_params.m_cost_of_change = coin_params.m_change_fee + change_spend_fee;
+ CScript change_out_script = CScript() << std::vector<unsigned char>(coin_params.change_output_size, OP_TRUE);
+ const auto dust{GetDustThreshold(CTxOut{/*nValueIn=*/0, change_out_script}, coin_params.m_discard_feerate)};
+ coin_params.min_viable_change = std::max(change_spend_fee + 1, dust);
int next_locktime{0};
CAmount total_balance{CreateCoins(fuzzed_data_provider, utxo_pool, coin_params, next_locktime)};
@@ -116,9 +118,10 @@ FUZZ_TARGET(coinselection)
}
// Run coinselection algorithms
- auto result_bnb = SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT);
+ auto result_bnb = coin_params.m_subtract_fee_outputs ? util::Error{Untranslated("BnB disabled when SFFO is enabled")} :
+ SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT);
if (result_bnb) {
- assert(result_bnb->GetChange(coin_params.m_cost_of_change, CAmount{0}) == 0);
+ assert(result_bnb->GetChange(coin_params.min_viable_change, coin_params.m_change_fee) == 0);
assert(result_bnb->GetSelectedValue() >= target);
(void)result_bnb->GetShuffledInputVector();
(void)result_bnb->GetInputSet();
diff --git a/src/wallet/test/fuzz/fees.cpp b/src/wallet/test/fuzz/fees.cpp
index 2f7892dc0a..c2e785651a 100644
--- a/src/wallet/test/fuzz/fees.cpp
+++ b/src/wallet/test/fuzz/fees.cpp
@@ -37,6 +37,10 @@ FUZZ_TARGET(wallet_fees, .init = initialize_setup)
}
if (fuzzed_data_provider.ConsumeBool()) {
+ wallet.m_fallback_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
+ }
+
+ if (fuzzed_data_provider.ConsumeBool()) {
wallet.m_discard_rate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
}
(void)GetDiscardRate(wallet);
@@ -58,6 +62,9 @@ FUZZ_TARGET(wallet_fees, .init = initialize_setup)
if (fuzzed_data_provider.ConsumeBool()) {
coin_control.m_confirm_target = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 999'000);
}
+ if (fuzzed_data_provider.ConsumeBool()) {
+ coin_control.m_fee_mode = fuzzed_data_provider.ConsumeBool() ? FeeEstimateMode::CONSERVATIVE : FeeEstimateMode::ECONOMICAL;
+ }
FeeCalculation fee_calculation;
FeeCalculation* maybe_fee_calculation{fuzzed_data_provider.ConsumeBool() ? nullptr : &fee_calculation};
diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp
index b0c955f482..228e9629ed 100644
--- a/src/wallet/test/fuzz/scriptpubkeyman.cpp
+++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp
@@ -49,9 +49,21 @@ void initialize_spkm()
MOCKED_DESC_CONVERTER.Init();
}
+/**
+ * Key derivation is expensive. Deriving deep derivation paths take a lot of compute and we'd rather spend time
+ * elsewhere in this target, like on actually fuzzing the DescriptorScriptPubKeyMan. So rule out strings which could
+ * correspond to a descriptor containing a too large derivation path.
+ */
+static bool TooDeepDerivPath(std::string_view desc)
+{
+ const FuzzBufferType desc_buf{reinterpret_cast<const unsigned char *>(desc.data()), desc.size()};
+ return HasDeepDerivPath(desc_buf);
+}
+
static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWalletDescriptor(FuzzedDataProvider& fuzzed_data_provider)
{
const std::string mocked_descriptor{fuzzed_data_provider.ConsumeRandomLengthString()};
+ if (TooDeepDerivPath(mocked_descriptor)) return {};
const auto desc_str{MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)};
if (!desc_str.has_value()) return std::nullopt;
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index 95d5c1b9ce..dfad0e2126 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -47,8 +47,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
pubkeys[i] = keys[i].GetPubKey();
}
- CKey uncompressedKey;
- uncompressedKey.MakeNewKey(false);
+ CKey uncompressedKey = GenerateRandomKey(/*compressed=*/false);
CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
std::unique_ptr<interfaces::Chain>& chain = m_node.chain;
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index b2d252b3f9..3509bc116f 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -33,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
coin_control.fOverrideFeeRate = true;
// We need to use a change type with high cost of change so that the leftover amount will be dropped to fee instead of added as a change output
coin_control.m_change_type = OutputType::LEGACY;
- auto res = CreateTransaction(*wallet, {recipient}, std::nullopt, coin_control);
+ auto res = CreateTransaction(*wallet, {recipient}, /*change_pos=*/std::nullopt, coin_control);
BOOST_CHECK(res);
const auto& txr = *res;
BOOST_CHECK_EQUAL(txr.tx->vout.size(), 1);
@@ -97,12 +97,12 @@ BOOST_FIXTURE_TEST_CASE(wallet_duplicated_preset_inputs_test, TestChain100Setup)
// so that the recipient's amount is no longer equal to the user's selected target of 299 BTC.
// First case, use 'subtract_fee_from_outputs=true'
- util::Result<CreatedTransactionResult> res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
+ util::Result<CreatedTransactionResult> res_tx = CreateTransaction(*wallet, recipients, /*change_pos=*/std::nullopt, coin_control);
BOOST_CHECK(!res_tx.has_value());
// Second case, don't use 'subtract_fee_from_outputs'.
recipients[0].fSubtractFeeFromAmount = false;
- res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
+ res_tx = CreateTransaction(*wallet, recipients, /*change_pos=*/std::nullopt, coin_control);
BOOST_CHECK(!res_tx.has_value());
}
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index ad8613d515..cbf3ccd1ec 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -24,7 +24,6 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
}
- wallet->LoadWallet();
{
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 3d1cbe36a8..65297054df 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -231,8 +231,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
keys.push_back(key);
key.clear();
key.setObject();
- CKey futureKey;
- futureKey.MakeNewKey(true);
+ CKey futureKey = GenerateRandomKey();
key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(futureKey.GetPubKey())));
key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1);
key.pushKV("internal", UniValue(true));
@@ -558,7 +557,7 @@ public:
CTransactionRef tx;
CCoinControl dummy;
{
- auto res = CreateTransaction(*wallet, {recipient}, std::nullopt, dummy);
+ auto res = CreateTransaction(*wallet, {recipient}, /*change_pos=*/std::nullopt, dummy);
BOOST_CHECK(res);
tx = res->tx;
}
@@ -704,8 +703,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
static size_t CalculateNestedKeyhashInputSize(bool use_max_sig)
{
// Generate ephemeral valid pubkey
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
CPubKey pubkey = key.GetPubKey();
// Generate pubkey hash
@@ -789,8 +787,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
context.args = &m_args;
context.chain = m_node.chain.get();
auto wallet = TestLoadWallet(context);
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
AddKey(*wallet, key);
TestUnloadWallet(std::move(wallet));
@@ -898,8 +895,7 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
context.args = &m_args;
context.chain = m_node.chain.get();
auto wallet = TestLoadWallet(context);
- CKey key;
- key.MakeNewKey(true);
+ CKey key = GenerateRandomKey();
AddKey(*wallet, key);
std::string error;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 4d4e23dd4c..70fb375efa 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1080,6 +1080,9 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
AddToSpends(wtx, &batch);
+
+ // Update birth time when tx time is older than it.
+ MaybeUpdateBirthTime(wtx.GetTxTime());
}
if (!fInsertedNew)
@@ -1199,6 +1202,10 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
}
}
}
+
+ // Update birth time when tx time is older than it.
+ MaybeUpdateBirthTime(wtx.GetTxTime());
+
return true;
}
@@ -1747,11 +1754,11 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
return true;
}
-void CWallet::FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time)
+void CWallet::MaybeUpdateBirthTime(int64_t time)
{
int64_t birthtime = m_birth_time.load();
- if (new_birth_time < birthtime) {
- m_birth_time = new_birth_time;
+ if (time < birthtime) {
+ m_birth_time = time;
}
}
@@ -2292,6 +2299,8 @@ DBErrors CWallet::LoadWallet()
{
LOCK(cs_wallet);
+ Assert(m_spk_managers.empty());
+ Assert(m_wallet_flags == 0);
DBErrors nLoadWalletRet = WalletBatch(GetDatabase()).LoadWallet(this);
if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
@@ -3087,7 +3096,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
int64_t time = spk_man->GetTimeFirstKey();
if (!time_first_key || time < *time_first_key) time_first_key = time;
}
- if (time_first_key) walletInstance->m_birth_time = *time_first_key;
+ if (time_first_key) walletInstance->MaybeUpdateBirthTime(*time_first_key);
if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
return nullptr;
@@ -3480,10 +3489,12 @@ LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man)
{
+ // Add spkm_man to m_spk_managers before calling any method
+ // that might access it.
const auto& spkm = m_spk_managers[id] = std::move(spkm_man);
// Update birth time if needed
- FirstKeyTimeChanged(spkm.get(), spkm->GetTimeFirstKey());
+ MaybeUpdateBirthTime(spkm->GetTimeFirstKey());
}
void CWallet::SetupLegacyScriptPubKeyMan()
@@ -3516,7 +3527,7 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
spk_man->NotifyWatchonlyChanged.connect(NotifyWatchonlyChanged);
spk_man->NotifyCanGetAddressesChanged.connect(NotifyCanGetAddressesChanged);
- spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&CWallet::FirstKeyTimeChanged, this, std::placeholders::_1, std::placeholders::_2));
+ spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&CWallet::MaybeUpdateBirthTime, this, std::placeholders::_2));
}
}
@@ -3567,8 +3578,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
// Make a seed
- CKey seed_key;
- seed_key.MakeNewKey(true);
+ CKey seed_key = GenerateRandomKey();
CPubKey seed = seed_key.GetPubKey();
assert(seed_key.VerifyPubKey(seed));
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 11b7964316..487921443f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -688,8 +688,8 @@ public:
bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- /** Updates wallet birth time if 'new_birth_time' is below it */
- void FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time);
+ /** Updates wallet birth time if 'time' is below it */
+ void MaybeUpdateBirthTime(int64_t time);
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
@@ -887,6 +887,9 @@ public:
/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
bool CanGetAddresses(bool internal = false) const;
+ /* Returns the time of the first created key or, in case of an import, it could be the time of the first received transaction */
+ int64_t GetBirthTime() const { return m_birth_time; }
+
/**
* Blocks until the wallet state is up-to-date to /at least/ the current
* chain at the time this function is entered
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index ba453b47e7..9820c7c0ee 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1401,13 +1401,13 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
}
// Make a copy of key to avoid data being deleted by the following read of the type
- Span key_data{key};
+ const SerializeData key_data{key.begin(), key.end()};
std::string type;
key >> type;
if (types.count(type) > 0) {
- if (!m_batch->Erase(key_data)) {
+ if (!m_batch->Erase(Span{key_data})) {
cursor.reset(nullptr);
m_batch->TxnAbort();
return false; // erase failed