aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml7
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am12
-rw-r--r--build_msvc/libsecp256k1/libsecp256k1.vcxproj2
-rw-r--r--build_msvc/vcpkg.json8
-rwxr-xr-xci/test/05_before_script.sh2
-rw-r--r--configure.ac49
-rw-r--r--contrib/builder-keys/README.md6
-rw-r--r--contrib/builder-keys/keys.txt1
-rwxr-xr-xcontrib/guix/libexec/build.sh16
-rwxr-xr-xcontrib/guix/libexec/codesign.sh7
-rw-r--r--contrib/guix/manifest.scm9
-rw-r--r--contrib/guix/patches/gcc-broken-longjmp.patch68
-rw-r--r--contrib/macdeploy/README.md23
-rwxr-xr-xcontrib/macdeploy/gen-sdk24
-rwxr-xr-xcontrib/seeds/makeseeds.py90
-rw-r--r--contrib/seeds/suspicious_hosts.txt16
-rw-r--r--contrib/testgen/README.md2
-rwxr-xr-xcontrib/testgen/gen_key_io_test_vectors.py22
-rw-r--r--depends/Makefile2
-rw-r--r--depends/README.md5
-rw-r--r--depends/funcs.mk22
-rw-r--r--depends/packages/native_libdmg-hfsplus.mk24
-rw-r--r--depends/packages/packages.mk2
-rw-r--r--depends/patches/native_libdmg-hfsplus/remove-libcrypto-dependency.patch45
-rw-r--r--doc/REST-interface.md19
-rw-r--r--doc/dependencies.md44
-rw-r--r--doc/developer-notes.md5
-rw-r--r--doc/release-process.md3
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/addrdb.cpp11
-rw-r--r--src/addrdb.h3
-rw-r--r--src/addrman.cpp67
-rw-r--r--src/addrman.h5
-rw-r--r--src/addrman_impl.h29
-rw-r--r--src/arith_uint256.cpp29
-rw-r--r--src/arith_uint256.h9
-rw-r--r--src/bench/addrman.cpp11
-rw-r--r--src/bench/rpc_blockchain.cpp4
-rw-r--r--src/bench/wallet_loading.cpp83
-rw-r--r--src/bitcoin-cli.cpp4
-rw-r--r--src/crypto/sha256.cpp16
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/init.cpp28
-rw-r--r--src/key.cpp8
-rw-r--r--src/logging/timer.h8
-rw-r--r--src/net.cpp41
-rw-r--r--src/net.h6
-rw-r--r--src/net_processing.cpp43
-rw-r--r--src/netaddress.cpp102
-rw-r--r--src/netaddress.h6
-rw-r--r--src/netbase.cpp53
-rw-r--r--src/netbase.h6
-rw-r--r--src/netgroup.cpp111
-rw-r--r--src/netgroup.h66
-rw-r--r--src/node/blockstorage.cpp20
-rw-r--r--src/node/blockstorage.h13
-rw-r--r--src/node/chainstate.cpp4
-rw-r--r--src/node/context.cpp1
-rw-r--r--src/node/context.h2
-rw-r--r--src/node/interfaces.cpp9
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoinamountfield.cpp22
-rw-r--r--src/qt/bitcoinamountfield.h3
-rw-r--r--src/qt/bitcoingui.cpp20
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/qt/bitcoinunits.cpp172
-rw-r--r--src/qt/bitcoinunits.h34
-rw-r--r--src/qt/coincontroldialog.cpp6
-rw-r--r--src/qt/guiutil.cpp18
-rw-r--r--src/qt/guiutil.h15
-rw-r--r--src/qt/initexecutor.cpp6
-rw-r--r--src/qt/notificator.cpp12
-rw-r--r--src/qt/optionsmodel.cpp31
-rw-r--r--src/qt/optionsmodel.h13
-rw-r--r--src/qt/overviewpage.cpp10
-rw-r--r--src/qt/peertablemodel.cpp3
-rw-r--r--src/qt/peertablemodel.h4
-rw-r--r--src/qt/peertablesortproxy.cpp2
-rw-r--r--src/qt/psbtoperationsdialog.cpp4
-rw-r--r--src/qt/rpcconsole.cpp13
-rw-r--r--src/qt/sendcoinsdialog.cpp3
-rw-r--r--src/qt/test/test_main.cpp42
-rw-r--r--src/qt/test/wallettests.cpp15
-rw-r--r--src/qt/transactiondesc.cpp28
-rw-r--r--src/qt/transactiondesc.h6
-rw-r--r--src/qt/transactionrecord.h21
-rw-r--r--src/qt/transactiontablemodel.cpp3
-rw-r--r--src/qt/walletcontroller.cpp3
-rw-r--r--src/qt/walletview.cpp1
-rw-r--r--src/qt/walletview.h3
-rw-r--r--src/random.cpp9
-rw-r--r--src/random.h5
-rw-r--r--src/rest.cpp11
-rw-r--r--src/rpc/blockchain.cpp45
-rw-r--r--src/rpc/blockchain.h3
-rw-r--r--src/rpc/request.cpp2
-rw-r--r--src/script/miniscript.cpp3
-rw-r--r--src/secp256k1/.cirrus.yml98
-rw-r--r--src/secp256k1/.gitattributes4
-rw-r--r--src/secp256k1/.gitignore10
-rw-r--r--src/secp256k1/Makefile.am92
-rw-r--r--src/secp256k1/README.md15
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m413
-rwxr-xr-xsrc/secp256k1/ci/cirrus.sh4
-rw-r--r--src/secp256k1/ci/linux-debian.Dockerfile3
-rw-r--r--src/secp256k1/configure.ac144
-rw-r--r--src/secp256k1/doc/CHANGELOG.md12
-rw-r--r--src/secp256k1/doc/release-process.md14
-rw-r--r--src/secp256k1/examples/EXAMPLES_COPYING121
-rw-r--r--src/secp256k1/examples/ecdh.c127
-rw-r--r--src/secp256k1/examples/ecdsa.c137
-rw-r--r--src/secp256k1/examples/random.h73
-rw-r--r--src/secp256k1/examples/schnorr.c152
-rw-r--r--src/secp256k1/include/secp256k1.h22
-rw-r--r--src/secp256k1/include/secp256k1_extrakeys.h9
-rw-r--r--src/secp256k1/include/secp256k1_schnorrsig.h13
-rw-r--r--src/secp256k1/sage/group_prover.sage64
-rw-r--r--src/secp256k1/sage/prove_group_implementations.sage64
-rw-r--r--src/secp256k1/sage/weierstrass_prover.sage13
-rw-r--r--src/secp256k1/src/bench_internal.c10
-rw-r--r--src/secp256k1/src/ecmult_compute_table.h16
-rw-r--r--src/secp256k1/src/ecmult_compute_table_impl.h49
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h86
-rw-r--r--src/secp256k1/src/ecmult_gen_compute_table.h (renamed from src/secp256k1/src/ecmult_gen_prec.h)8
-rw-r--r--src/secp256k1/src/ecmult_gen_compute_table_impl.h (renamed from src/secp256k1/src/ecmult_gen_prec_impl.h)10
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h2
-rw-r--r--src/secp256k1/src/ecmult_impl.h229
-rw-r--r--src/secp256k1/src/field.h15
-rw-r--r--src/secp256k1/src/field_10x26_impl.h109
-rw-r--r--src/secp256k1/src/field_5x52_impl.h100
-rw-r--r--src/secp256k1/src/field_impl.h2
-rw-r--r--src/secp256k1/src/gen_ecmult_static_pre_g.c131
-rw-r--r--src/secp256k1/src/group.h36
-rw-r--r--src/secp256k1/src/group_impl.h123
-rw-r--r--src/secp256k1/src/hash.h4
-rw-r--r--src/secp256k1/src/hash_impl.h61
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h35
-rw-r--r--src/secp256k1/src/modules/schnorrsig/main_impl.h6
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_impl.h43
-rw-r--r--src/secp256k1/src/precompute_ecmult.c96
-rw-r--r--src/secp256k1/src/precompute_ecmult_gen.c (renamed from src/secp256k1/src/gen_ecmult_gen_static_prec_table.c)43
-rw-r--r--src/secp256k1/src/precomputed_ecmult.c (renamed from src/secp256k1/src/ecmult_static_pre_g.h)231
-rw-r--r--src/secp256k1/src/precomputed_ecmult.h35
-rw-r--r--src/secp256k1/src/precomputed_ecmult_gen.c (renamed from src/secp256k1/src/ecmult_gen_static_prec_table.h)22
-rw-r--r--src/secp256k1/src/precomputed_ecmult_gen.h26
-rw-r--r--src/secp256k1/src/secp256k1.c8
-rw-r--r--src/secp256k1/src/testrand.h7
-rw-r--r--src/secp256k1/src/testrand_impl.h73
-rw-r--r--src/secp256k1/src/tests.c556
-rw-r--r--src/secp256k1/src/tests_exhaustive.c8
-rw-r--r--src/secp256k1/src/util.h41
-rw-r--r--src/secp256k1/src/valgrind_ctime_test.c2
-rw-r--r--src/sync.h4
-rw-r--r--src/test/addrman_tests.cpp119
-rw-r--r--src/test/data/key_io_invalid.json136
-rw-r--r--src/test/data/key_io_valid.json280
-rw-r--r--src/test/denialofservice_tests.cpp13
-rw-r--r--src/test/fuzz/addrman.cpp33
-rw-r--r--src/test/fuzz/asmap.cpp4
-rw-r--r--src/test/fuzz/connman.cpp13
-rw-r--r--src/test/fuzz/deserialize.cpp4
-rw-r--r--src/test/fuzz/util.cpp13
-rw-r--r--src/test/fuzz/util.h2
-rw-r--r--src/test/key_tests.cpp2
-rw-r--r--src/test/miniscript_tests.cpp11
-rw-r--r--src/test/netbase_tests.cpp27
-rw-r--r--src/test/pmt_tests.cpp15
-rw-r--r--src/test/util/logging.h2
-rw-r--r--src/test/util/net.h2
-rw-r--r--src/test/util/setup_common.cpp11
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/util/bytevectorhash.cpp4
-rw-r--r--src/util/epochguard.h3
-rw-r--r--src/util/macros.h2
-rw-r--r--src/util/sock.cpp5
-rw-r--r--src/util/sock.h10
-rw-r--r--src/util/time.cpp19
-rw-r--r--src/validation.cpp34
-rw-r--r--src/validation.h6
-rw-r--r--src/wallet/rpc/wallet.cpp2
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp18
-rw-r--r--test/README.md6
-rw-r--r--test/config.ini.in1
-rw-r--r--test/functional/README.md2
-rwxr-xr-xtest/functional/feature_fee_estimation.py105
-rwxr-xr-xtest/functional/interface_rest.py8
-rwxr-xr-xtest/functional/p2p_segwit.py25
-rwxr-xr-xtest/functional/test_framework/test_framework.py15
-rwxr-xr-xtest/functional/test_runner.py2
-rwxr-xr-xtest/functional/tool_signet_miner.py62
-rwxr-xr-xtest/functional/wallet_avoidreuse.py11
-rwxr-xr-xtest/functional/wallet_createwallet.py5
-rwxr-xr-xtest/functional/wallet_taproot.py14
-rwxr-xr-xtest/lint/lint-git-commit-check.py63
-rwxr-xr-xtest/lint/lint-git-commit-check.sh48
-rwxr-xr-xtest/lint/lint-includes.py179
-rwxr-xr-xtest/lint/lint-includes.sh103
-rwxr-xr-xtest/lint/lint-logs.py34
-rwxr-xr-xtest/lint/lint-logs.sh28
-rwxr-xr-xtest/lint/lint-python-mutable-default-parameters.py72
-rwxr-xr-xtest/lint/lint-python-mutable-default-parameters.sh52
-rwxr-xr-xtest/lint/lint-python.py131
-rwxr-xr-xtest/lint/lint-python.sh111
-rwxr-xr-xtest/lint/lint-submodule.py23
-rwxr-xr-xtest/lint/lint-submodule.sh20
-rwxr-xr-xtest/lint/lint-whitespace.py135
-rwxr-xr-xtest/lint/lint-whitespace.sh115
211 files changed, 4706 insertions, 2828 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 5bfdcbc9b1..c4aae3a50a 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -96,7 +96,7 @@ task:
env:
PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin;%PATH%'
PYTHONUTF8: 1
- CI_VCPKG_TAG: '2022.02.23'
+ CI_VCPKG_TAG: '2022.04.12'
VCPKG_DOWNLOADS: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\downloads'
VCPKG_DEFAULT_BINARY_CACHE: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives'
CCACHE_DIR: 'C:\Users\ContainerAdministrator\AppData\Local\ccache'
@@ -106,6 +106,7 @@ task:
QT_SOURCE_DIR: 'C:\qt-everywhere-src-5.15.3'
QTBASEDIR: 'C:\Qt_static'
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
+ QT_CONFIGURE_COMMAND: '..\configure -release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml'
IgnoreWarnIntDirInTempDetected: 'true'
merge_script:
- git config --global user.email "ci@ci.ci"
@@ -120,7 +121,7 @@ task:
folder: "%QTBASEDIR%"
reupload_on_changes: false
fingerprint_script:
- - echo %QT_DOWNLOAD_URL%
+ - echo %QT_DOWNLOAD_URL% %QT_CONFIGURE_COMMAND%
- msbuild -version
populate_script:
- curl -L -o C:\jom.zip http://download.qt.io/official_releases/jom/jom.zip
@@ -132,7 +133,7 @@ task:
- cd %QT_SOURCE_DIR%
- mkdir build
- cd build
- - ..\configure -release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml -prefix %QTBASEDIR%
+ - '%QT_CONFIGURE_COMMAND% -prefix %QTBASEDIR%'
- jom
- jom install
vcpkg_tools_cache:
diff --git a/.gitignore b/.gitignore
index cde517c986..6c888bfdc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,7 +77,6 @@ src/qt/bitcoin-qt.includes
*.log
*.trs
*.dmg
-*.iso
*.json.h
*.raw.h
diff --git a/Makefile.am b/Makefile.am
index 54e9a6865f..dd658170b3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ if ENABLE_MAN
SUBDIRS += doc/man
endif
.PHONY: deploy FORCE
-.INTERMEDIATE: $(OSX_TEMP_ISO) $(COVERAGE_INFO)
+.INTERMEDIATE: $(COVERAGE_INFO)
export PYTHONPATH
@@ -37,7 +37,6 @@ space := $(empty) $(empty)
OSX_APP=Bitcoin-Qt.app
OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME))
OSX_DMG = $(OSX_VOLNAME).dmg
-OSX_TEMP_ISO = $(OSX_DMG:.dmg=).temp.iso
OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus
OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns
OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed
@@ -47,7 +46,8 @@ DIST_CONTRIB = \
$(top_srcdir)/test/sanitizer_suppressions/tsan \
$(top_srcdir)/test/sanitizer_suppressions/ubsan \
$(top_srcdir)/contrib/linearize/linearize-data.py \
- $(top_srcdir)/contrib/linearize/linearize-hashes.py
+ $(top_srcdir)/contrib/linearize/linearize-hashes.py \
+ $(top_srcdir)/contrib/signet/miner
DIST_SHARE = \
$(top_srcdir)/share/genbuild.sh \
@@ -129,19 +129,15 @@ deploydir: $(OSX_DMG)
else !BUILD_DARWIN
APP_DIST_DIR=$(top_builddir)/dist
-$(OSX_TEMP_ISO): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt
+$(OSX_DMG): deploydir
$(XORRISOFS) -D -l -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -o $@ $(APP_DIST_DIR) -- $(if $(SOURCE_DATE_EPOCH),-volume_date all_file_dates =$(SOURCE_DATE_EPOCH))
-$(OSX_DMG): $(OSX_TEMP_ISO)
- $(DMG) dmg "$<" "$@"
-
$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING)
INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR)
deploydir: $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt
endif !BUILD_DARWIN
-appbundle: $(OSX_APP_BUILT)
deploy: $(OSX_DMG)
endif
diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
index f9b0a7975c..16ee32d87e 100644
--- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj
+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
@@ -8,6 +8,8 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<ItemGroup>
+ <ClCompile Include="..\..\src\secp256k1\src\precomputed_ecmult.c" />
+ <ClCompile Include="..\..\src\secp256k1\src\precomputed_ecmult_gen.c" />
<ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" />
</ItemGroup>
<ItemDefinitionGroup>
diff --git a/build_msvc/vcpkg.json b/build_msvc/vcpkg.json
index 48b4d1fd20..86773d1fd3 100644
--- a/build_msvc/vcpkg.json
+++ b/build_msvc/vcpkg.json
@@ -13,13 +13,5 @@
"features": ["thread"]
},
"zeromq"
- ],
- "builtin-baseline": "b86c0c35b88e2bf3557ff49dc831689c2f085090",
- "overrides": [
- {
- "name": "zeromq",
- "version": "4.3.4",
- "port-version": 3
- }
]
}
diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh
index d8dcb708aa..fc2f76797c 100755
--- a/ci/test/05_before_script.sh
+++ b/ci/test/05_before_script.sh
@@ -45,7 +45,7 @@ if [ -z "$NO_DEPENDS" ]; then
else
SHELL_OPTS="CONFIG_SHELL="
fi
- CI_EXEC "$SHELL_OPTS" make "$MAKEJOBS" -C depends HOST="$HOST" "$DEP_OPTS"
+ CI_EXEC "$SHELL_OPTS" make "$MAKEJOBS" -C depends HOST="$HOST" "$DEP_OPTS" LOG=1
fi
if [ -n "$PREVIOUS_RELEASES_TO_DOWNLOAD" ]; then
CI_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" "${PREVIOUS_RELEASES_TO_DOWNLOAD}"
diff --git a/configure.ac b/configure.ac
index ba570b2eee..4c80899e5f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -778,7 +778,6 @@ case $host in
AC_PATH_TOOL([INSTALLNAMETOOL], [install_name_tool], [install_name_tool])
AC_PATH_TOOL([OTOOL], [otool], [otool])
AC_PATH_PROGS([XORRISOFS], [xorrisofs], [xorrisofs])
- AC_PATH_PROGS([DMG], [dmg], [dmg])
dnl libtool will try to strip the static lib, which is a problem for
dnl cross-builds because strip attempts to call a hard-coded ld,
@@ -1300,21 +1299,6 @@ if test "$enable_fuzz" = "yes"; then
enable_fuzz_binary=yes
AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"], [], [$CXXFLAG_WERROR])
-
- AC_MSG_CHECKING([whether main function is needed for fuzz binary])
- AX_CHECK_LINK_FLAG(
- [-fsanitize=$use_sanitizers],
- [AC_MSG_RESULT([no])],
- [AC_MSG_RESULT([yes]); CORE_CPPFLAGS="$CORE_CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"],
- [],
- [AC_LANG_PROGRAM([[
- #include <cstdint>
- #include <cstddef>
- extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; }
- /* comment to remove the main function ...
- ]],[[
- */ int not_main() {
- ]])])
else
BITCOIN_QT_INIT
@@ -1328,8 +1312,25 @@ else
QT_DBUS_INCLUDES=SUPPRESS_WARNINGS($QT_DBUS_INCLUDES)
QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES)
fi
+fi
+
+if test "$enable_fuzz_binary" = "yes"; then
+ AC_MSG_CHECKING([whether main function is needed for fuzz binary])
+ AX_CHECK_LINK_FLAG(
+ [],
+ [AC_MSG_RESULT([no])],
+ [AC_MSG_RESULT([yes]); CORE_CPPFLAGS="$CORE_CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"],
+ [$SANITIZER_LDFLAGS],
+ [AC_LANG_PROGRAM([[
+ #include <cstdint>
+ #include <cstddef>
+ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; }
+ /* comment to remove the main function ...
+ ]],[[
+ */ int not_main() {
+ ]])])
- CORE_CPPFLAGS="$CORE_CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"
+ CHECK_RUNTIME_LIB
fi
if test "$enable_wallet" != "no"; then
@@ -1819,10 +1820,6 @@ if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_
AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests])
fi
-if test "$enable_fuzz_binary" = "yes"; then
- CHECK_RUNTIME_LIB
-fi
-
AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"])
AM_CONDITIONAL([BUILD_DARWIN], [test "$BUILD_OS" = "darwin"])
AM_CONDITIONAL([TARGET_LINUX], [test "$TARGET_OS" = "linux"])
@@ -1959,15 +1956,7 @@ LIBS_TEMP="$LIBS"
unset LIBS
LIBS="$LIBS_TEMP"
-PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
-unset PKG_CONFIG_PATH
-PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
-
-PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR"
-unset PKG_CONFIG_LIBDIR
-PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP"
-
-ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental"
+ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig"
AC_CONFIG_SUBDIRS([src/secp256k1])
AC_OUTPUT
diff --git a/contrib/builder-keys/README.md b/contrib/builder-keys/README.md
index 56bd87d0af..a6179d6012 100644
--- a/contrib/builder-keys/README.md
+++ b/contrib/builder-keys/README.md
@@ -19,9 +19,15 @@ gpg --refresh-keys
To fetch keys of builders and active developers, feed the list of fingerprints
of the primary keys into gpg:
+On \*NIX:
```sh
while read fingerprint keyholder_name; do gpg --keyserver hkps://keys.openpgp.org --recv-keys ${fingerprint}; done < ./keys.txt
```
+On Windows (requires Gpg4win >= 4.0.0):
+```
+FOR /F "tokens=1" %i IN (keys.txt) DO gpg --keyserver hkps://keys.openpgp.org --recv-keys %i
+```
+
Add your key to the list if you provided Guix attestations for two major or
minor releases of Bitcoin Core.
diff --git a/contrib/builder-keys/keys.txt b/contrib/builder-keys/keys.txt
index 913e7d32f6..c70069b440 100644
--- a/contrib/builder-keys/keys.txt
+++ b/contrib/builder-keys/keys.txt
@@ -51,5 +51,6 @@ ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost (sjors)
9EDAFF80E080659604F4A76B2EBB056FD847F8A7 Stephan Oeste (Emzy)
6DEEF79B050C4072509B743F8C275BC595448867 Tomas Kanocz (KanoczTomas)
AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami (wtogami)
+74E2DEF5D77260B98BC19438099BAD163C70FBFA Will Clark (will8clark)
79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko (willyko)
71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan (laanwj)
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 4eeb360603..2757d10a7c 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -79,19 +79,6 @@ prepend_to_search_env_var() {
export "${1}=${2}${!1:+:}${!1}"
}
-case "$HOST" in
- *darwin*)
- # When targeting darwin, zlib is required by native_libdmg-hfsplus.
- zlib_store_path=$(store_path "zlib")
- zlib_static_store_path=$(store_path "zlib" static)
-
- prepend_to_search_env_var LIBRARY_PATH "${zlib_static_store_path}/lib:${zlib_store_path}/lib"
- prepend_to_search_env_var C_INCLUDE_PATH "${zlib_store_path}/include"
- prepend_to_search_env_var CPLUS_INCLUDE_PATH "${zlib_store_path}/include"
- prepend_to_search_env_var OBJC_INCLUDE_PATH "${zlib_store_path}/include"
- prepend_to_search_env_var OBJCPLUS_INCLUDE_PATH "${zlib_store_path}/include"
-esac
-
# Set environment variables to point the CROSS toolchain to the right
# includes/libs for $HOST
case "$HOST" in
@@ -332,8 +319,7 @@ mkdir -p "$DISTSRC"
mkdir -p "unsigned-app-${HOST}"
cp --target-directory="unsigned-app-${HOST}" \
osx_volname \
- contrib/macdeploy/detached-sig-create.sh \
- "${BASEPREFIX}/${HOST}"/native/bin/dmg
+ contrib/macdeploy/detached-sig-create.sh
mv --target-directory="unsigned-app-${HOST}" dist
(
cd "unsigned-app-${HOST}"
diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh
index 6ede95f42b..9a5d3a1ce5 100755
--- a/contrib/guix/libexec/codesign.sh
+++ b/contrib/guix/libexec/codesign.sh
@@ -84,14 +84,11 @@ mkdir -p "$DISTSRC"
# Apply detached codesignatures to dist/ (in-place)
signapple apply dist/Bitcoin-Qt.app codesignatures/osx/dist
- # Make an uncompressed DMG from dist/
+ # Make a DMG from dist/
xorrisofs -D -l -V "$(< osx_volname)" -no-pad -r -dir-mode 0755 \
- -o uncompressed.dmg \
+ -o "${OUTDIR}/${DISTNAME}-${HOST}.dmg" \
dist \
-- -volume_date all_file_dates ="$SOURCE_DATE_EPOCH"
-
- # Compress uncompressed.dmg and output to OUTDIR
- ./dmg dmg uncompressed.dmg "${OUTDIR}/${DISTNAME}-${HOST}.dmg"
;;
*)
exit 1
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index fcec592c2c..9f8a4008cf 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -162,9 +162,10 @@ desirable for building Bitcoin Core release binaries."
(define (make-gcc-with-pthreads gcc)
(package-with-extra-configure-variable gcc "--enable-threads" "posix"))
-(define (make-mingw-w64-cross-gcc-vmov-alignment cross-gcc)
+(define (make-mingw-w64-cross-gcc cross-gcc)
(package-with-extra-patches cross-gcc
- (search-our-patches "vmov-alignment.patch")))
+ (search-our-patches "vmov-alignment.patch"
+ "gcc-broken-longjmp.patch")))
(define (make-mingw-pthreads-cross-toolchain target)
"Create a cross-compilation toolchain package for TARGET"
@@ -172,7 +173,7 @@ desirable for building Bitcoin Core release binaries."
(pthreads-xlibc mingw-w64-x86_64-winpthreads)
(pthreads-xgcc (make-gcc-with-pthreads
(cross-gcc target
- #:xgcc (make-ssp-fixed-gcc (make-mingw-w64-cross-gcc-vmov-alignment base-gcc))
+ #:xgcc (make-ssp-fixed-gcc (make-mingw-w64-cross-gcc base-gcc))
#:xbinutils xbinutils
#:libc pthreads-xlibc))))
;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and
@@ -572,8 +573,6 @@ inspecting signatures in Mach-O binaries.")
bzip2
gzip
xz
- zlib
- (list zlib "static")
;; Build tools
gnu-make
libtool
diff --git a/contrib/guix/patches/gcc-broken-longjmp.patch b/contrib/guix/patches/gcc-broken-longjmp.patch
new file mode 100644
index 0000000000..1cfc0918b0
--- /dev/null
+++ b/contrib/guix/patches/gcc-broken-longjmp.patch
@@ -0,0 +1,68 @@
+commit eb5698897c52702498938592d7f76e67d126451f
+Author: Eric Botcazou <ebotcazou@adacore.com>
+Date: Wed May 5 22:48:51 2021 +0200
+
+ Fix PR target/100402
+
+ This is a regression for 64-bit Windows present from mainline down to the 9
+ branch and introduced by the fix for PR target/99234. Again SEH, but with
+ a twist related to the way MinGW implements setjmp/longjmp, which turns out
+ to be piggybacked on SEH with recent versions of MinGW, i.e. the longjmp
+ performs a bona-fide unwinding of the stack, because it calls RtlUnwindEx
+ with the second argument initially passed to setjmp, which is the result of
+ __builtin_frame_address (0) in the MinGW header file:
+
+ define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0))
+
+ This means that we directly expose the frame pointer to the SEH machinery
+ here (unlike with regular exception handling where we use an intermediate
+ CFA) and thus that we cannot do whatever we want with it. The old code
+ would leave it unaligned, i.e. not multiple of 16, whereas the new code
+ aligns it, but this breaks for some reason; at least it appears that a
+ .seh_setframe directive with 0 as second argument always works, so the
+ fix aligns it this way.
+
+ gcc/
+ PR target/100402
+ * config/i386/i386.c (ix86_compute_frame_layout): For a SEH target,
+ always return the establisher frame for __builtin_frame_address (0).
+ gcc/testsuite/
+ * gcc.c-torture/execute/20210505-1.c: New test.
+
+diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
+index 2f838840e96..06ad1b2274e 100644
+--- a/gcc/config/i386/i386.c
++++ b/gcc/config/i386/i386.c
+@@ -6356,12 +6356,29 @@ ix86_compute_frame_layout (void)
+ area, see the SEH code in config/i386/winnt.c for the rationale. */
+ frame->hard_frame_pointer_offset = frame->sse_reg_save_offset;
+
+- /* If we can leave the frame pointer where it is, do so. Also, return
++ /* If we can leave the frame pointer where it is, do so; however return
+ the establisher frame for __builtin_frame_address (0) or else if the
+- frame overflows the SEH maximum frame size. */
++ frame overflows the SEH maximum frame size.
++
++ Note that the value returned by __builtin_frame_address (0) is quite
++ constrained, because setjmp is piggybacked on the SEH machinery with
++ recent versions of MinGW:
++
++ # elif defined(__SEH__)
++ # if defined(__aarch64__) || defined(_ARM64_)
++ # define setjmp(BUF) _setjmp((BUF), __builtin_sponentry())
++ # elif (__MINGW_GCC_VERSION < 40702)
++ # define setjmp(BUF) _setjmp((BUF), mingw_getsp())
++ # else
++ # define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0))
++ # endif
++
++ and the second argument passed to _setjmp, if not null, is forwarded
++ to the TargetFrame parameter of RtlUnwindEx by longjmp (after it has
++ built an ExceptionRecord on the fly describing the setjmp buffer). */
+ const HOST_WIDE_INT diff
+ = frame->stack_pointer_offset - frame->hard_frame_pointer_offset;
+- if (diff <= 255)
++ if (diff <= 255 && !crtl->accesses_prior_frames)
+ {
+ /* The resulting diff will be a multiple of 16 lower than 255,
+ i.e. at most 240 as required by the unwind data structure. */
diff --git a/contrib/macdeploy/README.md b/contrib/macdeploy/README.md
index ce69079e29..fa7d953ce3 100644
--- a/contrib/macdeploy/README.md
+++ b/contrib/macdeploy/README.md
@@ -15,13 +15,16 @@ When complete, it will have produced `Bitcoin-Core.dmg`.
A free Apple Developer Account is required to proceed.
Our current macOS SDK
-(`Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz`) can be
-extracted from
+(`Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz`)
+can be extracted from
[Xcode_12.2.xip](https://download.developer.apple.com/Developer_Tools/Xcode_12.2/Xcode_12.2.xip).
+
Alternatively, after logging in to your account go to 'Downloads', then 'More'
and search for [`Xcode_12.2`](https://developer.apple.com/download/all/?q=Xcode%2012.2).
+
An Apple ID and cookies enabled for the hostname are needed to download this.
-The `sha256sum` of the archive should be `28d352f8c14a43d9b8a082ac6338dc173cb153f964c6e8fb6ba389e5be528bd0`.
+
+The `sha256sum` of the downloaded XIP archive should be `28d352f8c14a43d9b8a082ac6338dc173cb153f964c6e8fb6ba389e5be528bd0`.
After Xcode version 7.x, Apple started shipping the `Xcode.app` in a `.xip`
archive. This makes the SDK less-trivial to extract on non-macOS machines. One
@@ -55,7 +58,10 @@ previous stage) as the first argument.
./contrib/macdeploy/gen-sdk '/path/to/Xcode.app'
```
+The `sha256sum` of the generated TAR.GZ archive should be `e7ca56bc8804d16624fad68be2e71647747d6629cacaaa3de5fbfa7f444e9eae`.
+
## Deterministic macOS DMG Notes
+
Working macOS DMGs are created in Linux by combining a recent `clang`, the Apple
`binutils` (`ld`, `ar`, etc) and DMG authoring tools.
@@ -89,16 +95,7 @@ redistributed.
[`xorrisofs`](https://www.gnu.org/software/xorriso/) is used to create the DMG.
-`xorrisofs` cannot compress DMGs, so afterwards, the DMG tool from the
-`libdmg-hfsplus` project is used to compress it. There are several bugs in this
-tool and its maintainer has seemingly abandoned the project.
-
-The DMG tool has the ability to create DMGs from scratch as well, but this functionality is
-broken. Only the compression feature is currently used. Ideally, the creation could be fixed
-and `xorrisofs` would no longer be necessary.
-
-Background images and other features can be added to DMG files by inserting a
-`.DS_Store` during creation.
+A background image is added to DMG files by inserting a `.DS_Store` during creation.
As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a requirement in
order to satisfy the new Gatekeeper requirements. Because this private key cannot be
diff --git a/contrib/macdeploy/gen-sdk b/contrib/macdeploy/gen-sdk
index ebef1d2db0..d70cc8613c 100755
--- a/contrib/macdeploy/gen-sdk
+++ b/contrib/macdeploy/gen-sdk
@@ -8,6 +8,21 @@ import gzip
import os
import contextlib
+# monkey-patch Python 3.8 and older to fix wrong TAR header handling
+# see https://github.com/bitcoin/bitcoin/pull/24534
+# and https://github.com/python/cpython/pull/18080 for more info
+if sys.version_info < (3, 9):
+ _old_create_header = tarfile.TarInfo._create_header
+ def _create_header(info, format, encoding, errors):
+ buf = _old_create_header(info, format, encoding, errors)
+ # replace devmajor/devminor with binary zeroes
+ buf = buf[:329] + bytes(16) + buf[345:]
+ # recompute checksum
+ chksum = tarfile.calc_chksums(buf)[0]
+ buf = buf[:-364] + bytes("%06o\0" % chksum, "ascii") + buf[-357:]
+ return buf
+ tarfile.TarInfo._create_header = staticmethod(_create_header)
+
@contextlib.contextmanager
def cd(path):
"""Context manager that restores PWD even if an exception was raised."""
@@ -75,14 +90,21 @@ def run():
tarinfo.name = str(pathlib.Path(alt_base_dir, tarinfo.name))
if tarinfo.linkname and tarinfo.linkname.startswith("./"):
tarinfo.linkname = str(pathlib.Path(alt_base_dir, tarinfo.linkname))
+ # make metadata deterministic
+ tarinfo.mtime = 0
+ tarinfo.uid, tarinfo.uname = 0, ''
+ tarinfo.gid, tarinfo.gname = 0, ''
+ # don't use isdir() as there are also executable files present
+ tarinfo.mode = 0o0755 if tarinfo.mode & 0o0100 else 0x0644
return tarinfo
with cd(dir_to_add):
+ # recursion already adds entries in sorted order
tarfp.add(".", recursive=True, filter=change_tarinfo_base)
print("Creating output .tar.gz file...")
with out_sdktgz_path.open("wb") as fp:
with gzip.GzipFile(fileobj=fp, mode='wb', compresslevel=9, mtime=0) as gzf:
- with tarfile.open(mode="w", fileobj=gzf) as tarfp:
+ with tarfile.open(mode="w", fileobj=gzf, format=tarfile.GNU_FORMAT) as tarfp:
print("Adding MacOSX SDK {} files...".format(sdk_version))
tarfp_add_with_base_change(tarfp, sdk_dir, out_name)
print("Adding libc++ headers...")
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 2b377f6c01..78eb04a836 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -10,18 +10,16 @@ import re
import sys
import dns.resolver
import collections
+from typing import List, Dict, Union
NSEEDS=512
-MAX_SEEDS_PER_ASN=2
-
-MIN_BLOCKS = 337600
-
-# These are hosts that have been observed to be behaving strangely (e.g.
-# aggressively connecting to every node).
-with open("suspicious_hosts.txt", mode="r", encoding="utf-8") as f:
- SUSPICIOUS_HOSTS = {s.strip() for s in f if s.strip()}
+MAX_SEEDS_PER_ASN = {
+ 'ipv4': 2,
+ 'ipv6': 10,
+}
+MIN_BLOCKS = 730000
PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$")
PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$")
@@ -40,9 +38,13 @@ PATTERN_AGENT = re.compile(
r"23.99"
r")")
-def parseline(line):
+def parseline(line: str) -> Union[dict, None]:
+ """ Parses a line from `seeds_main.txt` into a dictionary of details for that line.
+ or `None`, if the line could not be parsed.
+ """
sline = line.split()
if len(sline) < 11:
+ # line too short to be valid, skip it.
return None
m = PATTERN_IPV4.match(sline[0])
sortkey = None
@@ -107,25 +109,26 @@ def parseline(line):
'sortkey': sortkey,
}
-def dedup(ips):
- '''deduplicate by address,port'''
+def dedup(ips: List[Dict]) -> List[Dict]:
+ """ Remove duplicates from `ips` where multiple ips share address and port. """
d = {}
for ip in ips:
d[ip['ip'],ip['port']] = ip
return list(d.values())
-def filtermultiport(ips):
- '''Filter out hosts with more nodes per IP'''
+def filtermultiport(ips: List[Dict]) -> List[Dict]:
+ """ Filter out hosts with more nodes per IP"""
hist = collections.defaultdict(list)
for ip in ips:
hist[ip['sortkey']].append(ip)
return [value[0] for (key,value) in list(hist.items()) if len(value)==1]
-def lookup_asn(net, ip):
- '''
- Look up the asn for an IP (4 or 6) address by querying cymru.com, or None
- if it could not be found.
- '''
+def lookup_asn(net: str, ip: str) -> Union[int, None]:
+ """ Look up the asn for an `ip` address by querying cymru.com
+ on network `net` (e.g. ipv4 or ipv6).
+
+ Returns in integer ASN or None if it could not be found.
+ """
try:
if net == 'ipv4':
ipaddr = ip
@@ -147,20 +150,33 @@ def lookup_asn(net, ip):
return None
# Based on Greg Maxwell's seed_filter.py
-def filterbyasn(ips, max_per_asn, max_per_net):
+def filterbyasn(ips: List[Dict], max_per_asn: Dict, max_per_net: int) -> List[Dict]:
+ """ Prunes `ips` by
+ (a) trimming ips to have at most `max_per_net` ips from each net (e.g. ipv4, ipv6); and
+ (b) trimming ips to have at most `max_per_asn` ips from each asn in each net.
+ """
# Sift out ips by type
ips_ipv46 = [ip for ip in ips if ip['net'] in ['ipv4', 'ipv6']]
ips_onion = [ip for ip in ips if ip['net'] == 'onion']
# Filter IPv46 by ASN, and limit to max_per_net per network
result = []
- net_count = collections.defaultdict(int)
- asn_count = collections.defaultdict(int)
- for ip in ips_ipv46:
+ net_count: Dict[str, int] = collections.defaultdict(int)
+ asn_count: Dict[int, int] = collections.defaultdict(int)
+
+ for i, ip in enumerate(ips_ipv46):
+ if i % 10 == 0:
+ # give progress update
+ print(f"{i:6d}/{len(ips_ipv46)} [{100*i/len(ips_ipv46):04.1f}%]\r", file=sys.stderr, end='', flush=True)
+
if net_count[ip['net']] == max_per_net:
+ # do not add this ip as we already too many
+ # ips from this network
continue
asn = lookup_asn(ip['net'], ip['ip'])
- if asn is None or asn_count[asn] == max_per_asn:
+ if asn is None or asn_count[asn] == max_per_asn[ip['net']]:
+ # do not add this ip as we already have too many
+ # ips from this ASN on this network
continue
asn_count[asn] += 1
net_count[ip['net']] += 1
@@ -170,35 +186,33 @@ def filterbyasn(ips, max_per_asn, max_per_net):
result.extend(ips_onion[0:max_per_net])
return result
-def ip_stats(ips):
- hist = collections.defaultdict(int)
+def ip_stats(ips: List[Dict]) -> str:
+ """ Format and return pretty string from `ips`. """
+ hist: Dict[str, int] = collections.defaultdict(int)
for ip in ips:
if ip is not None:
hist[ip['net']] += 1
- return '%6d %6d %6d' % (hist['ipv4'], hist['ipv6'], hist['onion'])
+ return f"{hist['ipv4']:6d} {hist['ipv6']:6d} {hist['onion']:6d}"
def main():
lines = sys.stdin.readlines()
ips = [parseline(line) for line in lines]
print('\x1b[7m IPv4 IPv6 Onion Pass \x1b[0m', file=sys.stderr)
- print('%s Initial' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Initial', file=sys.stderr)
# Skip entries with invalid address.
ips = [ip for ip in ips if ip is not None]
- print('%s Skip entries with invalid address' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Skip entries with invalid address', file=sys.stderr)
# Skip duplicates (in case multiple seeds files were concatenated)
ips = dedup(ips)
- print('%s After removing duplicates' % (ip_stats(ips)), file=sys.stderr)
- # Skip entries from suspicious hosts.
- ips = [ip for ip in ips if ip['ip'] not in SUSPICIOUS_HOSTS]
- print('%s Skip entries from suspicious hosts' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} After removing duplicates', file=sys.stderr)
# Enforce minimal number of blocks.
ips = [ip for ip in ips if ip['blocks'] >= MIN_BLOCKS]
- print('%s Enforce minimal number of blocks' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Enforce minimal number of blocks', file=sys.stderr)
# Require service bit 1.
ips = [ip for ip in ips if (ip['service'] & 1) == 1]
- print('%s Require service bit 1' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Require service bit 1', file=sys.stderr)
# Require at least 50% 30-day uptime for clearnet, 10% for onion.
req_uptime = {
'ipv4': 50,
@@ -206,18 +220,18 @@ def main():
'onion': 10,
}
ips = [ip for ip in ips if ip['uptime'] > req_uptime[ip['net']]]
- print('%s Require minimum uptime' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Require minimum uptime', file=sys.stderr)
# Require a known and recent user agent.
ips = [ip for ip in ips if PATTERN_AGENT.match(ip['agent'])]
- print('%s Require a known and recent user agent' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Require a known and recent user agent', file=sys.stderr)
# Sort by availability (and use last success as tie breaker)
ips.sort(key=lambda x: (x['uptime'], x['lastsuccess'], x['ip']), reverse=True)
# Filter out hosts with multiple bitcoin ports, these are likely abusive
ips = filtermultiport(ips)
- print('%s Filter out hosts with multiple bitcoin ports' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Filter out hosts with multiple bitcoin ports', file=sys.stderr)
# Look up ASNs and limit results, both per ASN and globally.
ips = filterbyasn(ips, MAX_SEEDS_PER_ASN, NSEEDS)
- print('%s Look up ASNs and limit results per ASN and per net' % (ip_stats(ips)), file=sys.stderr)
+ print(f'{ip_stats(ips):s} Look up ASNs and limit results per ASN and per net', file=sys.stderr)
# Sort the results by IP address (for deterministic output).
ips.sort(key=lambda x: (x['net'], x['sortkey']))
for ip in ips:
diff --git a/contrib/seeds/suspicious_hosts.txt b/contrib/seeds/suspicious_hosts.txt
deleted file mode 100644
index 13385cc816..0000000000
--- a/contrib/seeds/suspicious_hosts.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-130.211.129.106
-148.251.238.178
-176.9.46.6
-178.63.107.226
-54.173.72.127
-54.174.10.182
-54.183.64.54
-54.194.231.211
-54.66.214.167
-54.66.220.137
-54.67.33.14
-54.77.251.214
-54.94.195.96
-54.94.200.247
-83.81.130.26
-88.198.17.7 \ No newline at end of file
diff --git a/contrib/testgen/README.md b/contrib/testgen/README.md
index 66276ec9dd..2f0288df16 100644
--- a/contrib/testgen/README.md
+++ b/contrib/testgen/README.md
@@ -2,7 +2,7 @@
Utilities to generate test vectors for the data-driven Bitcoin tests.
-Usage:
+To use inside a scripted-diff (or just execute directly):
./gen_key_io_test_vectors.py valid 70 > ../../src/test/data/key_io_valid.json
./gen_key_io_test_vectors.py invalid 70 > ../../src/test/data/key_io_invalid.json
diff --git a/contrib/testgen/gen_key_io_test_vectors.py b/contrib/testgen/gen_key_io_test_vectors.py
index 4aa7dc200b..7bfb1d76a8 100755
--- a/contrib/testgen/gen_key_io_test_vectors.py
+++ b/contrib/testgen/gen_key_io_test_vectors.py
@@ -4,10 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Generate valid and invalid base58/bech32(m) address and private key test vectors.
-
-Usage:
- ./gen_key_io_test_vectors.py valid 70 > ../../src/test/data/key_io_valid.json
- ./gen_key_io_test_vectors.py invalid 70 > ../../src/test/data/key_io_invalid.json
'''
from itertools import islice
@@ -131,7 +127,7 @@ def is_valid_bech32(v):
def gen_valid_base58_vector(template):
'''Generate valid base58 vector'''
prefix = bytearray(template[0])
- payload = bytearray(os.urandom(template[1]))
+ payload = rand_bytes(size=template[1])
suffix = bytearray(template[2])
dst_prefix = bytearray(template[4])
dst_suffix = bytearray(template[5])
@@ -143,7 +139,7 @@ def gen_valid_bech32_vector(template):
'''Generate valid bech32 vector'''
hrp = template[0]
witver = template[1]
- witprog = bytearray(os.urandom(template[2]))
+ witprog = rand_bytes(size=template[2])
encoding = template[4]
dst_prefix = bytearray(template[5])
rv = bech32_encode(encoding, hrp, [witver] + convertbits(witprog, 8, 5))
@@ -173,17 +169,17 @@ def gen_invalid_base58_vector(template):
corrupt_suffix = randbool(0.2)
if corrupt_prefix:
- prefix = os.urandom(1)
+ prefix = rand_bytes(size=1)
else:
prefix = bytearray(template[0])
if randomize_payload_size:
- payload = os.urandom(max(int(random.expovariate(0.5)), 50))
+ payload = rand_bytes(size=max(int(random.expovariate(0.5)), 50))
else:
- payload = os.urandom(template[1])
+ payload = rand_bytes(size=template[1])
if corrupt_suffix:
- suffix = os.urandom(len(template[2]))
+ suffix = rand_bytes(size=len(template[2]))
else:
suffix = bytearray(template[2])
@@ -204,7 +200,7 @@ def gen_invalid_bech32_vector(template):
to_upper = randbool(0.1)
hrp = template[0]
witver = template[1]
- witprog = bytearray(os.urandom(template[2]))
+ witprog = rand_bytes(size=template[2])
encoding = template[3]
if no_data:
@@ -234,6 +230,9 @@ def randbool(p = 0.5):
'''Return True with P(p)'''
return random.random() < p
+def rand_bytes(*, size):
+ return bytearray(random.getrandbits(8) for _ in range(size))
+
def gen_invalid_vectors():
'''Generate invalid test vectors'''
# start with some manual edge-cases
@@ -250,6 +249,7 @@ def gen_invalid_vectors():
if __name__ == '__main__':
import json
iters = {'valid':gen_valid_vectors, 'invalid':gen_invalid_vectors}
+ random.seed(42)
try:
uiter = iters[sys.argv[1]]
except IndexError:
diff --git a/depends/Makefile b/depends/Makefile
index 723509c81d..b901533786 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -271,7 +271,7 @@ clean-all: clean
@rm -rf $(SOURCES_PATH) x86_64* i686* mips* arm* aarch64* powerpc* riscv32* riscv64* s390x*
clean:
- @rm -rf $(WORK_PATH) $(BASE_CACHE) $(BUILD)
+ @rm -rf $(WORK_PATH) $(BASE_CACHE) $(BUILD) *.log
install: check-packages $(host_prefix)/share/config.site
diff --git a/depends/README.md b/depends/README.md
index f7647198c6..da2a74e0e7 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -113,7 +113,10 @@ The following can be set when running make: `make FOO=bar`
- `BUILD_ID_SALT`: Optional salt to use when generating build package ids
- `FORCE_USE_SYSTEM_CLANG`: (EXPERTS ONLY) When cross-compiling for macOS, use Clang found in the
system's `$PATH` rather than the default prebuilt release of Clang
- from llvm.org. Clang 8 or later is required.
+ from llvm.org. Clang 8 or later is required
+- `LOG`: Use file-based logging for individual packages. During a package build its log file
+ resides in the `depends` directory, and the log file is printed out automatically in case
+ of build error. After successful build log files are moved along with package archives
If some packages are not built, for example `make NO_WALLET=1`, the appropriate
options will be passed to bitcoin's configure. In this case, `--disable-wallet`.
diff --git a/depends/funcs.mk b/depends/funcs.mk
index c4ad109c69..75fa1ed43f 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -67,6 +67,7 @@ $(1)_cached_checksum:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_bui
$(1)_patch_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)/.patches-$($(1)_build_id)
$(1)_prefixbin:=$($($(1)_type)_prefix)/bin/
$(1)_cached:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz
+$(1)_build_log:=$(BASEDIR)/$(1)-$($(1)_version)-$($(1)_build_id).log
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
#stamps
@@ -85,7 +86,7 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path))
# The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior
$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash))
$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_TAR) --no-same-owner --strip-components=1 -xf $$($(1)_source)
-$(1)_preprocess_cmds ?=
+$(1)_preprocess_cmds ?= true
$(1)_build_cmds ?=
$(1)_config_cmds ?=
$(1)_stage_cmds ?=
@@ -187,44 +188,48 @@ endif
endef
define int_add_cmds
+ifneq ($(LOG),)
+$(1)_logging = >>$$($(1)_build_log) 2>&1 || { if test -f $$($(1)_build_log); then cat $$($(1)_build_log); fi; exit 1; }
+endif
+
$($(1)_fetched):
mkdir -p $$(@D) $(SOURCES_PATH)
rm -f $$@
touch $$@
- cd $$(@D); $(call $(1)_fetch_cmds,$(1))
+ cd $$(@D); $($(1)_fetch_cmds)
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
touch $$@
$($(1)_extracted): | $($(1)_fetched)
echo Extracting $(1)...
mkdir -p $$(@D)
- cd $$(@D); $(call $(1)_extract_cmds,$(1))
+ cd $$(@D); $($(1)_extract_cmds)
touch $$@
$($(1)_preprocessed): | $($(1)_extracted)
echo Preprocessing $(1)...
mkdir -p $$(@D) $($(1)_patch_dir)
$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;)
- cd $$(@D); $(call $(1)_preprocess_cmds, $(1))
+ { cd $$(@D); $($(1)_preprocess_cmds); } $$($(1)_logging)
touch $$@
$($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed)
echo Configuring $(1)...
rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), $(build_TAR) --no-same-owner -xf $($(package)_cached); )
mkdir -p $$(@D)
- +cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1))
+ +{ cd $$(@D); $($(1)_config_env) $($(1)_config_cmds); } $$($(1)_logging)
touch $$@
$($(1)_built): | $($(1)_configured)
echo Building $(1)...
mkdir -p $$(@D)
- +cd $$(@D); $($(1)_build_env) $(call $(1)_build_cmds, $(1))
+ +{ cd $$(@D); $($(1)_build_env) $($(1)_build_cmds); } $$($(1)_logging)
touch $$@
$($(1)_staged): | $($(1)_built)
echo Staging $(1)...
mkdir -p $($(1)_staging_dir)/$(host_prefix)
- cd $($(1)_build_dir); $($(1)_stage_env) $(call $(1)_stage_cmds, $(1))
+ +{ cd $($(1)_build_dir); $($(1)_stage_env) $($(1)_stage_cmds); } $$($(1)_logging)
rm -rf $($(1)_extract_dir)
touch $$@
$($(1)_postprocessed): | $($(1)_staged)
echo Postprocessing $(1)...
- cd $($(1)_staging_prefix_dir); $(call $(1)_postprocess_cmds)
+ cd $($(1)_staging_prefix_dir); $($(1)_postprocess_cmds)
touch $$@
$($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed)
echo Caching $(1)...
@@ -233,6 +238,7 @@ $($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed)
rm -rf $$(@D) && mkdir -p $$(@D)
mv $$($(1)_staging_dir)/$$(@F) $$(@)
rm -rf $($(1)_staging_dir)
+ if test -f $($(1)_build_log); then mv $($(1)_build_log) $$(@D); fi
$($(1)_cached_checksum): $($(1)_cached)
cd $$(@D); $(build_SHA256SUM) $$(<F) > $$(@)
diff --git a/depends/packages/native_libdmg-hfsplus.mk b/depends/packages/native_libdmg-hfsplus.mk
deleted file mode 100644
index c7c8adef41..0000000000
--- a/depends/packages/native_libdmg-hfsplus.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-package=native_libdmg-hfsplus
-$(package)_version=7ac55ec64c96f7800d9818ce64c79670e7f02b67
-$(package)_download_path=https://github.com/planetbeing/libdmg-hfsplus/archive
-$(package)_file_name=$($(package)_version).tar.gz
-$(package)_sha256_hash=56fbdc48ec110966342f0ecddd6f8f89202f4143ed2a3336e42bbf88f940850c
-$(package)_build_subdir=build
-$(package)_patches=remove-libcrypto-dependency.patch
-
-define $(package)_preprocess_cmds
- patch -p1 < $($(package)_patch_dir)/remove-libcrypto-dependency.patch && \
- mkdir build
-endef
-
-define $(package)_config_cmds
- $($(package)_cmake) -DCMAKE_C_FLAGS="$$($(1)_cflags) -Wl,--build-id=none" -DCMAKE_SKIP_RPATH="ON" -DCMAKE_EXE_LINKER_FLAGS="-static" -DCMAKE_FIND_LIBRARY_SUFFIXES=".a" ..
-endef
-
-define $(package)_build_cmds
- $(MAKE) -C dmg
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) -C dmg install
-endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 991db7f46e..998cc0221c 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -26,7 +26,7 @@ usdt_linux_packages=systemtap
darwin_native_packages = native_ds_store native_mac_alias
ifneq ($(build_os),darwin)
-darwin_native_packages += native_cctools native_libtapi native_libdmg-hfsplus
+darwin_native_packages += native_cctools native_libtapi
ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
darwin_native_packages+= native_clang
diff --git a/depends/patches/native_libdmg-hfsplus/remove-libcrypto-dependency.patch b/depends/patches/native_libdmg-hfsplus/remove-libcrypto-dependency.patch
deleted file mode 100644
index f346c8f2cf..0000000000
--- a/depends/patches/native_libdmg-hfsplus/remove-libcrypto-dependency.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 3e5fd3fb56bc9ff03beb535979e33dcf83fe1f70 Mon Sep 17 00:00:00 2001
-From: Cory Fields <cory-nospam-@coryfields.com>
-Date: Thu, 8 May 2014 12:39:42 -0400
-Subject: [PATCH] dmg: remove libcrypto dependency
-
----
- dmg/CMakeLists.txt | 16 ----------------
- 1 file changed, 16 deletions(-)
-
-diff --git a/dmg/CMakeLists.txt b/dmg/CMakeLists.txt
-index eec62d6..3969f64 100644
---- a/dmg/CMakeLists.txt
-+++ b/dmg/CMakeLists.txt
-@@ -1,12 +1,5 @@
--INCLUDE(FindOpenSSL)
- INCLUDE(FindZLIB)
-
--FIND_LIBRARY(CRYPTO_LIBRARIES crypto
-- PATHS
-- /usr/lib
-- /usr/local/lib
-- )
--
- IF(NOT ZLIB_FOUND)
- message(FATAL_ERROR "zlib is required for dmg!")
- ENDIF(NOT ZLIB_FOUND)
-@@ -18,15 +11,6 @@ link_directories(${PROJECT_BINARY_DIR}/common ${PROJECT_BINARY_DIR}/hfs)
-
- add_library(dmg adc.c base64.c checksum.c dmgfile.c dmglib.c filevault.c io.c partition.c resources.c udif.c)
-
--IF(OPENSSL_FOUND)
-- add_definitions(-DHAVE_CRYPT)
-- include_directories(${OPENSSL_INCLUDE_DIR})
-- target_link_libraries(dmg ${CRYPTO_LIBRARIES})
-- IF(WIN32)
-- TARGET_LINK_LIBRARIES(dmg gdi32)
-- ENDIF(WIN32)
--ENDIF(OPENSSL_FOUND)
--
- target_link_libraries(dmg common hfs z)
-
- add_executable(dmg-bin dmg.c)
---
-2.22.0
-
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index c359725faf..4b46f29153 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -82,17 +82,7 @@ Given a height: returns hash of block in best-block-chain at height provided.
Returns various state info regarding block chain processing.
Only supports JSON as output format.
-* chain : (string) current network name (main, test, signet, regtest)
-* blocks : (numeric) the current number of blocks processed in the server
-* headers : (numeric) the current number of headers we have validated
-* bestblockhash : (string) the hash of the currently best block
-* difficulty : (numeric) the current difficulty
-* mediantime : (numeric) the median time of the 11 blocks before the most recent block on the blockchain
-* verificationprogress : (numeric) estimate of verification progress [0..1]
-* chainwork : (string) total amount of work in active chain, in hexadecimal
-* pruned : (boolean) if the blocks are subject to pruning
-* pruneheight : (numeric) highest block available
-* softforks : (array) status of softforks in progress
+Refer to the `getblockchaininfo` RPC help for details.
#### Query UTXO set
`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`
@@ -127,14 +117,15 @@ $ curl localhost:18332/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff76
#### Memory pool
`GET /rest/mempool/info.json`
-Returns various information about the TX mempool.
+Returns various information about the transaction mempool.
Only supports JSON as output format.
-Refer to the `getmempoolinfo` RPC for documentation of the fields.
+Refer to the `getmempoolinfo` RPC help for details.
`GET /rest/mempool/contents.json`
-Returns transactions in the TX mempool.
+Returns the transactions in the mempool.
Only supports JSON as output format.
+Refer to the `getrawmempool` RPC help for details.
Risks
-------------
diff --git a/doc/dependencies.md b/doc/dependencies.md
index d5d0c46679..392078bfaf 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -15,35 +15,35 @@ You can find installation instructions in the `build-*.md` file for your platfor
## Required
-| Dependency | Version used | Minimum required | Runtime |
-| --- | --- | --- | --- |
-| [Boost](https://www.boost.org/users/download/) | 1.77.0 | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No |
-| [libevent](https://github.com/libevent/libevent/releases) | 2.1.12-stable | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No |
-| [glibc](https://www.gnu.org/software/libc/) | N/A | [2.18](https://github.com/bitcoin/bitcoin/pull/23511) | Yes |
+| Dependency | Releases | Version used | Minimum required | Runtime |
+| --- | --- | --- | --- | --- |
+| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.77.0](https://github.com/bitcoin/bitcoin/pull/24383) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No |
+| [libevent](../depends/packages/libevent.mk) | [link](https://github.com/libevent/libevent/releases) | [2.1.12-stable](https://github.com/bitcoin/bitcoin/pull/21991) | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No |
+| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.18](https://github.com/bitcoin/bitcoin/pull/23511) | Yes |
## Optional
### GUI
-| Dependency | Version used | Minimum required | Runtime |
-| --- | --- | --- | --- |
-| [Fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/) | 2.12.6 | 2.6 | Yes |
-| [FreeType](https://freetype.org) | 2.11.0 | 2.3.0 | Yes |
-| [qrencode](https://fukuchi.org/works/qrencode/) | [3.4.4](https://fukuchi.org/works/qrencode) | | No |
-| [Qt](https://www.qt.io) | [5.15.3](https://download.qt.io/official_releases/qt/) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
+| Dependency | Releases | Version used | Minimum required | Runtime |
+| --- | --- | --- | --- | --- |
+| [Fontconfig](../depends/packages/fontconfig.mk) | [link](https://www.freedesktop.org/wiki/Software/fontconfig/) | [2.12.6](https://github.com/bitcoin/bitcoin/pull/23495) | 2.6 | Yes |
+| [FreeType](../depends/packages/freetype.mk) | [link](https://freetype.org) | [2.11.0](https://github.com/bitcoin/bitcoin/commit/01544dd78ccc0b0474571da854e27adef97137fb) | 2.3.0 | Yes |
+| [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [3.4.4](https://github.com/bitcoin/bitcoin/pull/6373) | | No |
+| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.3](https://github.com/bitcoin/bitcoin/pull/24668) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
### Networking
-| Dependency | Version used | Minimum required | Runtime |
-| --- | --- | --- | --- |
-| [libnatpmp](https://github.com/miniupnp/libnatpmp/) | commit [4536032...](https://github.com/miniupnp/libnatpmp/tree/4536032ae32268a45c073a4d5e91bbab4534773a) | | No |
-| [MiniUPnPc](https://miniupnp.tuxfamily.org/) | 2.2.2 | 1.9 | No |
+| Dependency | Releases | Version used | Minimum required | Runtime |
+| --- | --- | --- | --- | --- |
+| [libnatpmp](../depends/packages/libnatpmp.mk) | [link](https://github.com/miniupnp/libnatpmp/) | commit [4536032...](https://github.com/bitcoin/bitcoin/pull/21209) | | No |
+| [MiniUPnPc](../depends/packages/miniupnpc.mk) | [link](https://miniupnp.tuxfamily.org/) | [2.2.2](https://github.com/bitcoin/bitcoin/pull/20421) | 1.9 | No |
### Notifications
-| Dependency | Version used | Minimum required | Runtime |
-| --- | --- | --- | --- |
-| [ZeroMQ](https://zeromq.org) | 4.3.4 | 4.0.0 | No |
+| Dependency | Releases | Version used | Minimum required | Runtime |
+| --- | --- | --- | --- | --- |
+| [ZeroMQ](../depends/packages/zeromq.mk) | [link](https://github.com/zeromq/libzmq/releases) | [4.3.4](https://github.com/bitcoin/bitcoin/pull/23956) | 4.0.0 | No |
### Wallet
-| Dependency | Version used | Minimum required | Runtime |
-| --- | --- | --- | --- |
-| [Berkeley DB](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) (legacy wallet) | 4.8.30 | 4.8.x | No |
-| [SQLite](https://sqlite.org) | 3.32.1 | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | No |
+| Dependency | Releases | Version used | Minimum required | Runtime |
+| --- | --- | --- | --- | --- |
+| [Berkeley DB](../depends/packages/bdb.mk) (legacy wallet) | [link](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.30 | 4.8.x | No |
+| [SQLite](../depends/packages/sqlite.mk) | [link](https://sqlite.org) | [3.32.1](https://github.com/bitcoin/bitcoin/pull/19077) | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | No |
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index f06902e624..9b1026a375 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -1220,7 +1220,10 @@ A few guidelines for introducing and reviewing new RPC interfaces:
- *Rationale*: Consistency with the existing interface.
-- Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`)
+- Argument and field naming: please consider whether there is already a naming
+ style or spelling convention in the API for the type of object in question
+ (`blockhash`, for example), and if so, try to use that. If not, use snake case
+ `fee_delta` (and not, e.g. `feedelta` or camel case `feeDelta`).
- *Rationale*: Consistency with the existing interface.
diff --git a/doc/release-process.md b/doc/release-process.md
index bc80e3d072..2f3a163a8e 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -37,7 +37,8 @@ Release Process
- This update should be reviewed with a reindex-chainstate with assumevalid=0 to catch any defect
that causes rejection of blocks in the past history.
- Clear the release notes and move them to the wiki (see "Write the release notes" below).
-- Translations on Transifex
+- Translations on Transifex:
+ - Pull translations from Transifex into the master branch.
- Create [a new resource](https://www.transifex.com/bitcoin/bitcoin/content/) named after the major version with the slug `[bitcoin.qt-translation-<RRR>x]`, where `RRR` is the major branch number padded with zeros. Use `src/qt/locale/bitcoin_en.xlf` to create it.
- In the project workflow settings, ensure that [Translation Memory Fill-up](https://docs.transifex.com/translation-memory/enabling-autofill) is enabled and that [Translation Memory Context Matching](https://docs.transifex.com/translation-memory/translation-memory-with-context) is disabled.
- Update the Transifex slug in [`.tx/config`](/.tx/config) to the slug of the resource created in the first step. This identifies which resource the translations will be synchronized from.
diff --git a/src/Makefile.am b/src/Makefile.am
index c089bed0c9..476ff0a6c5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -180,6 +180,7 @@ BITCOIN_CORE_H = \
net_types.h \
netaddress.h \
netbase.h \
+ netgroup.h \
netmessagemaker.h \
node/blockstorage.h \
node/caches.h \
@@ -352,6 +353,7 @@ libbitcoin_node_a_SOURCES = \
init.cpp \
mapport.cpp \
net.cpp \
+ netgroup.cpp \
net_processing.cpp \
node/blockstorage.cpp \
node/caches.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 5dae4374e3..58a09cd4a4 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -74,6 +74,7 @@ endif
if ENABLE_WALLET
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp
+bench_bench_bitcoin_SOURCES += bench/wallet_loading.cpp
endif
bench_bench_bitcoin_LDADD += $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 1fa2644647..0a76f83150 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -13,6 +13,7 @@
#include <hash.h>
#include <logging/timer.h>
#include <netbase.h>
+#include <netgroup.h>
#include <random.h>
#include <streams.h>
#include <tinyformat.h>
@@ -49,7 +50,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
{
// Generate random temporary filename
uint16_t randv = 0;
- GetRandBytes((unsigned char*)&randv, sizeof(randv));
+ GetRandBytes({(unsigned char*)&randv, sizeof(randv)});
std::string tmpfn = strprintf("%s.%04x", prefix, randv);
// open temp output file, and associate with CAutoFile
@@ -182,10 +183,10 @@ void ReadFromStream(AddrMan& addr, CDataStream& ssPeers)
DeserializeDB(ssPeers, addr, false);
}
-std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
+std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
{
auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
- addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
int64_t nStart = GetTimeMillis();
const auto path_addr{args.GetDataDirNet() / "peers.dat"};
@@ -194,7 +195,7 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart);
} catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it
- addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const InvalidAddrManVersionError&) {
@@ -203,7 +204,7 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
return strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."));
}
// Addrman can be in an inconsistent state after failure, reset it
- addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
LogPrintf("Creating new peers.dat because the file version was not compatible (%s). Original backed up to peers.dat.bak\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const std::exception& e) {
diff --git a/src/addrdb.h b/src/addrdb.h
index 4bdafb64e4..627ef3ac3c 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -17,6 +17,7 @@ class ArgsManager;
class AddrMan;
class CAddress;
class CDataStream;
+class NetGroupManager;
struct bilingual_str;
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr);
@@ -48,7 +49,7 @@ public:
};
/** Returns an error string on failure */
-std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman);
+std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman);
/**
* Dump the anchor IP address database (anchors.dat)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 2a08d99eef..f74729d47b 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -43,17 +43,17 @@ static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
/** The maximum time we'll spend trying to resolve a tried table collision, in seconds */
static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
-int AddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap) const
+int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
- uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
+ uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << netgroupman.GetGroup(*this) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
-int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const
+int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const
{
- std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
- uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
+ std::vector<unsigned char> vchSourceGroupKey = netgroupman.GetGroup(src);
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << netgroupman.GetGroup(*this) << vchSourceGroupKey).GetCheapHash();
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
@@ -99,11 +99,11 @@ double AddrInfo::GetChance(int64_t nNow) const
return fChance;
}
-AddrManImpl::AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio)
+AddrManImpl::AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)
: insecure_rand{deterministic}
, nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
, m_consistency_check_ratio{consistency_check_ratio}
- , m_asmap{std::move(asmap)}
+ , m_netgroupman{netgroupman}
{
for (auto& bucket : vvNew) {
for (auto& entry : bucket) {
@@ -218,11 +218,7 @@ void AddrManImpl::Serialize(Stream& s_) const
}
// Store asmap checksum after bucket entries so that it
// can be ignored by older clients for backward compatibility.
- uint256 asmap_checksum;
- if (m_asmap.size() != 0) {
- asmap_checksum = SerializeHash(m_asmap);
- }
- s << asmap_checksum;
+ s << m_netgroupman.GetAsmapChecksum();
}
template <typename Stream>
@@ -298,7 +294,7 @@ void AddrManImpl::Unserialize(Stream& s_)
for (int n = 0; n < nTried; n++) {
AddrInfo info;
s >> info;
- int nKBucket = info.GetTriedBucket(nKey, m_asmap);
+ int nKBucket = info.GetTriedBucket(nKey, m_netgroupman);
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
if (info.IsValid()
&& vvTried[nKBucket][nKBucketPos] == -1) {
@@ -335,10 +331,7 @@ void AddrManImpl::Unserialize(Stream& s_)
// If the bucket count and asmap checksum haven't changed, then attempt
// to restore the entries to the buckets/positions they were in before
// serialization.
- uint256 supplied_asmap_checksum;
- if (m_asmap.size() != 0) {
- supplied_asmap_checksum = SerializeHash(m_asmap);
- }
+ uint256 supplied_asmap_checksum{m_netgroupman.GetAsmapChecksum()};
uint256 serialized_asmap_checksum;
if (format >= Format::V2_ASMAP) {
s >> serialized_asmap_checksum;
@@ -371,7 +364,7 @@ void AddrManImpl::Unserialize(Stream& s_)
} else {
// In case the new table data cannot be used (bucket count wrong or new asmap),
// try to give them a reference based on their primary source address.
- bucket = info.GetNewBucket(nKey, m_asmap);
+ bucket = info.GetNewBucket(nKey, m_netgroupman);
bucket_position = info.GetBucketPosition(nKey, true, bucket);
if (vvNew[bucket][bucket_position] == -1) {
vvNew[bucket][bucket_position] = entry_index;
@@ -495,7 +488,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
AssertLockHeld(cs);
// remove the entry from all new buckets
- const int start_bucket{info.GetNewBucket(nKey, m_asmap)};
+ const int start_bucket{info.GetNewBucket(nKey, m_netgroupman)};
for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
const int pos{info.GetBucketPosition(nKey, true, bucket)};
@@ -510,7 +503,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
assert(info.nRefCount == 0);
// which tried bucket to move the entry to
- int nKBucket = info.GetTriedBucket(nKey, m_asmap);
+ int nKBucket = info.GetTriedBucket(nKey, m_netgroupman);
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
// first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
@@ -526,7 +519,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
nTried--;
// find which new bucket it belongs to
- int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
+ int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman);
int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
ClearNew(nUBucket, nUBucketPos);
assert(vvNew[nUBucket][nUBucketPos] == -1);
@@ -594,7 +587,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
nNew++;
}
- int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
+ int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
if (vvNew[nUBucket][nUBucketPos] != nId) {
@@ -610,7 +603,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
pinfo->nRefCount++;
vvNew[nUBucket][nUBucketPos] = nId;
LogPrint(BCLog::ADDRMAN, "Added %s mapped to AS%i to new[%i][%i]\n",
- addr.ToString(), addr.GetMappedAS(m_asmap), nUBucket, nUBucketPos);
+ addr.ToString(), m_netgroupman.GetMappedAS(addr), nUBucket, nUBucketPos);
} else {
if (pinfo->nRefCount == 0) {
Delete(nId);
@@ -650,7 +643,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
// which tried bucket to move the entry to
- int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
+ int tried_bucket = info.GetTriedBucket(nKey, m_netgroupman);
int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
// Will moving this address into tried evict another entry?
@@ -669,7 +662,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
// move nId to the tried tables
MakeTried(info, nId);
LogPrint(BCLog::ADDRMAN, "Moved %s mapped to AS%i to tried[%i][%i]\n",
- addr.ToString(), addr.GetMappedAS(m_asmap), tried_bucket, tried_bucket_pos);
+ addr.ToString(), m_netgroupman.GetMappedAS(addr), tried_bucket, tried_bucket_pos);
return true;
}
}
@@ -863,7 +856,7 @@ void AddrManImpl::ResolveCollisions_()
AddrInfo& info_new = mapInfo[id_new];
// Which tried bucket to move the entry to.
- int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
+ int tried_bucket = info_new.GetTriedBucket(nKey, m_netgroupman);
int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
if (!info_new.IsValid()) { // id_new may no longer map to a valid address
erase_collision = true;
@@ -929,7 +922,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
const AddrInfo& newInfo = mapInfo[id_new];
// which tried bucket to move the entry to
- int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
+ int tried_bucket = newInfo.GetTriedBucket(nKey, m_netgroupman);
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
@@ -945,13 +938,13 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& ad
if (!addr_info) return std::nullopt;
if(addr_info->fInTried) {
- int bucket{addr_info->GetTriedBucket(nKey, m_asmap)};
+ int bucket{addr_info->GetTriedBucket(nKey, m_netgroupman)};
return AddressPosition(/*tried_in=*/true,
/*multiplicity_in=*/1,
/*bucket_in=*/bucket,
/*position_in=*/addr_info->GetBucketPosition(nKey, false, bucket));
} else {
- int bucket{addr_info->GetNewBucket(nKey, m_asmap)};
+ int bucket{addr_info->GetNewBucket(nKey, m_netgroupman)};
return AddressPosition(/*tried_in=*/false,
/*multiplicity_in=*/addr_info->nRefCount,
/*bucket_in=*/bucket,
@@ -1026,7 +1019,7 @@ int AddrManImpl::CheckAddrman() const
if (!setTried.count(vvTried[n][i]))
return -11;
const auto it{mapInfo.find(vvTried[n][i])};
- if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_asmap) != n) {
+ if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_netgroupman) != n) {
return -17;
}
if (it->second.GetBucketPosition(nKey, false, n) != i) {
@@ -1154,13 +1147,8 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& add
return entry;
}
-const std::vector<bool>& AddrManImpl::GetAsmap() const
-{
- return m_asmap;
-}
-
-AddrMan::AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
- : m_impl(std::make_unique<AddrManImpl>(std::move(asmap), deterministic, consistency_check_ratio)) {}
+AddrMan::AddrMan(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)
+ : m_impl(std::make_unique<AddrManImpl>(netgroupman, deterministic, consistency_check_ratio)) {}
AddrMan::~AddrMan() = default;
@@ -1235,11 +1223,6 @@ void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
m_impl->SetServices(addr, nServices);
}
-const std::vector<bool>& AddrMan::GetAsmap() const
-{
- return m_impl->GetAsmap();
-}
-
std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr)
{
return m_impl->FindAddressEntry(addr);
diff --git a/src/addrman.h b/src/addrman.h
index 472282833b..a0063e8a9c 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -7,6 +7,7 @@
#define BITCOIN_ADDRMAN_H
#include <netaddress.h>
+#include <netgroup.h>
#include <protocol.h>
#include <streams.h>
#include <timedata.h>
@@ -88,7 +89,7 @@ protected:
const std::unique_ptr<AddrManImpl> m_impl;
public:
- explicit AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio);
+ explicit AddrMan(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio);
~AddrMan();
@@ -172,8 +173,6 @@ public:
//! Update an entry's service bits.
void SetServices(const CService& addr, ServiceFlags nServices);
- const std::vector<bool>& GetAsmap() const;
-
/** Test-only function
* Find the address record in AddrMan and return information about its
* position.
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 5e76f72342..9d98cdde54 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -76,15 +76,15 @@ public:
}
//! Calculate in which "tried" bucket this entry belongs
- int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
+ int GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const;
//! Calculate in which "new" bucket this entry belongs, given a certain source
- int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
+ int GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const;
//! Calculate in which "new" bucket this entry belongs, using its default source
- int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
+ int GetNewBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{
- return GetNewBucket(nKey, source, asmap);
+ return GetNewBucket(nKey, source, netgroupman);
}
//! Calculate in which position of a bucket to store this entry.
@@ -100,7 +100,7 @@ public:
class AddrManImpl
{
public:
- AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio);
+ AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio);
~AddrManImpl();
@@ -140,8 +140,6 @@ public:
std::optional<AddressPosition> FindAddressEntry(const CAddress& addr)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- const std::vector<bool>& GetAsmap() const;
-
friend class AddrManDeterministic;
private:
@@ -212,21 +210,8 @@ private:
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
const int32_t m_consistency_check_ratio;
- // Compressed IP->ASN mapping, loaded from a file when a node starts.
- // Should be always empty if no file was provided.
- // This mapping is then used for bucketing nodes in Addrman.
- //
- // If asmap is provided, nodes will be bucketed by
- // AS they belong to, in order to make impossible for a node
- // to connect to several nodes hosted in a single AS.
- // This is done in response to Erebus attack, but also to generally
- // diversify the connections every node creates,
- // especially useful when a large fraction of nodes
- // operate under a couple of cloud providers.
- //
- // If a new asmap was provided, the existing records
- // would be re-bucketed accordingly.
- const std::vector<bool> m_asmap;
+ /** Reference to the netgroup manager. netgroupman must be constructed before addrman and destructed after. */
+ const NetGroupManager& m_netgroupman;
//! Find an entry.
AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index f7f62dfc68..e614102de3 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -146,13 +146,21 @@ double base_uint<BITS>::getdouble() const
template <unsigned int BITS>
std::string base_uint<BITS>::GetHex() const
{
- return ArithToUint256(*this).GetHex();
+ base_blob<BITS> b;
+ for (int x = 0; x < this->WIDTH; ++x) {
+ WriteLE32(b.begin() + x*4, this->pn[x]);
+ }
+ return b.GetHex();
}
template <unsigned int BITS>
void base_uint<BITS>::SetHex(const char* psz)
{
- *this = UintToArith256(uint256S(psz));
+ base_blob<BITS> b;
+ b.SetHex(psz);
+ for (int x = 0; x < this->WIDTH; ++x) {
+ this->pn[x] = ReadLE32(b.begin() + x*4);
+ }
}
template <unsigned int BITS>
@@ -164,7 +172,7 @@ void base_uint<BITS>::SetHex(const std::string& str)
template <unsigned int BITS>
std::string base_uint<BITS>::ToString() const
{
- return (GetHex());
+ return GetHex();
}
template <unsigned int BITS>
@@ -183,20 +191,7 @@ unsigned int base_uint<BITS>::bits() const
}
// Explicit instantiations for base_uint<256>
-template base_uint<256>::base_uint(const std::string&);
-template base_uint<256>& base_uint<256>::operator<<=(unsigned int);
-template base_uint<256>& base_uint<256>::operator>>=(unsigned int);
-template base_uint<256>& base_uint<256>::operator*=(uint32_t b32);
-template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b);
-template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b);
-template int base_uint<256>::CompareTo(const base_uint<256>&) const;
-template bool base_uint<256>::EqualTo(uint64_t) const;
-template double base_uint<256>::getdouble() const;
-template std::string base_uint<256>::GetHex() const;
-template std::string base_uint<256>::ToString() const;
-template void base_uint<256>::SetHex(const char*);
-template void base_uint<256>::SetHex(const std::string&);
-template unsigned int base_uint<256>::bits() const;
+template class base_uint<256>;
// This implementation directly uses shifts instead of going
// through an intermediate MPI representation.
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index a0a0429c2a..b7b3b3a285 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -24,22 +24,19 @@ template<unsigned int BITS>
class base_uint
{
protected:
+ static_assert(BITS / 32 > 0 && BITS % 32 == 0, "Template parameter BITS must be a positive multiple of 32.");
static constexpr int WIDTH = BITS / 32;
uint32_t pn[WIDTH];
public:
base_uint()
{
- static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
-
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
base_uint(const base_uint& b)
{
- static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
-
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
@@ -53,8 +50,6 @@ public:
base_uint(uint64_t b)
{
- static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
-
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
@@ -284,4 +279,6 @@ public:
uint256 ArithToUint256(const arith_uint256 &);
arith_uint256 UintToArith256(const uint256 &);
+extern template class base_uint<256>;
+
#endif // BITCOIN_ARITH_UINT256_H
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index 34bc4380dd..76300f4db8 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -4,6 +4,7 @@
#include <addrman.h>
#include <bench/bench.h>
+#include <netgroup.h>
#include <random.h>
#include <util/check.h>
#include <util/time.h>
@@ -16,7 +17,7 @@
static constexpr size_t NUM_SOURCES = 64;
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
-static const std::vector<bool> EMPTY_ASMAP;
+static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
static std::vector<CAddress> g_sources;
@@ -77,14 +78,14 @@ static void AddrManAdd(benchmark::Bench& bench)
CreateAddresses();
bench.run([&] {
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman);
});
}
static void AddrManSelect(benchmark::Bench& bench)
{
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman);
@@ -96,7 +97,7 @@ static void AddrManSelect(benchmark::Bench& bench)
static void AddrManGetAddr(benchmark::Bench& bench)
{
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman);
@@ -125,7 +126,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
//
// This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
// AddrMan::Good() will still be noticeable.
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman);
markSomeAsGood(addrman);
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index 2143bcf950..e6fc8d21f4 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -40,7 +40,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
{
TestBlockAndIndex data;
bench.run([&] {
- auto univalue = blockToJSON(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);
});
}
@@ -50,7 +50,7 @@ BENCHMARK(BlockToJsonVerbose);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{
TestBlockAndIndex data;
- auto univalue = blockToJSON(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_loading.cpp b/src/bench/wallet_loading.cpp
new file mode 100644
index 0000000000..38d3460001
--- /dev/null
+++ b/src/bench/wallet_loading.cpp
@@ -0,0 +1,83 @@
+// Copyright (c) 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 <bench/bench.h>
+#include <interfaces/chain.h>
+#include <node/context.h>
+#include <test/util/mining.h>
+#include <test/util/setup_common.h>
+#include <test/util/wallet.h>
+#include <util/translation.h>
+#include <validationinterface.h>
+#include <wallet/context.h>
+#include <wallet/receive.h>
+#include <wallet/wallet.h>
+
+#include <optional>
+
+using wallet::CWallet;
+using wallet::DatabaseOptions;
+using wallet::DatabaseStatus;
+using wallet::ISMINE_SPENDABLE;
+using wallet::MakeWalletDatabase;
+using wallet::WALLET_FLAG_DESCRIPTORS;
+using wallet::WalletContext;
+
+static const std::shared_ptr<CWallet> BenchLoadWallet(WalletContext& context, DatabaseOptions& options)
+{
+ DatabaseStatus status;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ auto database = MakeWalletDatabase("", options, status, error);
+ assert(database);
+ auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings);
+ NotifyWalletLoaded(context, wallet);
+ if (context.chain) {
+ wallet->postInitProcess();
+ }
+ return wallet;
+}
+
+static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)
+{
+ SyncWithValidationInterfaceQueue();
+ wallet->m_chain_notifications_handler.reset();
+ UnloadWallet(std::move(wallet));
+}
+
+static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet)
+{
+ const auto test_setup = MakeNoLogFileContext<TestingSetup>();
+
+ WalletContext context;
+ context.args = &test_setup->m_args;
+ context.chain = test_setup->m_node.chain.get();
+
+ // Setup the wallet
+ // Loading the wallet will also create it
+ DatabaseOptions options;
+ if (!legacy_wallet) options.create_flags = WALLET_FLAG_DESCRIPTORS;
+ auto wallet = BenchLoadWallet(context, options);
+
+ // Generate a bunch of transactions and addresses to put into the wallet
+ for (int i = 0; i < 5000; ++i) {
+ generatetoaddress(test_setup->m_node, getnewaddress(*wallet));
+ }
+
+ // reload the wallet for the actual benchmark
+ BenchUnloadWallet(std::move(wallet));
+
+ bench.minEpochIterations(10).run([&] {
+ wallet = BenchLoadWallet(context, options);
+
+ // Cleanup
+ BenchUnloadWallet(std::move(wallet));
+ });
+}
+
+static void WalletLoadingLegacy(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/true); }
+static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); }
+
+BENCHMARK(WalletLoadingLegacy);
+BENCHMARK(WalletLoadingDescriptors);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 6925a4c8c6..dea46693bc 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -1055,7 +1055,9 @@ static void ParseGetInfoResult(UniValue& result)
result_string += "\n";
}
- result_string += strprintf("%sWarnings:%s %s", YELLOW, RESET, result["warnings"].getValStr());
+ const std::string warnings{result["warnings"].getValStr()};
+ result_string += strprintf("%sWarnings:%s %s", YELLOW, RESET, warnings.empty() ? "(none)" : warnings);
+
result.setStr(result_string);
}
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index cde543e68c..196f81ea16 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -586,17 +586,9 @@ std::string SHA256AutoDetect()
bool have_sse4 = false;
bool have_xsave = false;
bool have_avx = false;
- bool have_avx2 = false;
- bool have_x86_shani = false;
- bool enabled_avx = false;
-
- (void)AVXEnabled;
- (void)have_sse4;
- (void)have_avx;
- (void)have_xsave;
- (void)have_avx2;
- (void)have_x86_shani;
- (void)enabled_avx;
+ [[maybe_unused]] bool have_avx2 = false;
+ [[maybe_unused]] bool have_x86_shani = false;
+ [[maybe_unused]] bool enabled_avx = false;
uint32_t eax, ebx, ecx, edx;
GetCPUID(1, 0, eax, ebx, ecx, edx);
@@ -641,7 +633,7 @@ std::string SHA256AutoDetect()
ret += ",avx2(8way)";
}
#endif
-#endif
+#endif // defined(USE_ASM) && defined(HAVE_GETCPUID)
#if defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
bool have_arm_shani = false;
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index b0ea80ea1a..50a601c684 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -227,7 +227,7 @@ const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
{
std::vector<uint8_t> ret(OBFUSCATE_KEY_NUM_BYTES);
- GetRandBytes(ret.data(), OBFUSCATE_KEY_NUM_BYTES);
+ GetRandBytes(ret);
return ret;
}
diff --git a/src/init.cpp b/src/init.cpp
index 86e6ec4451..aa1cff761e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -33,6 +33,7 @@
#include <net_permissions.h>
#include <net_processing.h>
#include <netbase.h>
+#include <netgroup.h>
#include <node/blockstorage.h>
#include <node/caches.h>
#include <node/chainstate.h>
@@ -109,7 +110,6 @@ using node::LoadChainstate;
using node::NodeContext;
using node::ThreadImport;
using node::VerifyLoadedChainstate;
-using node::fHavePruned;
using node::fPruneMode;
using node::fReindex;
using node::nPruneTarget;
@@ -240,6 +240,7 @@ void Shutdown(NodeContext& node)
node.connman.reset();
node.banman.reset();
node.addrman.reset();
+ node.netgroupman.reset();
if (node.mempool && node.mempool->IsLoaded() && node.args->GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool(*node.mempool);
@@ -660,7 +661,8 @@ void InitParameterInteraction(ArgsManager& args)
LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__);
}
- if (args.IsArgSet("-proxy")) {
+ std::string proxy_arg = args.GetArg("-proxy", "");
+ if (proxy_arg != "" && proxy_arg != "0") {
// to protect privacy, do not listen by default if a default proxy server is specified
if (args.SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
@@ -1228,8 +1230,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)};
{
- // Initialize addrman
- assert(!node.addrman);
// Read asmap file if configured
std::vector<bool> asmap;
@@ -1253,8 +1253,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("Using /16 prefix for IP bucketing\n");
}
+ // Initialize netgroup manager
+ assert(!node.netgroupman);
+ node.netgroupman = std::make_unique<NetGroupManager>(std::move(asmap));
+
+ // Initialize addrman
+ assert(!node.addrman);
uiInterface.InitMessage(_("Loading P2P addresses…").translated);
- if (const auto error{LoadAddrman(asmap, args, node.addrman)}) {
+ if (const auto error{LoadAddrman(*node.netgroupman, args, node.addrman)}) {
return InitError(*error);
}
}
@@ -1262,7 +1268,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
assert(!node.banman);
node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetIntArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
- node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman, args.GetBoolArg("-networkactive", true));
+ node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()),
+ GetRand(std::numeric_limits<uint64_t>::max()),
+ *node.addrman, *node.netgroupman, args.GetBoolArg("-networkactive", true));
assert(!node.fee_estimator);
// Don't initialize fee estimation with old data if we don't relay transactions,
@@ -1480,7 +1488,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
try {
uiInterface.InitMessage(_("Verifying blocks…").translated);
auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (fHavePruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
+ if (chainman.m_blockman.m_have_pruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
MIN_BLOCKS_TO_KEEP);
}
@@ -1664,9 +1672,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime();
tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip());
}
- if (tip_info && ::pindexBestHeader) {
- tip_info->header_height = ::pindexBestHeader->nHeight;
- tip_info->header_time = ::pindexBestHeader->GetBlockTime();
+ if (tip_info && chainman.m_best_header) {
+ tip_info->header_height = chainman.m_best_header->nHeight;
+ tip_info->header_time = chainman.m_best_header->GetBlockTime();
}
}
LogPrintf("nBestHeight = %d\n", chain_active_height);
diff --git a/src/key.cpp b/src/key.cpp
index 354bd097ce..d1d521f97d 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -159,7 +159,7 @@ bool CKey::Check(const unsigned char *vch) {
void CKey::MakeNewKey(bool fCompressedIn) {
do {
- GetStrongRandBytes(keydata.data(), keydata.size());
+ GetStrongRandBytes(keydata);
} while (!Check(keydata.data()));
fValid = true;
fCompressed = fCompressedIn;
@@ -244,7 +244,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
}
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
- GetRandBytes(rnd, sizeof(rnd));
+ GetRandBytes(rnd);
uint256 hash;
CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
std::vector<unsigned char> vchSig;
@@ -288,7 +288,7 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false;
}
- bool ret = secp256k1_schnorrsig_sign(secp256k1_context_sign, sig.data(), hash.data(), &keypair, aux.data());
+ bool ret = secp256k1_schnorrsig_sign32(secp256k1_context_sign, sig.data(), hash.data(), &keypair, aux.data());
if (ret) {
// Additional verification step to prevent using a potentially corrupted signature
secp256k1_xonly_pubkey pubkey_verify;
@@ -397,7 +397,7 @@ void ECC_Start() {
{
// Pass in a random blinding seed to the secp256k1 context.
std::vector<unsigned char, secure_allocator<unsigned char>> vseed(32);
- GetRandBytes(vseed.data(), 32);
+ GetRandBytes(vseed);
bool ret = secp256k1_context_randomize(ctx, vseed.data());
assert(ret);
}
diff --git a/src/logging/timer.h b/src/logging/timer.h
index fc5307bc62..d954e46301 100644
--- a/src/logging/timer.h
+++ b/src/logging/timer.h
@@ -97,13 +97,13 @@ private:
#define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category) \
- BCLog::Timer<std::chrono::microseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category)
+ BCLog::Timer<std::chrono::microseconds> UNIQUE_NAME(logging_timer)(__func__, end_msg, log_category)
#define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category) \
- BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category)
+ BCLog::Timer<std::chrono::milliseconds> UNIQUE_NAME(logging_timer)(__func__, end_msg, log_category)
#define LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE(end_msg, log_category) \
- BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category, /* msg_on_completion=*/false)
+ BCLog::Timer<std::chrono::milliseconds> UNIQUE_NAME(logging_timer)(__func__, end_msg, log_category, /* msg_on_completion=*/false)
#define LOG_TIME_SECONDS(end_msg) \
- BCLog::Timer<std::chrono::seconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg)
+ BCLog::Timer<std::chrono::seconds> UNIQUE_NAME(logging_timer)(__func__, end_msg)
#endif // BITCOIN_LOGGING_TIMER_H
diff --git a/src/net.cpp b/src/net.cpp
index 602d56ab98..77fa06ce26 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1190,7 +1190,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
// According to the internet TCP_NODELAY is not carried into accepted sockets
// on all platforms. Set it again here just to be sure.
- SetSocketNoDelay(sock->Get());
+ const int on{1};
+ if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {
+ LogPrint(BCLog::NET, "connection from %s: unable to set TCP_NODELAY, continuing anyway\n",
+ addr.ToString());
+ }
// Don't accept connections from banned peers.
bool banned = m_banman && m_banman->IsBanned(addr);
@@ -1997,7 +2001,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
- setConnected.insert(pnode->addr.GetGroup(addrman.GetAsmap()));
+ setConnected.insert(m_netgroupman.GetGroup(pnode->addr));
} // no default case, so the compiler can warn about missing cases
}
}
@@ -2071,7 +2075,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
m_anchors.pop_back();
if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) ||
!HasAllDesirableServiceFlags(addr.nServices) ||
- setConnected.count(addr.GetGroup(addrman.GetAsmap()))) continue;
+ setConnected.count(m_netgroupman.GetGroup(addr))) continue;
addrConnect = addr;
LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToString());
break;
@@ -2112,7 +2116,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
// Require outbound connections, other than feelers, to be to distinct network groups
- if (!fFeeler && setConnected.count(addr.GetGroup(addrman.GetAsmap()))) {
+ if (!fFeeler && setConnected.count(m_netgroupman.GetGroup(addr))) {
break;
}
@@ -2395,17 +2399,26 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
- setsockopt(sock->Get(), SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int));
+ if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
+ strError = strprintf(Untranslated("Error setting SO_REUSEADDR on socket: %s, continuing anyway"), NetworkErrorString(WSAGetLastError()));
+ LogPrintf("%s\n", strError.original);
+ }
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
#ifdef IPV6_V6ONLY
- setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int));
+ if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
+ strError = strprintf(Untranslated("Error setting IPV6_V6ONLY on socket: %s, continuing anyway"), NetworkErrorString(WSAGetLastError()));
+ LogPrintf("%s\n", strError.original);
+ }
#endif
#ifdef WIN32
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
- setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
+ if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR) {
+ strError = strprintf(Untranslated("Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway"), NetworkErrorString(WSAGetLastError()));
+ LogPrintf("%s\n", strError.original);
+ }
#endif
}
@@ -2499,8 +2512,12 @@ void CConnman::SetNetworkActive(bool active)
}
}
-CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in, bool network_active)
- : addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
+CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in,
+ const NetGroupManager& netgroupman, bool network_active)
+ : addrman(addrman_in)
+ , m_netgroupman{netgroupman}
+ , nSeed0(nSeed0In)
+ , nSeed1(nSeed1In)
{
SetTryNewOutboundPeer(false);
@@ -2859,7 +2876,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
for (CNode* pnode : m_nodes) {
vstats.emplace_back();
pnode->CopyStats(vstats.back());
- vstats.back().m_mapped_as = pnode->addr.GetMappedAS(addrman.GetAsmap());
+ vstats.back().m_mapped_as = m_netgroupman.GetMappedAS(pnode->addr);
}
}
@@ -3092,9 +3109,9 @@ CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
return CSipHasher(nSeed0, nSeed1).Write(id);
}
-uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
+uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& address) const
{
- std::vector<unsigned char> vchNetGroup(ad.GetGroup(addrman.GetAsmap()));
+ std::vector<unsigned char> vchNetGroup(m_netgroupman.GetGroup(address));
return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
}
diff --git a/src/net.h b/src/net.h
index 1bc011c748..b253a90442 100644
--- a/src/net.h
+++ b/src/net.h
@@ -17,6 +17,7 @@
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
+#include <netgroup.h>
#include <policy/feerate.h>
#include <protocol.h>
#include <random.h>
@@ -787,7 +788,9 @@ public:
m_onion_binds = connOptions.onion_binds;
}
- CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, bool network_active = true);
+ CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman,
+ bool network_active = true);
+
~CConnman();
bool Start(CScheduler& scheduler, const Options& options);
@@ -1085,6 +1088,7 @@ private:
std::atomic<bool> fNetworkActive{true};
bool fAddressesInitialized{false};
AddrMan& addrman;
+ const NetGroupManager& m_netgroupman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
Mutex m_addr_fetches_mutex;
std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index ba72a11ec9..46b4d2e3df 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1499,9 +1499,9 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
{
AssertLockHeld(cs_main);
if (m_chainman.ActiveChain().Contains(pindex)) return true;
- return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
- (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
- (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
+ return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (m_chainman.m_best_header != nullptr) &&
+ (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
+ (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
}
std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index)
@@ -1896,7 +1896,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
// disconnect node in case we have reached the outbound limit for serving historical blocks
if (m_connman.OutboundTargetReached(true) &&
- (((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
+ (((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
!pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
) {
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
@@ -2173,12 +2173,12 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// nUnconnectingHeaders gets reset back to 0.
if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
- headers[0].GetHash().ToString(),
- headers[0].hashPrevBlock.ToString(),
- pindexBestHeader->nHeight,
- pfrom.GetId(), nodestate->nUnconnectingHeaders);
+ headers[0].GetHash().ToString(),
+ headers[0].hashPrevBlock.ToString(),
+ m_chainman.m_best_header->nHeight,
+ pfrom.GetId(), nodestate->nUnconnectingHeaders);
// Set hashLastUnknownBlock for this peer, so that if we
// eventually get the headers - even from a different peer -
// we can use this peer to download.
@@ -2235,7 +2235,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
if (nCount == MAX_HEADERS_RESULTS) {
// Headers message had its maximum size; the peer may have more headers.
- // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue
+ // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or m_chainman.m_best_header, continue
// from there instead.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
@@ -3102,8 +3102,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (best_block != nullptr) {
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), *best_block));
- LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId());
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *best_block));
+ LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", m_chainman.m_best_header->nHeight, best_block->ToString(), pfrom.GetId());
}
return;
@@ -3549,7 +3549,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!m_chainman.ActiveChainstate().IsInitialBlockDownload())
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
return;
}
@@ -4472,7 +4472,7 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::mic
if (pingSend) {
uint64_t nonce = 0;
while (nonce == 0) {
- GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
+ GetRandBytes({(unsigned char*)&nonce, sizeof(nonce)});
}
peer.m_ping_queued = false;
peer.m_ping_start = now;
@@ -4670,28 +4670,29 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
CNodeState &state = *State(pto->GetId());
// Start block sync
- if (pindexBestHeader == nullptr)
- pindexBestHeader = m_chainman.ActiveChain().Tip();
+ if (m_chainman.m_best_header == nullptr) {
+ m_chainman.m_best_header = m_chainman.ActiveChain().Tip();
+ }
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
- if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
+ if ((nSyncStarted == 0 && fFetch) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
state.fSyncStarted = true;
state.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE +
(
// Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling
// to maintain precision
std::chrono::microseconds{HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER} *
- (GetAdjustedTime() - pindexBestHeader->GetBlockTime()) / consensusParams.nPowTargetSpacing
+ (GetAdjustedTime() - m_chainman.m_best_header->GetBlockTime()) / consensusParams.nPowTargetSpacing
);
nSyncStarted++;
- const CBlockIndex *pindexStart = pindexBestHeader;
+ const CBlockIndex* pindexStart = m_chainman.m_best_header;
/* If possible, start at the block preceding the currently
best known header. This ensures that we always get a
non-empty list of headers back as long as the peer
is up-to-date. With a non-empty response, we can initialise
the peer's known best block. This wouldn't be possible
- if we requested starting at pindexBestHeader and
+ if we requested starting at m_chainman.m_best_header and
got back an empty response. */
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
@@ -5016,7 +5017,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Check for headers sync timeouts
if (state.fSyncStarted && state.m_headers_sync_timeout < std::chrono::microseconds::max()) {
// Detect whether this is a stalling initial-headers-sync peer
- if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) {
+ if (m_chainman.m_best_header->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) {
if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) {
// Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer,
// and we have others we could be using instead.
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index f7640329f8..bc1915aad9 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -10,7 +10,6 @@
#include <hash.h>
#include <prevector.h>
#include <tinyformat.h>
-#include <util/asmap.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -722,107 +721,6 @@ Network CNetAddr::GetNetClass() const
return m_net;
}
-uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
- uint32_t net_class = GetNetClass();
- if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
- return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
- }
- std::vector<bool> ip_bits(128);
- if (HasLinkedIPv4()) {
- // For lookup, treat as if it was just an IPv4 address (IPV4_IN_IPV6_PREFIX + IPv4 bits)
- for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
- for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
- ip_bits[byte_i * 8 + bit_i] = (IPV4_IN_IPV6_PREFIX[byte_i] >> (7 - bit_i)) & 1;
- }
- }
- uint32_t ipv4 = GetLinkedIPv4();
- for (int i = 0; i < 32; ++i) {
- ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
- }
- } else {
- // Use all 128 bits of the IPv6 address otherwise
- assert(IsIPv6());
- for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
- uint8_t cur_byte = m_addr[byte_i];
- for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
- ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
- }
- }
- }
- uint32_t mapped_as = Interpret(asmap, ip_bits);
- return mapped_as;
-}
-
-/**
- * Get the canonical identifier of our network group
- *
- * The groups are assigned in a way where it should be costly for an attacker to
- * obtain addresses with many different group identifiers, even if it is cheap
- * to obtain addresses with the same identifier.
- *
- * @note No two connections will be attempted to addresses with the same network
- * group.
- */
-std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) const
-{
- std::vector<unsigned char> vchRet;
- uint32_t net_class = GetNetClass();
- // If non-empty asmap is supplied and the address is IPv4/IPv6,
- // return ASN to be used for bucketing.
- uint32_t asn = GetMappedAS(asmap);
- if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
- vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
- for (int i = 0; i < 4; i++) {
- vchRet.push_back((asn >> (8 * i)) & 0xFF);
- }
- return vchRet;
- }
-
- vchRet.push_back(net_class);
- int nBits{0};
-
- if (IsLocal()) {
- // all local addresses belong to the same group
- } else if (IsInternal()) {
- // all internal-usage addresses get their own group
- nBits = ADDR_INTERNAL_SIZE * 8;
- } else if (!IsRoutable()) {
- // all other unroutable addresses belong to the same group
- } else if (HasLinkedIPv4()) {
- // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
- uint32_t ipv4 = GetLinkedIPv4();
- vchRet.push_back((ipv4 >> 24) & 0xFF);
- vchRet.push_back((ipv4 >> 16) & 0xFF);
- return vchRet;
- } else if (IsTor() || IsI2P()) {
- nBits = 4;
- } else if (IsCJDNS()) {
- // Treat in the same way as Tor and I2P because the address in all of
- // them is "random" bytes (derived from a public key). However in CJDNS
- // the first byte is a constant 0xfc, so the random bytes come after it.
- // Thus skip the constant 8 bits at the start.
- nBits = 12;
- } else if (IsHeNet()) {
- // for he.net, use /36 groups
- nBits = 36;
- } else {
- // for the rest of the IPv6 network, use /32 groups
- nBits = 32;
- }
-
- // Push our address onto vchRet.
- const size_t num_bytes = nBits / 8;
- vchRet.insert(vchRet.end(), m_addr.begin(), m_addr.begin() + num_bytes);
- nBits %= 8;
- // ...for the last byte, push nBits and for the rest of the byte push 1's
- if (nBits > 0) {
- assert(num_bytes < m_addr.size());
- vchRet.push_back(m_addr[num_bytes] | ((1 << (8 - nBits)) - 1));
- }
-
- return vchRet;
-}
-
std::vector<unsigned char> CNetAddr::GetAddrBytes() const
{
if (IsAddrV1Compatible()) {
diff --git a/src/netaddress.h b/src/netaddress.h
index 6d21dcd5cd..b9a8dc589a 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -202,12 +202,6 @@ public:
//! Whether this address has a linked IPv4 address (see GetLinkedIPv4()).
bool HasLinkedIPv4() const;
- // The AS on the BGP path to the node we use to diversify
- // peers in AddrMan bucketing based on the AS infrastructure.
- // The ip->AS mapping depends on how asmap is constructed.
- uint32_t GetMappedAS(const std::vector<bool>& asmap) const;
-
- std::vector<unsigned char> GetGroup(const std::vector<bool>& asmap) const;
std::vector<unsigned char> GetAddrBytes() const;
int GetReachabilityFrom(const CNetAddr* paddrPartner = nullptr) const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 9a0b800565..9557297df1 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -305,7 +305,7 @@ enum class IntrRecvError {
*
* @see This function can be interrupted by calling InterruptSocks5(bool).
* Sockets can be made non-blocking with SetSocketNonBlocking(const
- * SOCKET&, bool).
+ * SOCKET&).
*/
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
{
@@ -499,10 +499,11 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
return nullptr;
}
+ auto sock = std::make_unique<Sock>(hSocket);
+
// Ensure that waiting for I/O on this socket won't result in undefined
// behavior.
- if (!IsSelectableSocket(hSocket)) {
- CloseSocket(hSocket);
+ if (!IsSelectableSocket(sock->Get())) {
LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
return nullptr;
}
@@ -511,19 +512,24 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
int set = 1;
// Set the no-sigpipe option on the socket for BSD systems, other UNIXes
// should use the MSG_NOSIGNAL flag for every send.
- setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
+ if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)) == SOCKET_ERROR) {
+ LogPrintf("Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",
+ NetworkErrorString(WSAGetLastError()));
+ }
#endif
// Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
- SetSocketNoDelay(hSocket);
+ const int on{1};
+ if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {
+ LogPrint(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n");
+ }
// Set the non-blocking option on the socket.
- if (!SetSocketNonBlocking(hSocket, true)) {
- CloseSocket(hSocket);
+ if (!SetSocketNonBlocking(sock->Get())) {
LogPrintf("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError()));
return nullptr;
}
- return std::make_unique<Sock>(hSocket);
+ return sock;
}
std::function<std::unique_ptr<Sock>(const CService&)> CreateSock = CreateSockTCP;
@@ -711,40 +717,21 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
return false;
}
-bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking)
+bool SetSocketNonBlocking(const SOCKET& hSocket)
{
- if (fNonBlocking) {
-#ifdef WIN32
- u_long nOne = 1;
- if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
-#else
- int fFlags = fcntl(hSocket, F_GETFL, 0);
- if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
-#endif
- return false;
- }
- } else {
#ifdef WIN32
- u_long nZero = 0;
- if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
+ u_long nOne = 1;
+ if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
#else
- int fFlags = fcntl(hSocket, F_GETFL, 0);
- if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
+ int fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
#endif
- return false;
- }
+ return false;
}
return true;
}
-bool SetSocketNoDelay(const SOCKET& hSocket)
-{
- int set = 1;
- int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
- return rc == 0;
-}
-
void InterruptSocks5(bool interrupt)
{
interruptSocks5Recv = interrupt;
diff --git a/src/netbase.h b/src/netbase.h
index f9e3872c16..bf7522210d 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -221,10 +221,8 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
*/
bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
-/** Disable or enable blocking-mode for a socket */
-bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
-/** Set the TCP_NODELAY flag on a socket */
-bool SetSocketNoDelay(const SOCKET& hSocket);
+/** Enable non-blocking mode for a socket */
+bool SetSocketNonBlocking(const SOCKET& hSocket);
void InterruptSocks5(bool interrupt);
/**
diff --git a/src/netgroup.cpp b/src/netgroup.cpp
new file mode 100644
index 0000000000..5f42d6c719
--- /dev/null
+++ b/src/netgroup.cpp
@@ -0,0 +1,111 @@
+// 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.
+
+#include <netgroup.h>
+
+#include <hash.h>
+#include <util/asmap.h>
+
+uint256 NetGroupManager::GetAsmapChecksum() const
+{
+ if (!m_asmap.size()) return {};
+
+ return SerializeHash(m_asmap);
+}
+
+std::vector<unsigned char> NetGroupManager::GetGroup(const CNetAddr& address) const
+{
+ std::vector<unsigned char> vchRet;
+ // If non-empty asmap is supplied and the address is IPv4/IPv6,
+ // return ASN to be used for bucketing.
+ uint32_t asn = GetMappedAS(address);
+ if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
+ vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
+ for (int i = 0; i < 4; i++) {
+ vchRet.push_back((asn >> (8 * i)) & 0xFF);
+ }
+ return vchRet;
+ }
+
+ vchRet.push_back(address.GetNetClass());
+ int nStartByte{0};
+ int nBits{0};
+
+ if (address.IsLocal()) {
+ // all local addresses belong to the same group
+ } else if (address.IsInternal()) {
+ // All internal-usage addresses get their own group.
+ // Skip over the INTERNAL_IN_IPV6_PREFIX returned by CAddress::GetAddrBytes().
+ nStartByte = INTERNAL_IN_IPV6_PREFIX.size();
+ nBits = ADDR_INTERNAL_SIZE * 8;
+ } else if (!address.IsRoutable()) {
+ // all other unroutable addresses belong to the same group
+ } else if (address.HasLinkedIPv4()) {
+ // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
+ uint32_t ipv4 = address.GetLinkedIPv4();
+ vchRet.push_back((ipv4 >> 24) & 0xFF);
+ vchRet.push_back((ipv4 >> 16) & 0xFF);
+ return vchRet;
+ } else if (address.IsTor() || address.IsI2P()) {
+ nBits = 4;
+ } else if (address.IsCJDNS()) {
+ // Treat in the same way as Tor and I2P because the address in all of
+ // them is "random" bytes (derived from a public key). However in CJDNS
+ // the first byte is a constant 0xfc, so the random bytes come after it.
+ // Thus skip the constant 8 bits at the start.
+ nBits = 12;
+ } else if (address.IsHeNet()) {
+ // for he.net, use /36 groups
+ nBits = 36;
+ } else {
+ // for the rest of the IPv6 network, use /32 groups
+ nBits = 32;
+ }
+
+ // Push our address onto vchRet.
+ auto addr_bytes = address.GetAddrBytes();
+ const size_t num_bytes = nBits / 8;
+ vchRet.insert(vchRet.end(), addr_bytes.begin() + nStartByte, addr_bytes.begin() + nStartByte + num_bytes);
+ nBits %= 8;
+ // ...for the last byte, push nBits and for the rest of the byte push 1's
+ if (nBits > 0) {
+ assert(num_bytes < addr_bytes.size());
+ vchRet.push_back(addr_bytes[num_bytes] | ((1 << (8 - nBits)) - 1));
+ }
+
+ return vchRet;
+}
+
+uint32_t NetGroupManager::GetMappedAS(const CNetAddr& address) const
+{
+ uint32_t net_class = address.GetNetClass();
+ if (m_asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
+ return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
+ }
+ std::vector<bool> ip_bits(128);
+ if (address.HasLinkedIPv4()) {
+ // For lookup, treat as if it was just an IPv4 address (IPV4_IN_IPV6_PREFIX + IPv4 bits)
+ for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
+ for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
+ ip_bits[byte_i * 8 + bit_i] = (IPV4_IN_IPV6_PREFIX[byte_i] >> (7 - bit_i)) & 1;
+ }
+ }
+ uint32_t ipv4 = address.GetLinkedIPv4();
+ for (int i = 0; i < 32; ++i) {
+ ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
+ }
+ } else {
+ // Use all 128 bits of the IPv6 address otherwise
+ assert(address.IsIPv6());
+ auto addr_bytes = address.GetAddrBytes();
+ for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
+ uint8_t cur_byte = addr_bytes[byte_i];
+ for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
+ ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
+ }
+ }
+ }
+ uint32_t mapped_as = Interpret(m_asmap, ip_bits);
+ return mapped_as;
+}
diff --git a/src/netgroup.h b/src/netgroup.h
new file mode 100644
index 0000000000..2dd63ec66b
--- /dev/null
+++ b/src/netgroup.h
@@ -0,0 +1,66 @@
+// 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_NETGROUP_H
+#define BITCOIN_NETGROUP_H
+
+#include <netaddress.h>
+#include <uint256.h>
+
+#include <vector>
+
+/**
+ * Netgroup manager
+ */
+class NetGroupManager {
+public:
+ explicit NetGroupManager(std::vector<bool> asmap)
+ : m_asmap{std::move(asmap)}
+ {}
+
+ /** Get a checksum identifying the asmap being used. */
+ uint256 GetAsmapChecksum() const;
+
+ /**
+ * Get the canonical identifier of the network group for address.
+ *
+ * The groups are assigned in a way where it should be costly for an attacker to
+ * obtain addresses with many different group identifiers, even if it is cheap
+ * to obtain addresses with the same identifier.
+ *
+ * @note No two connections will be attempted to addresses with the same network
+ * group.
+ */
+ std::vector<unsigned char> GetGroup(const CNetAddr& address) const;
+
+ /**
+ * Get the autonomous system on the BGP path to address.
+ *
+ * The ip->AS mapping depends on how asmap is constructed.
+ */
+ uint32_t GetMappedAS(const CNetAddr& address) const;
+
+private:
+ /** Compressed IP->ASN mapping, loaded from a file when a node starts.
+ *
+ * This mapping is then used for bucketing nodes in Addrman and for
+ * ensuring we connect to a diverse set of peers in Connman. The map is
+ * empty if no file was provided.
+ *
+ * If asmap is provided, nodes will be bucketed by AS they belong to, in
+ * order to make impossible for a node to connect to several nodes hosted
+ * in a single AS. This is done in response to Erebus attack, but also to
+ * generally diversify the connections every node creates, especially
+ * useful when a large fraction of nodes operate under a couple of cloud
+ * providers.
+ *
+ * If a new asmap is provided, the existing addrman records are
+ * re-bucketed.
+ *
+ * This is initialized in the constructor, const, and therefore is
+ * thread-safe. */
+ const std::vector<bool> m_asmap;
+};
+
+#endif // BITCOIN_NETGROUP_H
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 763fd29744..21cb0250d8 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -24,7 +24,6 @@
namespace node {
std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
-bool fHavePruned = false;
bool fPruneMode = false;
uint64_t nPruneTarget = 0;
@@ -81,7 +80,7 @@ const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const
return it == m_block_index.end() ? nullptr : &it->second;
}
-CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
+CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header)
{
AssertLockHeld(cs_main);
@@ -106,8 +105,9 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
- if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)
- pindexBestHeader = pindexNew;
+ if (best_header == nullptr || best_header->nChainWork < pindexNew->nChainWork) {
+ best_header = pindexNew;
+ }
m_dirty_blockindex.insert(pindexNew);
@@ -285,8 +285,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
if (pindex->pprev) {
pindex->BuildSkip();
}
- if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
- pindexBestHeader = pindex;
}
return true;
@@ -302,6 +300,8 @@ void BlockManager::Unload()
m_last_blockfile = 0;
m_dirty_blockindex.clear();
m_dirty_fileinfo.clear();
+
+ m_have_pruned = false;
}
bool BlockManager::WriteBlockIndexDB()
@@ -364,8 +364,8 @@ bool BlockManager::LoadBlockIndexDB()
}
// Check whether we have ever pruned block & undo files
- m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned);
- if (fHavePruned) {
+ m_block_tree_db->ReadFlag("prunedblockfiles", m_have_pruned);
+ if (m_have_pruned) {
LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n");
}
@@ -391,10 +391,10 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
return nullptr;
}
-bool IsBlockPruned(const CBlockIndex* pblockindex)
+bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex)
{
AssertLockHeld(::cs_main);
- return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
+ return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
}
// If we're using -prune with -reindex, then delete block files that will be ignored by the
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index a051e90808..11445aa22e 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -45,8 +45,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
extern std::atomic_bool fImporting;
extern std::atomic_bool fReindex;
/** Pruning-related variables and constants */
-/** True if any block files have ever been pruned. */
-extern bool fHavePruned;
/** True if we're running in -prune mode. */
extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */
@@ -147,7 +145,7 @@ public:
/** Clear all data members. */
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -171,15 +169,18 @@ public:
//! Returns last CBlockIndex* that is a checkpoint
const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /** True if any block files have ever been pruned. */
+ 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);
+
~BlockManager()
{
Unload();
}
};
-//! Check whether the block associated with this index entry is pruned or not.
-bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
-
void CleanupBlockRevFiles();
/** Open a block file (blk?????.dat) */
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index 9fdeb036fd..e43211402c 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -49,7 +49,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
- // LoadBlockIndex will load fHavePruned if we've ever removed a
+ // LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
// Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different!
@@ -65,7 +65,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
- if (fHavePruned && !fPruneMode) {
+ if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
}
diff --git a/src/node/context.cpp b/src/node/context.cpp
index 893c32f1bc..0b31c10f44 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -9,6 +9,7 @@
#include <interfaces/chain.h>
#include <net.h>
#include <net_processing.h>
+#include <netgroup.h>
#include <policy/fees.h>
#include <scheduler.h>
#include <txmempool.h>
diff --git a/src/node/context.h b/src/node/context.h
index 644c997531..91ba456219 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -18,6 +18,7 @@ class CConnman;
class CScheduler;
class CTxMemPool;
class ChainstateManager;
+class NetGroupManager;
class PeerManager;
namespace interfaces {
class Chain;
@@ -43,6 +44,7 @@ struct NodeContext {
std::unique_ptr<AddrMan> addrman;
std::unique_ptr<CConnman> connman;
std::unique_ptr<CTxMemPool> mempool;
+ std::unique_ptr<const NetGroupManager> netgroupman;
std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
std::unique_ptr<PeerManager> peerman;
std::unique_ptr<ChainstateManager> chainman;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 73d15652b1..954bd1c31d 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -212,9 +212,10 @@ public:
bool getHeaderTip(int& height, int64_t& block_time) override
{
LOCK(::cs_main);
- if (::pindexBestHeader) {
- height = ::pindexBestHeader->nHeight;
- block_time = ::pindexBestHeader->GetBlockTime();
+ auto best_header = chainman().m_best_header;
+ if (best_header) {
+ height = best_header->nHeight;
+ block_time = best_header->GetBlockTime();
return true;
}
return false;
@@ -644,7 +645,7 @@ public:
bool havePruned() override
{
LOCK(cs_main);
- return node::fHavePruned;
+ return m_node.chainman->m_blockman.m_have_pruned;
}
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
bool isInitialBlockDownload() override {
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index c6b884e40a..8cac28400f 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -95,6 +95,8 @@ static void RegisterMetaTypes()
qRegisterMetaType<std::function<void()>>("std::function<void()>");
qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
+
+ qRegisterMetaTypeStreamOperators<BitcoinUnit>("BitcoinUnit");
}
static QString GetLangTerritory()
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index a257e250e0..c92aecd095 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -14,6 +14,9 @@
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QLineEdit>
+#include <QVariant>
+
+#include <cassert>
/** QSpinBox that uses fixed-point numbers internally and uses our own
* formatting/parsing functions.
@@ -96,7 +99,7 @@ public:
setValue(val);
}
- void setDisplayUnit(int unit)
+ void setDisplayUnit(BitcoinUnit unit)
{
bool valid = false;
CAmount val = value(&valid);
@@ -122,7 +125,7 @@ public:
const QFontMetrics fm(fontMetrics());
int h = lineEdit()->minimumSizeHint().height();
- int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS));
+ int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnit::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS));
w += 2; // cursor blinking space
QStyleOptionSpinBox opt;
@@ -141,14 +144,13 @@ public:
opt.rect = rect();
- cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
- .expandedTo(QApplication::globalStrut());
+ cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
}
return cachedMinimumSizeHint;
}
private:
- int currentUnit{BitcoinUnits::BTC};
+ BitcoinUnit currentUnit{BitcoinUnit::BTC};
CAmount singleStep{CAmount(100000)}; // satoshis
mutable QSize cachedMinimumSizeHint;
bool m_allow_empty{true};
@@ -326,14 +328,14 @@ void BitcoinAmountField::unitChanged(int idx)
unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
// Determine new unit ID
- int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
-
- amount->setDisplayUnit(newUnit);
+ QVariant new_unit = unit->currentData(BitcoinUnits::UnitRole);
+ assert(new_unit.isValid());
+ amount->setDisplayUnit(new_unit.value<BitcoinUnit>());
}
-void BitcoinAmountField::setDisplayUnit(int newUnit)
+void BitcoinAmountField::setDisplayUnit(BitcoinUnit new_unit)
{
- unit->setValue(newUnit);
+ unit->setValue(QVariant::fromValue(new_unit));
}
void BitcoinAmountField::setSingleStep(const CAmount& step)
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index 366a6fc4b5..a40cd38332 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -6,6 +6,7 @@
#define BITCOIN_QT_BITCOINAMOUNTFIELD_H
#include <consensus/amount.h>
+#include <qt/bitcoinunits.h>
#include <QWidget>
@@ -52,7 +53,7 @@ public:
bool validate();
/** Change unit used to display amount. */
- void setDisplayUnit(int unit);
+ void setDisplayUnit(BitcoinUnit new_unit);
/** Make field empty and ready for new input. */
void clear();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 85e3c23085..81b0e711b2 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -41,6 +41,7 @@
#include <validation.h>
#include <QAction>
+#include <QActionGroup>
#include <QApplication>
#include <QComboBox>
#include <QCursor>
@@ -355,7 +356,7 @@ void BitcoinGUI::createActions()
showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME));
m_mask_values_action = new QAction(tr("&Mask values"), this);
- m_mask_values_action->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_M));
+ m_mask_values_action->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_M));
m_mask_values_action->setStatusTip(tr("Mask the values in the Overview tab"));
m_mask_values_action->setCheckable(true);
@@ -426,8 +427,8 @@ void BitcoinGUI::createActions()
}
#endif // ENABLE_WALLET
- connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole);
- connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow);
+ connect(new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole);
+ connect(new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow);
}
void BitcoinGUI::createMenuBar()
@@ -1244,7 +1245,7 @@ void BitcoinGUI::showEvent(QShowEvent *event)
}
#ifdef ENABLE_WALLET
-void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName)
+void BitcoinGUI::incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName)
{
// On new transaction, make an info balloon
QString msg = tr("Date: %1\n").arg(date) +
@@ -1495,11 +1496,10 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl
{
createContextMenu();
setToolTip(tr("Unit to show amounts in. Click to select another unit."));
- QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
+ QList<BitcoinUnit> units = BitcoinUnits::availableUnits();
int max_width = 0;
const QFontMetrics fm(font());
- for (const BitcoinUnits::Unit unit : units)
- {
+ for (const BitcoinUnit unit : units) {
max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit)));
}
setMinimumSize(max_width, 0);
@@ -1529,8 +1529,8 @@ void UnitDisplayStatusBarControl::changeEvent(QEvent* e)
void UnitDisplayStatusBarControl::createContextMenu()
{
menu = new QMenu(this);
- for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) {
- menu->addAction(BitcoinUnits::longName(u))->setData(QVariant(u));
+ for (const BitcoinUnit u : BitcoinUnits::availableUnits()) {
+ menu->addAction(BitcoinUnits::longName(u))->setData(QVariant::fromValue(u));
}
connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection);
}
@@ -1551,7 +1551,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel)
}
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
-void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits)
+void UnitDisplayStatusBarControl::updateDisplayUnit(BitcoinUnit newUnits)
{
setText(BitcoinUnits::longName(newUnits));
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index d2b29ba27b..5d9a978695 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -9,6 +9,7 @@
#include <config/bitcoin-config.h>
#endif
+#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsdialog.h>
@@ -260,7 +261,7 @@ public Q_SLOTS:
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
/** Show incoming transaction notification for new transactions. */
- void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName);
+ void incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName);
#endif // ENABLE_WALLET
private:
@@ -341,7 +342,7 @@ private:
private Q_SLOTS:
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
- void updateDisplayUnit(int newUnits);
+ void updateDisplayUnit(BitcoinUnit newUnits);
/** Tells underlying optionsModel to update its current display unit. */
void onMenuSelection(QAction* action);
};
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 69caf64d5c..fe3eb3240b 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -18,94 +18,75 @@ BitcoinUnits::BitcoinUnits(QObject *parent):
{
}
-QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
+QList<BitcoinUnit> BitcoinUnits::availableUnits()
{
- QList<BitcoinUnits::Unit> unitlist;
- unitlist.append(BTC);
- unitlist.append(mBTC);
- unitlist.append(uBTC);
- unitlist.append(SAT);
+ QList<BitcoinUnit> unitlist;
+ unitlist.append(Unit::BTC);
+ unitlist.append(Unit::mBTC);
+ unitlist.append(Unit::uBTC);
+ unitlist.append(Unit::SAT);
return unitlist;
}
-bool BitcoinUnits::valid(int unit)
+QString BitcoinUnits::longName(Unit unit)
{
- switch(unit)
- {
- case BTC:
- case mBTC:
- case uBTC:
- case SAT:
- return true;
- default:
- return false;
- }
-}
-
-QString BitcoinUnits::longName(int unit)
-{
- switch(unit)
- {
- case BTC: return QString("BTC");
- case mBTC: return QString("mBTC");
- case uBTC: return QString::fromUtf8("µBTC (bits)");
- case SAT: return QString("Satoshi (sat)");
- default: return QString("???");
- }
+ switch (unit) {
+ case Unit::BTC: return QString("BTC");
+ case Unit::mBTC: return QString("mBTC");
+ case Unit::uBTC: return QString::fromUtf8("µBTC (bits)");
+ case Unit::SAT: return QString("Satoshi (sat)");
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
-QString BitcoinUnits::shortName(int unit)
+QString BitcoinUnits::shortName(Unit unit)
{
- switch(unit)
- {
- case uBTC: return QString::fromUtf8("bits");
- case SAT: return QString("sat");
- default: return longName(unit);
- }
+ switch (unit) {
+ case Unit::BTC: return longName(unit);
+ case Unit::mBTC: return longName(unit);
+ case Unit::uBTC: return QString("bits");
+ case Unit::SAT: return QString("sat");
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
-QString BitcoinUnits::description(int unit)
+QString BitcoinUnits::description(Unit unit)
{
- switch(unit)
- {
- case BTC: return QString("Bitcoins");
- case mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
- case uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
- case SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
- default: return QString("???");
- }
+ switch (unit) {
+ case Unit::BTC: return QString("Bitcoins");
+ case Unit::mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
+ case Unit::uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
+ case Unit::SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
-qint64 BitcoinUnits::factor(int unit)
+qint64 BitcoinUnits::factor(Unit unit)
{
- switch(unit)
- {
- case BTC: return 100000000;
- case mBTC: return 100000;
- case uBTC: return 100;
- case SAT: return 1;
- default: return 100000000;
- }
+ switch (unit) {
+ case Unit::BTC: return 100'000'000;
+ case Unit::mBTC: return 100'000;
+ case Unit::uBTC: return 100;
+ case Unit::SAT: return 1;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
-int BitcoinUnits::decimals(int unit)
+int BitcoinUnits::decimals(Unit unit)
{
- switch(unit)
- {
- case BTC: return 8;
- case mBTC: return 5;
- case uBTC: return 2;
- case SAT: return 0;
- default: return 0;
- }
+ switch (unit) {
+ case Unit::BTC: return 8;
+ case Unit::mBTC: return 5;
+ case Unit::uBTC: return 2;
+ case Unit::SAT: return 0;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
-QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify)
+QString BitcoinUnits::format(Unit unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
- if(!valid(unit))
- return QString(); // Refuse to format invalid unit
qint64 n = (qint64)nIn;
qint64 coin = factor(unit);
int num_decimals = decimals(unit);
@@ -147,19 +128,19 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator
// Please take care to use formatHtmlWithUnit instead, when
// appropriate.
-QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
+QString BitcoinUnits::formatWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
{
return format(unit, amount, plussign, separators) + QString(" ") + shortName(unit);
}
-QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
+QString BitcoinUnits::formatHtmlWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
{
QString str(formatWithUnit(unit, amount, plussign, separators));
str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML));
return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
}
-QString BitcoinUnits::formatWithPrivacy(int unit, const CAmount& amount, SeparatorStyle separators, bool privacy)
+QString BitcoinUnits::formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy)
{
assert(amount >= 0);
QString value;
@@ -171,10 +152,11 @@ QString BitcoinUnits::formatWithPrivacy(int unit, const CAmount& amount, Separat
return value + QString(" ") + shortName(unit);
}
-bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out)
+bool BitcoinUnits::parse(Unit unit, const QString& value, CAmount* val_out)
{
- if(!valid(unit) || value.isEmpty())
+ if (value.isEmpty()) {
return false; // Refuse to parse invalid unit or empty string
+ }
int num_decimals = decimals(unit);
// Ignore spaces and thin spaces when parsing
@@ -210,14 +192,9 @@ bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out)
return ok;
}
-QString BitcoinUnits::getAmountColumnTitle(int unit)
+QString BitcoinUnits::getAmountColumnTitle(Unit unit)
{
- QString amountTitle = QObject::tr("Amount");
- if (BitcoinUnits::valid(unit))
- {
- amountTitle += " ("+BitcoinUnits::shortName(unit) + ")";
- }
- return amountTitle;
+ return QObject::tr("Amount") + " (" + shortName(unit) + ")";
}
int BitcoinUnits::rowCount(const QModelIndex &parent) const
@@ -240,7 +217,7 @@ QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
case Qt::ToolTipRole:
return QVariant(description(unit));
case UnitRole:
- return QVariant(static_cast<int>(unit));
+ return QVariant::fromValue(unit);
}
}
return QVariant();
@@ -250,3 +227,40 @@ CAmount BitcoinUnits::maxMoney()
{
return MAX_MONEY;
}
+
+namespace {
+qint8 ToQint8(BitcoinUnit unit)
+{
+ switch (unit) {
+ case BitcoinUnit::BTC: return 0;
+ case BitcoinUnit::mBTC: return 1;
+ case BitcoinUnit::uBTC: return 2;
+ case BitcoinUnit::SAT: return 3;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+}
+
+BitcoinUnit FromQint8(qint8 num)
+{
+ switch (num) {
+ case 0: return BitcoinUnit::BTC;
+ case 1: return BitcoinUnit::mBTC;
+ case 2: return BitcoinUnit::uBTC;
+ case 3: return BitcoinUnit::SAT;
+ }
+ assert(false);
+}
+} // namespace
+
+QDataStream& operator<<(QDataStream& out, const BitcoinUnit& unit)
+{
+ return out << ToQint8(unit);
+}
+
+QDataStream& operator>>(QDataStream& in, BitcoinUnit& unit)
+{
+ qint8 input;
+ in >> input;
+ unit = FromQint8(input);
+ return in;
+}
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 9fedec0d4f..b3b5a8fc18 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -8,6 +8,7 @@
#include <consensus/amount.h>
#include <QAbstractListModel>
+#include <QDataStream>
#include <QString>
// U+2009 THIN SPACE = UTF-8 E2 80 89
@@ -38,13 +39,13 @@ public:
/** Bitcoin units.
@note Source: https://en.bitcoin.it/wiki/Units . Please add only sensible ones
*/
- enum Unit
- {
+ enum class Unit {
BTC,
mBTC,
uBTC,
SAT
};
+ Q_ENUM(Unit)
enum class SeparatorStyle
{
@@ -59,30 +60,28 @@ public:
//! Get list of units, for drop-down box
static QList<Unit> availableUnits();
- //! Is unit ID valid?
- static bool valid(int unit);
//! Long name
- static QString longName(int unit);
+ static QString longName(Unit unit);
//! Short name
- static QString shortName(int unit);
+ static QString shortName(Unit unit);
//! Longer description
- static QString description(int unit);
+ static QString description(Unit unit);
//! Number of Satoshis (1e-8) per unit
- static qint64 factor(int unit);
+ static qint64 factor(Unit unit);
//! Number of decimals left
- static int decimals(int unit);
+ static int decimals(Unit unit);
//! Format as string
- static QString format(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD, bool justify = false);
+ static QString format(Unit unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD, bool justify = false);
//! Format as string (with unit)
- static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD);
+ static QString formatWithUnit(Unit unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD);
//! Format as HTML string (with unit)
- static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD);
+ static QString formatHtmlWithUnit(Unit unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD);
//! Format as string (with unit) of fixed length to preserve privacy, if it is set.
- static QString formatWithPrivacy(int unit, const CAmount& amount, SeparatorStyle separators, bool privacy);
+ static QString formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy);
//! Parse string to coin amount
- static bool parse(int unit, const QString &value, CAmount *val_out);
+ static bool parse(Unit unit, const QString& value, CAmount* val_out);
//! Gets title for amount column including current display unit if optionsModel reference available */
- static QString getAmountColumnTitle(int unit);
+ static QString getAmountColumnTitle(Unit unit);
///@}
//! @name AbstractListModel implementation
@@ -107,8 +106,11 @@ public:
static CAmount maxMoney();
private:
- QList<BitcoinUnits::Unit> unitlist;
+ QList<Unit> unitlist;
};
typedef BitcoinUnits::Unit BitcoinUnit;
+QDataStream& operator<<(QDataStream& out, const BitcoinUnit& unit);
+QDataStream& operator>>(QDataStream& in, BitcoinUnit& unit);
+
#endif // BITCOIN_QT_BITCOINUNITS_H
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index d3103492a4..bd9a90a890 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -507,7 +507,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
}
// actually update labels
- int nDisplayUnit = BitcoinUnits::BTC;
+ BitcoinUnit nDisplayUnit = BitcoinUnit::BTC;
if (model && model->getOptionsModel())
nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
@@ -588,9 +588,9 @@ void CoinControlDialog::updateView()
ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
ui->treeWidget->setAlternatingRowColors(!treeMode);
QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
- QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
+ QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate;
- int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
+ BitcoinUnit nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
for (const auto& coins : model->wallet().listCoins()) {
CCoinControlWidgetItem* itemWalletAddress{nullptr};
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 362601b512..6fb5fce5b3 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -60,6 +60,7 @@
#include <QSettings>
#include <QShortcut>
#include <QSize>
+#include <QStandardPaths>
#include <QString>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
@@ -80,6 +81,8 @@
void ForceActivation();
#endif
+using namespace std::chrono_literals;
+
namespace GUIUtil {
QString dateTimeStr(const QDateTime &date)
@@ -175,8 +178,7 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
if(!i->second.isEmpty())
{
- if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount))
- {
+ if (!BitcoinUnits::parse(BitcoinUnit::BTC, i->second, &rv.amount)) {
return false;
}
}
@@ -208,7 +210,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
if (info.amount)
{
- ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount, false, BitcoinUnits::SeparatorStyle::NEVER));
+ ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnit::BTC, info.amount, false, BitcoinUnits::SeparatorStyle::NEVER));
paramCount++;
}
@@ -728,6 +730,16 @@ QString formatDurationStr(std::chrono::seconds dur)
return str_list.join(" ");
}
+QString FormatPeerAge(std::chrono::seconds time_connected)
+{
+ const auto time_now{GetTime<std::chrono::seconds>()};
+ const auto age{time_now - time_connected};
+ if (age >= 24h) return QObject::tr("%1 d").arg(age / 24h);
+ if (age >= 1h) return QObject::tr("%1 h").arg(age / 1h);
+ if (age >= 1min) return QObject::tr("%1 m").arg(age / 1min);
+ return QObject::tr("%1 s").arg(age / 1s);
+}
+
QString formatServicesStr(quint64 mask)
{
QStringList strList;
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 0224b18b4e..e38ac6026a 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -223,6 +223,9 @@ namespace GUIUtil
/** Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(std::chrono::seconds dur);
+ /** Convert peer connection time to a QString denominated in the most relevant unit. */
+ QString FormatPeerAge(std::chrono::seconds time_connected);
+
/** Format CNodeStats.nServices bitmask into a user-readable string */
QString formatServicesStr(quint64 mask);
@@ -358,18 +361,6 @@ namespace GUIUtil
#endif
}
- /**
- * Queue a function to run in an object's event loop. This can be
- * replaced by a call to the QMetaObject::invokeMethod functor overload after Qt 5.10, but
- * for now use a QObject::connect for compatibility with older Qt versions, based on
- * https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style
- */
- template <typename Fn>
- void ObjectInvoke(QObject* object, Fn&& function, Qt::ConnectionType connection = Qt::QueuedConnection)
- {
- QObject source;
- QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection);
- }
/**
* Replaces a plain text link with an HTML tagged one.
diff --git a/src/qt/initexecutor.cpp b/src/qt/initexecutor.cpp
index 24ae7ba73d..d269dfec71 100644
--- a/src/qt/initexecutor.cpp
+++ b/src/qt/initexecutor.cpp
@@ -5,13 +5,13 @@
#include <qt/initexecutor.h>
#include <interfaces/node.h>
-#include <qt/guiutil.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <exception>
#include <QDebug>
+#include <QMetaObject>
#include <QObject>
#include <QString>
#include <QThread>
@@ -39,7 +39,7 @@ void InitExecutor::handleRunawayException(const std::exception* e)
void InitExecutor::initialize()
{
- GUIUtil::ObjectInvoke(&m_context, [this] {
+ QMetaObject::invokeMethod(&m_context, [this] {
try {
util::ThreadRename("qt-init");
qDebug() << "Running initialization in thread";
@@ -56,7 +56,7 @@ void InitExecutor::initialize()
void InitExecutor::shutdown()
{
- GUIUtil::ObjectInvoke(&m_context, [this] {
+ QMetaObject::invokeMethod(&m_context, [this] {
try {
qDebug() << "Running Shutdown in thread";
m_node.appShutdown();
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index b097ef080c..51151b0be8 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -14,8 +14,9 @@
#include <QTemporaryFile>
#include <QVariant>
#ifdef USE_DBUS
-#include <stdint.h>
+#include <QDBusMetaType>
#include <QtDBus>
+#include <stdint.h>
#endif
#ifdef Q_OS_MAC
#include <qt/macnotificationhandler.h>
@@ -73,8 +74,6 @@ public:
FreedesktopImage() {}
explicit FreedesktopImage(const QImage &img);
- static int metaType();
-
// Image to variant that can be marshalled over DBus
static QVariant toVariant(const QImage &img);
@@ -136,15 +135,10 @@ const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)
return a;
}
-int FreedesktopImage::metaType()
-{
- return qDBusRegisterMetaType<FreedesktopImage>();
-}
-
QVariant FreedesktopImage::toVariant(const QImage &img)
{
FreedesktopImage fimg(img);
- return QVariant(FreedesktopImage::metaType(), &fimg);
+ return QVariant(qDBusRegisterMetaType<FreedesktopImage>(), &fimg);
}
void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 52bda59748..40b9ed5483 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -24,6 +24,7 @@
#include <QLatin1Char>
#include <QSettings>
#include <QStringList>
+#include <QVariant>
const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
@@ -71,9 +72,16 @@ void OptionsModel::Init(bool resetSettings)
fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool();
// Display
- if (!settings.contains("nDisplayUnit"))
- settings.setValue("nDisplayUnit", BitcoinUnits::BTC);
- nDisplayUnit = settings.value("nDisplayUnit").toInt();
+ if (!settings.contains("DisplayBitcoinUnit")) {
+ settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(BitcoinUnit::BTC));
+ }
+ QVariant unit = settings.value("DisplayBitcoinUnit");
+ if (unit.canConvert<BitcoinUnit>()) {
+ m_display_bitcoin_unit = unit.value<BitcoinUnit>();
+ } else {
+ m_display_bitcoin_unit = BitcoinUnit::BTC;
+ settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(m_display_bitcoin_unit));
+ }
if (!settings.contains("strThirdPartyTxUrls"))
settings.setValue("strThirdPartyTxUrls", "");
@@ -376,7 +384,7 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return m_sub_fee_from_amount;
#endif
case DisplayUnit:
- return nDisplayUnit;
+ return QVariant::fromValue(m_display_bitcoin_unit);
case ThirdPartyTxUrls:
return strThirdPartyTxUrls;
case Language:
@@ -584,16 +592,13 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
return successful;
}
-/** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
-void OptionsModel::setDisplayUnit(const QVariant &value)
+void OptionsModel::setDisplayUnit(const QVariant& new_unit)
{
- if (!value.isNull())
- {
- QSettings settings;
- nDisplayUnit = value.toInt();
- settings.setValue("nDisplayUnit", nDisplayUnit);
- Q_EMIT displayUnitChanged(nDisplayUnit);
- }
+ if (new_unit.isNull() || new_unit.value<BitcoinUnit>() == m_display_bitcoin_unit) return;
+ m_display_bitcoin_unit = new_unit.value<BitcoinUnit>();
+ QSettings settings;
+ settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(m_display_bitcoin_unit));
+ Q_EMIT displayUnitChanged(m_display_bitcoin_unit);
}
void OptionsModel::setRestartRequired(bool fRequired)
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index bb9a8c1f8c..510ebb5cfd 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -6,6 +6,7 @@
#define BITCOIN_QT_OPTIONSMODEL_H
#include <cstdint>
+#include <qt/bitcoinunits.h>
#include <qt/guiconstants.h>
#include <QAbstractListModel>
@@ -55,7 +56,7 @@ public:
ProxyUseTor, // bool
ProxyIPTor, // QString
ProxyPortTor, // int
- DisplayUnit, // BitcoinUnits::Unit
+ DisplayUnit, // BitcoinUnit
ThirdPartyTxUrls, // QString
Language, // QString
UseEmbeddedMonospacedFont, // bool
@@ -79,14 +80,14 @@ public:
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) override;
- /** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
- void setDisplayUnit(const QVariant &value);
+ /** Updates current unit in memory, settings and emits displayUnitChanged(new_unit) signal */
+ void setDisplayUnit(const QVariant& new_unit);
/* Explicit getters */
bool getShowTrayIcon() const { return m_show_tray_icon; }
bool getMinimizeToTray() const { return fMinimizeToTray; }
bool getMinimizeOnClose() const { return fMinimizeOnClose; }
- int getDisplayUnit() const { return nDisplayUnit; }
+ BitcoinUnit getDisplayUnit() const { return m_display_bitcoin_unit; }
QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; }
bool getUseEmbeddedMonospacedFont() const { return m_use_embedded_monospaced_font; }
bool getCoinControlFeatures() const { return fCoinControlFeatures; }
@@ -112,7 +113,7 @@ private:
bool fMinimizeToTray;
bool fMinimizeOnClose;
QString language;
- int nDisplayUnit;
+ BitcoinUnit m_display_bitcoin_unit;
QString strThirdPartyTxUrls;
bool m_use_embedded_monospaced_font;
bool fCoinControlFeatures;
@@ -127,7 +128,7 @@ private:
// Check settings version and upgrade default values if required
void checkAndMigrate();
Q_SIGNALS:
- void displayUnitChanged(int unit);
+ void displayUnitChanged(BitcoinUnit unit);
void coinControlFeaturesChanged(bool);
void showTrayIconChanged(bool);
void useEmbeddedMonospacedFontChanged(bool);
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 7127706463..820bcbf3cd 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -34,9 +34,9 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
- QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
- platformStyle(_platformStyle)
+ explicit TxViewDelegate(const PlatformStyle* _platformStyle, QObject* parent = nullptr)
+ : QAbstractItemDelegate(parent), unit(BitcoinUnit::BTC),
+ platformStyle(_platformStyle)
{
connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged);
}
@@ -125,7 +125,7 @@ public:
return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE};
}
- int unit;
+ BitcoinUnit unit;
Q_SIGNALS:
//! An intermediate signal for emitting from the `paint() const` member function.
@@ -197,7 +197,7 @@ OverviewPage::~OverviewPage()
void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
{
- int unit = walletModel->getOptionsModel()->getDisplayUnit();
+ BitcoinUnit unit = walletModel->getOptionsModel()->getDisplayUnit();
m_balances = balances;
if (walletModel->wallet().isLegacy()) {
if (walletModel->wallet().privateKeysDisabled()) {
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 563bca76e5..41c389d9cc 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -71,6 +71,8 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const
switch (column) {
case NetNodeId:
return (qint64)rec->nodeStats.nodeid;
+ case Age:
+ return GUIUtil::FormatPeerAge(rec->nodeStats.m_connected);
case Address:
return QString::fromStdString(rec->nodeStats.m_addr_name);
case Direction:
@@ -96,6 +98,7 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const
} else if (role == Qt::TextAlignmentRole) {
switch (column) {
case NetNodeId:
+ case Age:
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
case Address:
return {};
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index 11064cdbfe..e2515de775 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -47,6 +47,7 @@ public:
enum ColumnIndex {
NetNodeId = 0,
+ Age,
Address,
Direction,
ConnectionType,
@@ -82,6 +83,9 @@ private:
/*: Title of Peers Table column which contains a
unique number used to identify a connection. */
tr("Peer"),
+ /*: Title of Peers Table column which indicates the duration (length of time)
+ since the peer connection started. */
+ tr("Age"),
/*: Title of Peers Table column which contains the
IP/Onion/I2P address of the connected peer. */
tr("Address"),
diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp
index 26fedb4127..d87f10c365 100644
--- a/src/qt/peertablesortproxy.cpp
+++ b/src/qt/peertablesortproxy.cpp
@@ -24,6 +24,8 @@ bool PeerTableSortProxy::lessThan(const QModelIndex& left_index, const QModelInd
switch (static_cast<PeerTableModel::ColumnIndex>(left_index.column())) {
case PeerTableModel::NetNodeId:
return left_stats.nodeid < right_stats.nodeid;
+ case PeerTableModel::Age:
+ return left_stats.m_connected > right_stats.m_connected;
case PeerTableModel::Address:
return left_stats.m_addr_name.compare(right_stats.m_addr_name) < 0;
case PeerTableModel::Direction:
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 6880c157c0..333766ce21 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -181,7 +181,7 @@ std::string PSBTOperationsDialog::renderTransaction(const PartiallySignedTransac
ExtractDestination(out.scriptPubKey, address);
totalAmount += out.nValue;
tx_description.append(tr(" * Sends %1 to %2")
- .arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, out.nValue))
+ .arg(BitcoinUnits::formatWithUnit(BitcoinUnit::BTC, out.nValue))
.arg(QString::fromStdString(EncodeDestination(address))));
tx_description.append("<br>");
}
@@ -193,7 +193,7 @@ std::string PSBTOperationsDialog::renderTransaction(const PartiallySignedTransac
tx_description.append(tr("Unable to calculate transaction fee or total transaction amount."));
} else {
tx_description.append(tr("Pays transaction fee: "));
- tx_description.append(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, *analysis.fee));
+ tx_description.append(BitcoinUnits::formatWithUnit(BitcoinUnit::BTC, *analysis.fee));
// add total amount in all subdivision units
tx_description.append("<hr />");
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index dcc4f36aaa..eb69fabe89 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -618,17 +618,16 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
case Qt::Key_Down: if(obj == ui->lineEdit) { browseHistory(1); return true; } break;
case Qt::Key_PageUp: /* pass paging keys to messages widget */
case Qt::Key_PageDown:
- if(obj == ui->lineEdit)
- {
- QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt));
+ if (obj == ui->lineEdit) {
+ QApplication::sendEvent(ui->messagesWidget, keyevt);
return true;
}
break;
case Qt::Key_Return:
case Qt::Key_Enter:
// forward these events to lineEdit
- if(obj == autoCompleter->popup()) {
- QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
+ if (obj == autoCompleter->popup()) {
+ QApplication::sendEvent(ui->lineEdit, keyevt);
autoCompleter->popup()->hide();
return true;
}
@@ -642,7 +641,7 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
((mod & Qt::ShiftModifier) && key == Qt::Key_Insert)))
{
ui->lineEdit->setFocus();
- QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
+ QApplication::sendEvent(ui->lineEdit, keyevt);
return true;
}
}
@@ -694,6 +693,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
}
+ ui->peerWidget->horizontalHeader()->setSectionResizeMode(PeerTableModel::Age, QHeaderView::ResizeToContents);
ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this));
@@ -726,6 +726,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH);
ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
}
+ ui->banlistWidget->horizontalHeader()->setSectionResizeMode(BanTableModel::Address, QHeaderView::ResizeToContents);
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
// create ban table context menu
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index c924789796..fd8eccb86d 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -380,8 +380,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
question_string.append("<hr />");
CAmount totalAmount = m_current_transaction->getTotalTransactionAmount() + txFee;
QStringList alternativeUnits;
- for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits())
- {
+ for (const BitcoinUnit u : BitcoinUnits::availableUnits()) {
if(u != model->getOptionsModel()->getDisplayUnit())
alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
}
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 07d256f05a..aeedd92834 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -21,8 +21,10 @@
#endif // ENABLE_WALLET
#include <QApplication>
+#include <QDebug>
#include <QObject>
#include <QTest>
+
#include <functional>
#if defined(QT_STATICPLUGIN)
@@ -69,8 +71,6 @@ int main(int argc, char* argv[])
gArgs.ForceSetArg("-upnp", "0");
gArgs.ForceSetArg("-natpmp", "0");
- bool fInvalid = false;
-
// Prefer the "minimal" platform for the test instead of the normal default
// platform ("xcb", "windows", or "cocoa") so tests can't unintentionally
// interfere with any background GUIs and don't require extra resources.
@@ -86,32 +86,32 @@ int main(int argc, char* argv[])
app.setApplicationName("Bitcoin-Qt-test");
app.createNode(*init);
+ int num_test_failures{0};
+
AppTests app_tests(app);
- if (QTest::qExec(&app_tests) != 0) {
- fInvalid = true;
- }
+ num_test_failures += QTest::qExec(&app_tests);
+
OptionTests options_tests(app.node());
- if (QTest::qExec(&options_tests) != 0) {
- fInvalid = true;
- }
+ num_test_failures += QTest::qExec(&options_tests);
+
URITests test1;
- if (QTest::qExec(&test1) != 0) {
- fInvalid = true;
- }
+ num_test_failures += QTest::qExec(&test1);
+
RPCNestedTests test3(app.node());
- if (QTest::qExec(&test3) != 0) {
- fInvalid = true;
- }
+ num_test_failures += QTest::qExec(&test3);
+
#ifdef ENABLE_WALLET
WalletTests test5(app.node());
- if (QTest::qExec(&test5) != 0) {
- fInvalid = true;
- }
+ num_test_failures += QTest::qExec(&test5);
+
AddressBookTests test6(app.node());
- if (QTest::qExec(&test6) != 0) {
- fInvalid = true;
- }
+ num_test_failures += QTest::qExec(&test6);
#endif
- return fInvalid;
+ if (num_test_failures) {
+ qWarning("\nFailed tests: %d\n", num_test_failures);
+ } else {
+ qDebug("\nAll tests passed.\n");
+ }
+ return num_test_failures;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 6ab534764b..c4cd0f4cd1 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -7,24 +7,25 @@
#include <interfaces/chain.h>
#include <interfaces/node.h>
+#include <key_io.h>
#include <qt/bitcoinamountfield.h>
+#include <qt/bitcoinunits.h>
#include <qt/clientmodel.h>
#include <qt/optionsmodel.h>
+#include <qt/overviewpage.h>
#include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h>
+#include <qt/receivecoinsdialog.h>
+#include <qt/receiverequestdialog.h>
+#include <qt/recentrequeststablemodel.h>
#include <qt/sendcoinsdialog.h>
#include <qt/sendcoinsentry.h>
#include <qt/transactiontablemodel.h>
#include <qt/transactionview.h>
#include <qt/walletmodel.h>
-#include <key_io.h>
#include <test/util/setup_common.h>
#include <validation.h>
#include <wallet/wallet.h>
-#include <qt/overviewpage.h>
-#include <qt/receivecoinsdialog.h>
-#include <qt/recentrequeststablemodel.h>
-#include <qt/receiverequestdialog.h>
#include <chrono>
#include <memory>
@@ -196,7 +197,7 @@ void TestGUI(interfaces::Node& node)
// Check balance in send dialog
QLabel* balanceLabel = sendCoinsDialog.findChild<QLabel*>("labelBalance");
QString balanceText = balanceLabel->text();
- int unit = walletModel.getOptionsModel()->getDisplayUnit();
+ BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit();
CAmount balance = walletModel.wallet().getBalance();
QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
QCOMPARE(balanceText, balanceComparison);
@@ -222,7 +223,7 @@ void TestGUI(interfaces::Node& node)
overviewPage.setWalletModel(&walletModel);
QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
QString balanceText = balanceLabel->text().trimmed();
- int unit = walletModel.getOptionsModel()->getDisplayUnit();
+ BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit();
CAmount balance = walletModel.wallet().getBalance();
QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
QCOMPARE(balanceText, balanceComparison);
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index be5851d627..9e92f89543 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -32,20 +32,18 @@ using wallet::ISMINE_SPENDABLE;
using wallet::ISMINE_WATCH_ONLY;
using wallet::isminetype;
-QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks)
+QString TransactionDesc::FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool)
{
- {
- int nDepth = status.depth_in_main_chain;
- if (nDepth < 0) {
- return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
- } else if (nDepth == 0) {
- const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()};
- return tr("0/unconfirmed, %1").arg(inMempool ? tr("in memory pool") : tr("not in memory pool")) + abandoned;
- } else if (nDepth < 6) {
- return tr("%1/unconfirmed").arg(nDepth);
- } else {
- return tr("%1 confirmations").arg(nDepth);
- }
+ int depth = status.depth_in_main_chain;
+ if (depth < 0) {
+ return tr("conflicted with a transaction with %1 confirmations").arg(-depth);
+ } else if (depth == 0) {
+ const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()};
+ return tr("0/unconfirmed, %1").arg(inMempool ? tr("in memory pool") : tr("not in memory pool")) + abandoned;
+ } else if (depth < 6) {
+ return tr("%1/unconfirmed").arg(depth);
+ } else {
+ return tr("%1 confirmations").arg(depth);
}
}
@@ -77,7 +75,7 @@ bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant)
return false;
}
-QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
+QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit)
{
int numBlocks;
interfaces::WalletTxStatus status;
@@ -95,7 +93,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
CAmount nDebit = wtx.debit;
CAmount nNet = nCredit - nDebit;
- strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks);
+ strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(status, inMempool);
strHTML += "<br>";
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h
index cf955a433c..803e41b699 100644
--- a/src/qt/transactiondesc.h
+++ b/src/qt/transactiondesc.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_QT_TRANSACTIONDESC_H
#define BITCOIN_QT_TRANSACTIONDESC_H
+#include <qt/bitcoinunits.h>
+
#include <QObject>
#include <QString>
@@ -24,12 +26,12 @@ class TransactionDesc: public QObject
Q_OBJECT
public:
- static QString toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit);
+ static QString toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit);
private:
TransactionDesc() {}
- static QString FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks);
+ static QString FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool);
};
#endif // BITCOIN_QT_TRANSACTIONDESC_H
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index dd34656d5f..d8748d7dc9 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -20,13 +20,7 @@ struct WalletTxStatus;
/** UI model for transaction status. The transaction status is the part of a transaction that will change over time.
*/
-class TransactionStatus
-{
-public:
- TransactionStatus() : countsForBalance(false), sortKey(""),
- matures_in(0), status(Unconfirmed), depth(0), open_for(0)
- { }
-
+struct TransactionStatus {
enum Status {
Confirmed, /**< Have 6 or more confirmations (normal tx) or fully mature (mined tx) **/
/// Normal (sent/received) transactions
@@ -40,28 +34,25 @@ public:
};
/// Transaction counts towards available balance
- bool countsForBalance;
+ bool countsForBalance{false};
/// Sorting key based on status
std::string sortKey;
/** @name Generated (mined) transactions
@{*/
- int matures_in;
+ int matures_in{0};
/**@}*/
/** @name Reported status
@{*/
- Status status;
- qint64 depth;
- qint64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number
- of additional blocks that need to be mined before
- finalization */
+ Status status{Unconfirmed};
+ qint64 depth{0};
/**@}*/
/** Current block hash (to know whether cached status is still valid) */
uint256 m_cur_block_hash{};
- bool needsUpdate;
+ bool needsUpdate{false};
};
/** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 6b0495f5a8..7b932890cf 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -5,6 +5,7 @@
#include <qt/transactiontablemodel.h>
#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
@@ -232,7 +233,7 @@ public:
return nullptr;
}
- QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
+ QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit)
{
return TransactionDesc::toHTML(node, wallet, rec, unit);
}
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index b025bb367c..d27ddf1aba 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -24,6 +24,7 @@
#include <QApplication>
#include <QMessageBox>
+#include <QMetaObject>
#include <QMutexLocker>
#include <QThread>
#include <QTimer>
@@ -135,7 +136,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
// handled on the GUI event loop.
wallet_model->moveToThread(thread());
// setParent(parent) must be called in the thread which created the parent object. More details in #18948.
- GUIUtil::ObjectInvoke(this, [wallet_model, this] {
+ QMetaObject::invokeMethod(this, [wallet_model, this] {
wallet_model->setParent(this);
}, GUIUtil::blockingGUIThreadConnection());
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index e7ec54721a..344bf628bb 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -23,7 +23,6 @@
#include <util/strencodings.h>
#include <QAction>
-#include <QActionGroup>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QProgressDialog>
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index 2f9d344bc8..301084ffa9 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -6,6 +6,7 @@
#define BITCOIN_QT_WALLETVIEW_H
#include <consensus/amount.h>
+#include <qt/bitcoinunits.h>
#include <QStackedWidget>
@@ -115,7 +116,7 @@ Q_SIGNALS:
/** Encryption status of wallet changed */
void encryptionStatusChanged();
/** Notify that a new transaction appeared */
- void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName);
+ void incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName);
/** Notify that the out of sync warning icon has been pressed */
void outOfSyncWarningClicked();
};
diff --git a/src/random.cpp b/src/random.cpp
index b862510524..6ae08103b1 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -13,9 +13,10 @@
#include <compat.h> // for Windows API
#include <wincrypt.h>
#endif
-#include <logging.h> // for LogPrintf()
+#include <logging.h>
#include <randomenv.h>
#include <support/allocators/secure.h>
+#include <span.h>
#include <sync.h> // for Mutex
#include <util/time.h> // for GetTimeMicros()
@@ -578,8 +579,8 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept
}
}
-void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); }
-void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
+void GetRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST); }
+void GetStrongRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW); }
void RandAddPeriodic() noexcept { ProcRand(nullptr, 0, RNGLevel::PERIODIC); }
void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); }
@@ -598,7 +599,7 @@ int GetRandInt(int nMax) noexcept
uint256 GetRandHash() noexcept
{
uint256 hash;
- GetRandBytes((unsigned char*)&hash, sizeof(hash));
+ GetRandBytes(hash);
return hash;
}
diff --git a/src/random.h b/src/random.h
index 97302d61ab..285158b1c3 100644
--- a/src/random.h
+++ b/src/random.h
@@ -8,6 +8,7 @@
#include <crypto/chacha20.h>
#include <crypto/common.h>
+#include <span.h>
#include <uint256.h>
#include <chrono>
@@ -66,7 +67,7 @@
*
* Thread-safe.
*/
-void GetRandBytes(unsigned char* buf, int num) noexcept;
+void GetRandBytes(Span<unsigned char> bytes) noexcept;
/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */
uint64_t GetRand(uint64_t nMax) noexcept;
/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
@@ -105,7 +106,7 @@ uint256 GetRandHash() noexcept;
*
* Thread-safe.
*/
-void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
+void GetStrongRandBytes(Span<unsigned char> bytes) noexcept;
/**
* Gather entropy from various expensive sources, and feed them to the PRNG state.
diff --git a/src/rest.cpp b/src/rest.cpp
index a8eba05c3f..2aeb9c68c3 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -37,7 +37,6 @@
#include <univalue.h>
using node::GetTransaction;
-using node::IsBlockPruned;
using node::NodeContext;
using node::ReadBlockFromDisk;
@@ -295,10 +294,10 @@ static bool rest_block(const std::any& context,
CBlock block;
const CBlockIndex* pblockindex = nullptr;
const CBlockIndex* tip = nullptr;
+ ChainstateManager* maybe_chainman = GetChainman(context, req);
+ if (!maybe_chainman) return false;
+ ChainstateManager& chainman = *maybe_chainman;
{
- ChainstateManager* maybe_chainman = GetChainman(context, req);
- if (!maybe_chainman) return false;
- ChainstateManager& chainman = *maybe_chainman;
LOCK(cs_main);
tip = chainman.ActiveChain().Tip();
pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
@@ -306,7 +305,7 @@ static bool rest_block(const std::any& context,
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
- if (IsBlockPruned(pblockindex))
+ if (chainman.m_blockman.IsBlockPruned(pblockindex))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
@@ -333,7 +332,7 @@ static bool rest_block(const std::any& context,
}
case RESTResponseFormat::JSON: {
- UniValue objBlock = blockToJSON(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 d23ffc9036..d6a6bd5f31 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -55,7 +55,6 @@ using node::BlockManager;
using node::CCoinsStats;
using node::CoinStatsHashType;
using node::GetUTXOStats;
-using node::IsBlockPruned;
using node::NodeContext;
using node::ReadBlockFromDisk;
using node::SnapshotMetadata;
@@ -162,7 +161,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
return result;
}
-UniValue blockToJSON(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);
@@ -181,7 +180,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
case TxVerbosity::SHOW_DETAILS:
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
CBlockUndo blockUndo;
- const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
+ const bool have_undo{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
for (size_t i = 0; i < block.vtx.size(); ++i) {
const CTransactionRef& tx = block.vtx.at(i);
@@ -566,11 +565,11 @@ static RPCHelpMan getblockheader()
};
}
-static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
CBlock block;
- if (IsBlockPruned(pblockindex)) {
+ if (blockman.IsBlockPruned(pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
}
@@ -584,11 +583,11 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_RE
return block;
}
-static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(::cs_main);
CBlockUndo blockUndo;
- if (IsBlockPruned(pblockindex)) {
+ if (blockman.IsBlockPruned(pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
}
@@ -702,8 +701,8 @@ static RPCHelpMan getblock()
CBlock block;
const CBlockIndex* pblockindex;
const CBlockIndex* tip;
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
{
- ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main);
pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
tip = chainman.ActiveChain().Tip();
@@ -712,7 +711,7 @@ static RPCHelpMan getblock()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- block = GetBlockChecked(pblockindex);
+ block = GetBlockChecked(chainman.m_blockman, pblockindex);
}
if (verbosity <= 0)
@@ -732,7 +731,7 @@ static RPCHelpMan getblock()
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
}
- return blockToJSON(block, tip, pblockindex, tx_verbosity);
+ return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
},
};
}
@@ -1204,18 +1203,18 @@ RPCHelpMan getblockchaininfo()
const CBlockIndex* tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
const int height = tip->nHeight;
UniValue obj(UniValue::VOBJ);
- obj.pushKV("chain", Params().NetworkIDString());
- obj.pushKV("blocks", height);
- obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
- obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
- obj.pushKV("difficulty", (double)GetDifficulty(tip));
- obj.pushKV("time", (int64_t)tip->nTime);
- obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
- obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
- obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
- obj.pushKV("chainwork", tip->nChainWork.GetHex());
+ obj.pushKV("chain", Params().NetworkIDString());
+ 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", (double)GetDifficulty(tip));
+ obj.pushKV("time", (int64_t)tip->nTime);
+ obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
+ obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
+ obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
+ obj.pushKV("chainwork", tip->nChainWork.GetHex());
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
- obj.pushKV("pruned", node::fPruneMode);
+ obj.pushKV("pruned", node::fPruneMode);
if (node::fPruneMode) {
const CBlockIndex* block = CHECK_NONFATAL(tip);
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
@@ -1774,8 +1773,8 @@ static RPCHelpMan getblockstats()
}
}
- const CBlock block = GetBlockChecked(pindex);
- const CBlockUndo blockUndo = GetUndoChecked(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;
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index a8c6d171cc..5fbd9d5fd3 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -10,6 +10,7 @@
#include <fs.h>
#include <streams.h>
#include <sync.h>
+#include <validation.h>
#include <any>
#include <stdint.h>
@@ -39,7 +40,7 @@ double GetDifficulty(const CBlockIndex* blockindex);
void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */
-UniValue blockToJSON(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);
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 95a7c25b93..d0e068de19 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -82,7 +82,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
{
const size_t COOKIE_SIZE = 32;
unsigned char rand_pwd[COOKIE_SIZE];
- GetRandBytes(rand_pwd, COOKIE_SIZE);
+ GetRandBytes(rand_pwd);
std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
/** the umask determines what permissions are used to create this file -
diff --git a/src/script/miniscript.cpp b/src/script/miniscript.cpp
index d0bb937885..019f02f159 100644
--- a/src/script/miniscript.cpp
+++ b/src/script/miniscript.cpp
@@ -116,7 +116,8 @@ Type ComputeType(Fragment nodetype, Type x, Type y, Type z, const std::vector<Ty
"e"_mst.If(x << "f"_mst) | // e=f_x
(x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x
(x & "ms"_mst) | // m=m_x, s=s_x
- "nudx"_mst; // n, u, d, x
+ // NOTE: 'd:' is not 'u' under P2WSH as MINIMALIF is only a policy rule there.
+ "ndx"_mst; // n, d, x
case Fragment::WRAP_V: return
"V"_mst.If(x << "B"_mst) | // V=B_x
(x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x
diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml
index 35a9a45367..a2e7f36d1f 100644
--- a/src/secp256k1/.cirrus.yml
+++ b/src/secp256k1/.cirrus.yml
@@ -4,10 +4,10 @@ env:
# 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: -j2
+ MAKEFLAGS: -j4
BUILD: check
### secp256k1 config
- STATICPRECOMPUTATION: yes
+ ECMULTWINDOW: auto
ECMULTGENPRECISION: auto
ASM: no
WIDEMUL: auto
@@ -23,6 +23,8 @@ env:
BENCH: yes
SECP256K1_BENCH_ITERS: 2
CTIMETEST: yes
+ # Compile and run the tests
+ EXAMPLES: yes
cat_logs_snippet: &CAT_LOGS
always:
@@ -50,28 +52,32 @@ merge_base_script_snippet: &MERGE_BASE
- git config --global user.name "ci"
- git merge FETCH_HEAD # Merge base to detect silent merge conflicts
-task:
- name: "x86_64: Linux (Debian stable)"
+linux_container_snippet: &LINUX_CONTAINER
container:
dockerfile: ci/linux-debian.Dockerfile
# Reduce number of CPUs to be able to do more builds in parallel.
cpu: 1
+ # Gives us more CPUs for free if they're available.
+ greedy: true
# More than enough for our scripts.
memory: 1G
+
+task:
+ name: "x86_64: Linux (Debian stable)"
+ << : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- - env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128}
- - env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
- - env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- - env: { RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
- - env: { STATICPRECOMPUTATION: no}
+ - env: { RECOVERY: yes, SCHNORRSIG: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
- env: {CFLAGS: -O0, CTIMETEST: no}
- - env: { ECMULTGENPRECISION: 2 }
- - env: { ECMULTGENPRECISION: 8 }
+ - env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
+ - env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
matrix:
- env:
CC: gcc
@@ -84,15 +90,11 @@ task:
task:
name: "i686: Linux (Debian stable)"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
HOST: i686-linux-gnu
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
matrix:
- env:
@@ -134,8 +136,10 @@ task:
## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
##
brew_valgrind_pre_script:
+ # Retry a few times because this tends to fail randomly.
+ - for i in {1..5}; do brew update && break || sleep 15; done
- brew config
- - brew tap --shallow LouisBrunner/valgrind
+ - brew tap LouisBrunner/valgrind
# Fetch valgrind source but don't build it yet.
- brew fetch --HEAD LouisBrunner/valgrind/valgrind
brew_valgrind_cache:
@@ -165,10 +169,7 @@ task:
task:
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
WRAPPER_CMD: qemu-s390x
SECP256K1_TEST_ITERS: 16
@@ -176,7 +177,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@@ -188,10 +188,7 @@ task:
task:
name: "ARM32: Linux (Debian stable, QEMU)"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
WRAPPER_CMD: qemu-arm
SECP256K1_TEST_ITERS: 16
@@ -199,12 +196,11 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
matrix:
- env: {}
- - env: {ASM: arm}
+ - env: {EXPERIMENTAL: yes, ASM: arm}
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -212,10 +208,7 @@ task:
task:
name: "ARM64: Linux (Debian stable, QEMU)"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
WRAPPER_CMD: qemu-aarch64
SECP256K1_TEST_ITERS: 16
@@ -223,7 +216,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@@ -233,10 +225,7 @@ task:
task:
name: "ppc64le: Linux (Debian stable, QEMU)"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
WRAPPER_CMD: qemu-ppc64le
SECP256K1_TEST_ITERS: 16
@@ -244,7 +233,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@@ -254,10 +242,7 @@ task:
task:
name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
WRAPPER_CMD: wine64-stable
SECP256K1_TEST_ITERS: 16
@@ -265,7 +250,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@@ -275,23 +259,23 @@ task:
# Sanitizers
task:
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 2G
+ << : *LINUX_CONTAINER
env:
ECDH: yes
RECOVERY: yes
- EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
matrix:
- name: "Valgrind (memcheck)"
+ container:
+ cpu: 2
env:
# The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html)
WRAPPER_CMD: "valgrind --error-exitcode=42"
SECP256K1_TEST_ITERS: 2
- name: "UBSan, ASan, LSan"
+ container:
+ memory: 2G
env:
CFLAGS: "-fsanitize=undefined,address -g"
UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"
@@ -302,11 +286,10 @@ task:
matrix:
- env:
ASM: auto
- STATICPRECOMPUTATION: yes
- env:
ASM: no
- STATICPRECOMPUTATION: no
ECMULTGENPRECISION: 2
+ ECMULTWINDOW: 2
matrix:
- env:
CC: clang
@@ -320,17 +303,13 @@ task:
task:
name: "C++ -fpermissive"
- container:
- dockerfile: ci/linux-debian.Dockerfile
- cpu: 1
- memory: 1G
+ << : *LINUX_CONTAINER
env:
# ./configure correctly errors out when given CC=g++.
# We hack around this by passing CC=g++ only to make.
CC: gcc
- MAKEFLAGS: -j2 CC=g++ CFLAGS=-fpermissive\ -g
+ MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
WERROR_CFLAGS:
- EXPERIMENTAL: yes
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
@@ -338,3 +317,10 @@ task:
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
+
+task:
+ name: "sage prover"
+ << : *LINUX_CONTAINER
+ test_script:
+ - cd sage
+ - sage prove_group_implementations.sage
diff --git a/src/secp256k1/.gitattributes b/src/secp256k1/.gitattributes
index a0fa567da8..30efb2244f 100644
--- a/src/secp256k1/.gitattributes
+++ b/src/secp256k1/.gitattributes
@@ -1,2 +1,2 @@
-src/ecmult_static_pre_g.h linguist-generated
-src/ecmult_gen_static_prec_table.h linguist-generated
+src/precomputed_ecmult.c linguist-generated
+src/precomputed_ecmult_gen.c linguist-generated
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index 22cd500501..d88627d72e 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -3,14 +3,19 @@ bench_ecmult
bench_internal
tests
exhaustive_tests
-gen_ecmult_gen_static_prec_table
-gen_ecmult_static_pre_g
+precompute_ecmult_gen
+precompute_ecmult
valgrind_ctime_test
+ecdh_example
+ecdsa_example
+schnorr_example
*.exe
*.so
*.a
*.csv
!.gitignore
+*.log
+*.trs
Makefile
configure
@@ -41,6 +46,7 @@ coverage.*.html
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
+build-aux/ar-lib
build-aux/config.guess
build-aux/config.sub
build-aux/depcomp
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 7ea29bc6e3..51c5960301 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -26,12 +26,14 @@ noinst_HEADERS += src/eckey.h
noinst_HEADERS += src/eckey_impl.h
noinst_HEADERS += src/ecmult.h
noinst_HEADERS += src/ecmult_impl.h
+noinst_HEADERS += src/ecmult_compute_table.h
+noinst_HEADERS += src/ecmult_compute_table_impl.h
noinst_HEADERS += src/ecmult_const.h
noinst_HEADERS += src/ecmult_const_impl.h
noinst_HEADERS += src/ecmult_gen.h
noinst_HEADERS += src/ecmult_gen_impl.h
-noinst_HEADERS += src/ecmult_gen_prec.h
-noinst_HEADERS += src/ecmult_gen_prec_impl.h
+noinst_HEADERS += src/ecmult_gen_compute_table.h
+noinst_HEADERS += src/ecmult_gen_compute_table_impl.h
noinst_HEADERS += src/field_10x26.h
noinst_HEADERS += src/field_10x26_impl.h
noinst_HEADERS += src/field_5x52.h
@@ -42,6 +44,8 @@ noinst_HEADERS += src/modinv32.h
noinst_HEADERS += src/modinv32_impl.h
noinst_HEADERS += src/modinv64.h
noinst_HEADERS += src/modinv64_impl.h
+noinst_HEADERS += src/precomputed_ecmult.h
+noinst_HEADERS += src/precomputed_ecmult_gen.h
noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/scratch.h
@@ -59,13 +63,19 @@ noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
+noinst_HEADERS += examples/random.h
+
+PRECOMPUTED_LIB = libsecp256k1_precomputed.la
+noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
+libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c
+libsecp256k1_precomputed_la_CPPFLAGS = $(SECP_INCLUDES)
if USE_EXTERNAL_ASM
COMMON_LIB = libsecp256k1_common.la
-noinst_LTLIBRARIES = $(COMMON_LIB)
else
COMMON_LIB =
endif
+noinst_LTLIBRARIES += $(COMMON_LIB)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
@@ -78,8 +88,8 @@ endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
-libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB)
-libsecp256k1_la_LDFLAGS = -no-undefined
+libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
+libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
if VALGRIND_ENABLED
libsecp256k1_la_CPPFLAGS += -DVALGRIND
@@ -91,10 +101,10 @@ noinst_PROGRAMS += bench bench_internal bench_ecmult
bench_SOURCES = src/bench.c
bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
-bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_internal_CPPFLAGS = $(SECP_INCLUDES)
bench_ecmult_SOURCES = src/bench_ecmult.c
-bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_ecmult_CPPFLAGS = $(SECP_INCLUDES)
endif
@@ -112,7 +122,7 @@ endif
if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
endif
-tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
+tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
tests_LDFLAGS = -static
TESTS += tests
endif
@@ -124,22 +134,57 @@ exhaustive_tests_CPPFLAGS = $(SECP_INCLUDES)
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
+# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables).
exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
+if USE_EXAMPLES
+noinst_PROGRAMS += ecdsa_example
+ecdsa_example_SOURCES = examples/ecdsa.c
+ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
+ecdsa_example_LDADD = libsecp256k1.la
+ecdsa_example_LDFLAGS = -static
+if BUILD_WINDOWS
+ecdsa_example_LDFLAGS += -lbcrypt
+endif
+TESTS += ecdsa_example
+if ENABLE_MODULE_ECDH
+noinst_PROGRAMS += ecdh_example
+ecdh_example_SOURCES = examples/ecdh.c
+ecdh_example_CPPFLAGS = -I$(top_srcdir)/include
+ecdh_example_LDADD = libsecp256k1.la
+ecdh_example_LDFLAGS = -static
+if BUILD_WINDOWS
+ecdh_example_LDFLAGS += -lbcrypt
+endif
+TESTS += ecdh_example
+endif
+if ENABLE_MODULE_SCHNORRSIG
+noinst_PROGRAMS += schnorr_example
+schnorr_example_SOURCES = examples/schnorr.c
+schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
+schnorr_example_LDADD = libsecp256k1.la
+schnorr_example_LDFLAGS = -static
+if BUILD_WINDOWS
+schnorr_example_LDFLAGS += -lbcrypt
+endif
+TESTS += schnorr_example
+endif
+endif
+
### Precomputed tables
-EXTRA_PROGRAMS = gen_ecmult_static_pre_g gen_ecmult_gen_static_prec_table
+EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
CLEANFILES = $(EXTRA_PROGRAMS)
-gen_ecmult_static_pre_g_SOURCES = src/gen_ecmult_static_pre_g.c
-gen_ecmult_static_pre_g_CPPFLAGS = $(SECP_INCLUDES)
-gen_ecmult_static_pre_g_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+precompute_ecmult_SOURCES = src/precompute_ecmult.c
+precompute_ecmult_CPPFLAGS = $(SECP_INCLUDES)
+precompute_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
-gen_ecmult_gen_static_prec_table_SOURCES = src/gen_ecmult_gen_static_prec_table.c
-gen_ecmult_gen_static_prec_table_CPPFLAGS = $(SECP_INCLUDES)
-gen_ecmult_gen_static_prec_table_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
+precompute_ecmult_gen_CPPFLAGS = $(SECP_INCLUDES)
+precompute_ecmult_gen_LDADD = $(SECP_LIBS) $(COMMON_LIB)
# See Automake manual, Section "Errors with distclean".
# We don't list any dependencies for the prebuilt files here because
@@ -147,15 +192,14 @@ gen_ecmult_gen_static_prec_table_LDADD = $(SECP_LIBS) $(COMMON_LIB)
# build by a normal user) depends on mtimes, and thus is very fragile.
# This means that rebuilds of the prebuilt files always need to be
# forced by deleting them, e.g., by invoking `make clean-precomp`.
-src/ecmult_static_pre_g.h:
- $(MAKE) $(AM_MAKEFLAGS) gen_ecmult_static_pre_g$(EXEEXT)
- ./gen_ecmult_static_pre_g$(EXEEXT)
-src/ecmult_gen_static_prec_table.h:
- $(MAKE) $(AM_MAKEFLAGS) gen_ecmult_gen_static_prec_table$(EXEEXT)
- ./gen_ecmult_gen_static_prec_table$(EXEEXT)
-
-PRECOMP = src/ecmult_gen_static_prec_table.h src/ecmult_static_pre_g.h
-noinst_HEADERS += $(PRECOMP)
+src/precomputed_ecmult.c:
+ $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT)
+ ./precompute_ecmult$(EXEEXT)
+src/precomputed_ecmult_gen.c:
+ $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult_gen$(EXEEXT)
+ ./precompute_ecmult_gen$(EXEEXT)
+
+PRECOMP = src/precomputed_ecmult_gen.c src/precomputed_ecmult.c
precomp: $(PRECOMP)
# Ensure the prebuilt files will be build first (only if they don't exist,
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 5fc07dd4fa..f5db915e83 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -17,9 +17,7 @@ Features:
* Suitable for embedded systems.
* Optional module for public key recovery.
* Optional module for ECDH key exchange.
-* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) (experimental).
-
-Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
+* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
Implementation details
----------------------
@@ -35,6 +33,7 @@ Implementation details
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
* Using 10 26-bit limbs (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
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
@@ -69,6 +68,16 @@ libsecp256k1 is built using autotools:
$ make check # run the test suite
$ sudo make install # optional
+To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
+
+Usage examples
+-----------
+ Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
+ * [ECDSA example](examples/ecdsa.c)
+ * [Schnorr signatures example](examples/schnorr.c)
+ * [Deriving a shared secret (ECDH) example](examples/ecdh.c)
+ To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
+
Test coverage
-----------
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index c14d09fa1b..dda770e001 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -38,3 +38,16 @@ AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
unset flag_works
AC_SUBST($2)
])
+
+dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode)
+dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled
+AC_DEFUN([SECP_SET_DEFAULT], [
+ if test "${enable_dev_mode+set}" != set; then
+ AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]])
+ fi
+ if test x"$enable_dev_mode" = x"yes"; then
+ $1="$3"
+ else
+ $1="$2"
+ fi
+])
diff --git a/src/secp256k1/ci/cirrus.sh b/src/secp256k1/ci/cirrus.sh
index e27b34782e..b85f012d3f 100755
--- a/src/secp256k1/ci/cirrus.sh
+++ b/src/secp256k1/ci/cirrus.sh
@@ -15,9 +15,11 @@ valgrind --version || true
./configure \
--enable-experimental="$EXPERIMENTAL" \
--with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \
- --enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
+ --with-ecmult-window="$ECMULTWINDOW" \
+ --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-schnorrsig="$SCHNORRSIG" \
+ --enable-examples="$EXAMPLES" \
--with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS
diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile
index fdba12aa00..5cccbb5565 100644
--- a/src/secp256k1/ci/linux-debian.Dockerfile
+++ b/src/secp256k1/ci/linux-debian.Dockerfile
@@ -19,7 +19,8 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \
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 \
- wine gcc-mingw-w64-x86-64
+ wine gcc-mingw-w64-x86-64 \
+ sagemath
# Run a dummy command in wine to make it set up configuration
RUN wine64-stable xcopy || true
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 94feea7bb7..2db59a8ff3 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -1,30 +1,47 @@
AC_PREREQ([2.60])
-AC_INIT([libsecp256k1],[0.1])
+
+# 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.
+define(_PKG_VERSION_MAJOR, 0)
+define(_PKG_VERSION_MINOR, 1)
+define(_PKG_VERSION_BUILD, 0)
+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:
+# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+# 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, 0)
+define(_LIB_VERSION_REVISION, 0)
+define(_LIB_VERSION_AGE, 0)
+
+AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_BUILD)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-pre]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
+
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
-AM_INIT_AUTOMAKE([foreign subdir-objects])
-LT_INIT([win32-dll])
+# Require Automake 1.11.2 for AM_PROG_AR
+AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
# Make the compilation flags quiet unless V=1 is used.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-PKG_PROG_PKG_CONFIG
-
-AC_PATH_TOOL(AR, ar)
-AC_PATH_TOOL(RANLIB, ranlib)
-AC_PATH_TOOL(STRIP, strip)
-
-AM_PROG_CC_C_O
-AC_PROG_CC_C89
+AC_PROG_CC
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
AM_PROG_AS
+AM_PROG_AR
+
+LT_INIT([win32-dll])
+
+build_windows=no
case $host_os in
*darwin*)
@@ -49,6 +66,9 @@ case $host_os in
fi
fi
;;
+ cygwin*|mingw*)
+ build_windows=yes
+ ;;
esac
# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS.
@@ -91,55 +111,54 @@ SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
### Define config arguments
###
+# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly.
+# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set.
+AC_ARG_ENABLE(dev_mode, [], [],
+ [enable_dev_mode=no])
+
AC_ARG_ENABLE(benchmark,
- AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
- [use_benchmark=$enableval],
- [use_benchmark=yes])
+ AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])])
AC_ARG_ENABLE(coverage,
- AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]),
- [enable_coverage=$enableval],
- [enable_coverage=no])
+ AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_coverage], [no], [no])])
AC_ARG_ENABLE(tests,
- AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]),
- [use_tests=$enableval],
- [use_tests=yes])
+ AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
AC_ARG_ENABLE(experimental,
- AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]),
- [use_experimental=$enableval],
- [use_experimental=no])
+ AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
AC_ARG_ENABLE(exhaustive_tests,
- AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]),
- [use_exhaustive_tests=$enableval],
- [use_exhaustive_tests=yes])
+ AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])])
+
+AC_ARG_ENABLE(examples,
+ AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_examples], [no], [yes])])
AC_ARG_ENABLE(module_ecdh,
- AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation]),
- [enable_module_ecdh=$enableval],
- [enable_module_ecdh=no])
+ AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
AC_ARG_ENABLE(module_recovery,
- AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]),
- [enable_module_recovery=$enableval],
- [enable_module_recovery=no])
+ AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])])
AC_ARG_ENABLE(module_extrakeys,
- AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
- [enable_module_extrakeys=$enableval],
- [enable_module_extrakeys=no])
+ AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])])
AC_ARG_ENABLE(module_schnorrsig,
- AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
- [enable_module_schnorrsig=$enableval],
- [enable_module_schnorrsig=no])
+ AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
AC_ARG_ENABLE(external_default_callbacks,
- AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
- [use_external_default_callbacks=$enableval],
- [use_external_default_callbacks=no])
+ AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
+ [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
# Test-only override of the (autodetected by the C code) "widemul" setting.
# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
@@ -152,7 +171,7 @@ 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].]
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.]
-[A window size larger than 15 will require you delete the prebuilt ecmult_static_pre_g.h file so that it can be rebuilt.]
+[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.]
[For very large window sizes, use "make -j 1" to reduce memory use during compilation.]
["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]]
)],
@@ -229,14 +248,14 @@ else
fi
# Select assembly optimization
-use_external_asm=no
+enable_external_asm=no
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
arm)
- use_external_asm=yes
+ enable_external_asm=yes
;;
no)
;;
@@ -245,7 +264,7 @@ no)
;;
esac
-if test x"$use_external_asm" = x"yes"; then
+if test x"$enable_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi
@@ -333,7 +352,7 @@ if test x"$enable_module_extrakeys" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
fi
-if test x"$use_external_default_callbacks" = x"yes"; then
+if test x"$enable_external_default_callbacks" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
fi
@@ -345,16 +364,8 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
AC_MSG_NOTICE([WARNING: experimental build])
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
- AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
- AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
AC_MSG_NOTICE([******])
else
- if test x"$enable_module_extrakeys" = x"yes"; then
- AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
- fi
- if test x"$enable_module_schnorrsig" = x"yes"; then
- AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
- fi
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
fi
@@ -372,29 +383,30 @@ AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AC_SUBST(SECP_CFLAGS)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
-AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
-AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
-AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
+AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
+AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
+AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
+AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
-AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
+AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
-
-# Make sure nothing new is exported so that we don't break the cache.
-PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
-unset PKG_CONFIG_PATH
-PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
+AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
+AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
+AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
+AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE)
AC_OUTPUT
echo
echo "Build Options:"
-echo " with external callbacks = $use_external_default_callbacks"
-echo " with benchmarks = $use_benchmark"
-echo " with tests = $use_tests"
+echo " with external callbacks = $enable_external_default_callbacks"
+echo " with benchmarks = $enable_benchmark"
+echo " with tests = $enable_tests"
echo " with coverage = $enable_coverage"
+echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
diff --git a/src/secp256k1/doc/CHANGELOG.md b/src/secp256k1/doc/CHANGELOG.md
new file mode 100644
index 0000000000..3c4c2e4583
--- /dev/null
+++ b/src/secp256k1/doc/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Changelog
+
+This file is currently only a template for future use.
+
+Each change falls into one of the following categories: Added, Changed, Deprecated, Removed, Fixed or Security.
+
+## [Unreleased]
+
+## [MAJOR.MINOR.PATCH] - YYYY-MM-DD
+
+### Added/Changed/Deprecated/Removed/Fixed/Security
+- [Title with link to Pull Request](https://link-to-pr)
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
new file mode 100644
index 0000000000..a35b8a9db3
--- /dev/null
+++ b/src/secp256k1/doc/release-process.md
@@ -0,0 +1,14 @@
+# Release Process
+
+1. Open PR to master that
+ 1. adds release notes to `doc/CHANGELOG.md` and
+ 2. if this is **not** a patch release, updates `_PKG_VERSION_{MAJOR,MINOR}` and `_LIB_VERSIONS_*` in `configure.ac`
+2. After the PR is merged,
+ * if this is **not** a patch release, create a release branch with name `MAJOR.MINOR`.
+ Make sure that the branch contains the right commits.
+ Create commit on the release branch that sets `_PKG_VERSION_IS_RELEASE` in `configure.ac` to `true`.
+ * if this **is** a patch release, open a pull request with the bugfixes to the `MAJOR.MINOR` branch.
+ Also include the release note commit bump `_PKG_VERSION_BUILD` and `_LIB_VERSIONS_*` in `configure.ac`.
+4. Tag the commit with `git tag -s vMAJOR.MINOR.PATCH`.
+5. Push branch and tag with `git push origin --tags`.
+6. Create a new GitHub release with a link to the corresponding entry in `doc/CHANGELOG.md`.
diff --git a/src/secp256k1/examples/EXAMPLES_COPYING b/src/secp256k1/examples/EXAMPLES_COPYING
new file mode 100644
index 0000000000..0e259d42c9
--- /dev/null
+++ b/src/secp256k1/examples/EXAMPLES_COPYING
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/src/secp256k1/examples/ecdh.c b/src/secp256k1/examples/ecdh.c
new file mode 100644
index 0000000000..d7e8add361
--- /dev/null
+++ b/src/secp256k1/examples/ecdh.c
@@ -0,0 +1,127 @@
+/*************************************************************************
+ * Written in 2020-2022 by Elichai Turkel *
+ * To the extent possible under law, the author(s) have dedicated all *
+ * copyright and related and neighboring rights to the software in this *
+ * file to the public domain worldwide. This software is distributed *
+ * without any warranty. For the CC0 Public Domain Dedication, see *
+ * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
+ *************************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include <secp256k1.h>
+#include <secp256k1_ecdh.h>
+
+#include "random.h"
+
+
+int main(void) {
+ unsigned char seckey1[32];
+ unsigned char seckey2[32];
+ unsigned char compressed_pubkey1[33];
+ unsigned char compressed_pubkey2[33];
+ unsigned char shared_secret1[32];
+ unsigned char shared_secret2[32];
+ unsigned char randomize[32];
+ int return_val;
+ size_t len;
+ secp256k1_pubkey pubkey1;
+ secp256k1_pubkey pubkey2;
+
+ /* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create`
+ * needs a context object initialized for signing, which is why we create
+ * a context with the SECP256K1_CONTEXT_SIGN flag.
+ * (The docs for `secp256k1_ecdh` don't require any special context, just
+ * some initialized context) */
+ secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ if (!fill_random(randomize, sizeof(randomize))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+ /* Randomizing the context is recommended to protect against side-channel
+ * leakage See `secp256k1_context_randomize` in secp256k1.h for more
+ * information about it. This should never fail. */
+ return_val = secp256k1_context_randomize(ctx, randomize);
+ assert(return_val);
+
+ /*** Key Generation ***/
+
+ /* If the secret key is zero or out of range (bigger than secp256k1's
+ * order), we try to sample a new key. Note that the probability of this
+ * happening is negligible. */
+ while (1) {
+ if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+ if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
+ break;
+ }
+ }
+
+ /* Public key creation using a valid context with a verified secret key should never fail */
+ return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1);
+ assert(return_val);
+ return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2);
+ assert(return_val);
+
+ /* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */
+ len = sizeof(compressed_pubkey1);
+ return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED);
+ assert(return_val);
+ /* Should be the same size as the size of the output, because we passed a 33 byte array. */
+ assert(len == sizeof(compressed_pubkey1));
+
+ /* Serialize pubkey2 in a compressed form (33 bytes) */
+ len = sizeof(compressed_pubkey2);
+ return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED);
+ assert(return_val);
+ /* Should be the same size as the size of the output, because we passed a 33 byte array. */
+ assert(len == sizeof(compressed_pubkey2));
+
+ /*** Creating the shared secret ***/
+
+ /* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified
+ * seckey and valid pubkey */
+ return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL);
+ assert(return_val);
+
+ /* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified
+ * seckey and valid pubkey */
+ return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL);
+ assert(return_val);
+
+ /* Both parties should end up with the same shared secret */
+ return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1));
+ assert(return_val == 0);
+
+ printf("Secret Key1: ");
+ print_hex(seckey1, sizeof(seckey1));
+ printf("Compressed Pubkey1: ");
+ print_hex(compressed_pubkey1, sizeof(compressed_pubkey1));
+ printf("\nSecret Key2: ");
+ print_hex(seckey2, sizeof(seckey2));
+ printf("Compressed Pubkey2: ");
+ print_hex(compressed_pubkey2, sizeof(compressed_pubkey2));
+ printf("\nShared Secret: ");
+ print_hex(shared_secret1, sizeof(shared_secret1));
+
+ /* This will clear everything from the context and free the memory */
+ secp256k1_context_destroy(ctx);
+
+ /* It's best practice to try to clear secrets from memory after using them.
+ * This is done because some bugs can allow an attacker to leak memory, for
+ * example through "out of bounds" array access (see Heartbleed), Or the OS
+ * swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
+ *
+ * TODO: Prevent these writes from being optimized out, as any good compiler
+ * will remove any writes that aren't used. */
+ memset(seckey1, 0, sizeof(seckey1));
+ memset(seckey2, 0, sizeof(seckey2));
+ memset(shared_secret1, 0, sizeof(shared_secret1));
+ memset(shared_secret2, 0, sizeof(shared_secret2));
+
+ return 0;
+}
diff --git a/src/secp256k1/examples/ecdsa.c b/src/secp256k1/examples/ecdsa.c
new file mode 100644
index 0000000000..434c856ba0
--- /dev/null
+++ b/src/secp256k1/examples/ecdsa.c
@@ -0,0 +1,137 @@
+/*************************************************************************
+ * Written in 2020-2022 by Elichai Turkel *
+ * To the extent possible under law, the author(s) have dedicated all *
+ * copyright and related and neighboring rights to the software in this *
+ * file to the public domain worldwide. This software is distributed *
+ * without any warranty. For the CC0 Public Domain Dedication, see *
+ * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
+ *************************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include <secp256k1.h>
+
+#include "random.h"
+
+
+
+int main(void) {
+ /* Instead of signing the message directly, we must sign a 32-byte hash.
+ * Here the message is "Hello, world!" and the hash function was SHA-256.
+ * An actual implementation should just call SHA-256, but this example
+ * hardcodes the output to avoid depending on an additional library.
+ * See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */
+ unsigned char msg_hash[32] = {
+ 0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,
+ 0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,
+ 0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,
+ 0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,
+ };
+ unsigned char seckey[32];
+ unsigned char randomize[32];
+ unsigned char compressed_pubkey[33];
+ unsigned char serialized_signature[64];
+ size_t len;
+ int is_signature_valid;
+ int return_val;
+ secp256k1_pubkey pubkey;
+ secp256k1_ecdsa_signature sig;
+ /* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs
+ * a context object initialized for signing and `secp256k1_ecdsa_verify` needs
+ * a context initialized for verification, which is why we create a context
+ * for both signing and verification with the SECP256K1_CONTEXT_SIGN and
+ * SECP256K1_CONTEXT_VERIFY flags. */
+ secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ if (!fill_random(randomize, sizeof(randomize))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+ /* Randomizing the context is recommended to protect against side-channel
+ * leakage See `secp256k1_context_randomize` in secp256k1.h for more
+ * information about it. This should never fail. */
+ return_val = secp256k1_context_randomize(ctx, randomize);
+ assert(return_val);
+
+ /*** Key Generation ***/
+
+ /* If the secret key is zero or out of range (bigger than secp256k1's
+ * order), we try to sample a new key. Note that the probability of this
+ * happening is negligible. */
+ while (1) {
+ if (!fill_random(seckey, sizeof(seckey))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+ if (secp256k1_ec_seckey_verify(ctx, seckey)) {
+ break;
+ }
+ }
+
+ /* Public key creation using a valid context with a verified secret key should never fail */
+ return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey);
+ assert(return_val);
+
+ /* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */
+ len = sizeof(compressed_pubkey);
+ return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED);
+ assert(return_val);
+ /* Should be the same size as the size of the output, because we passed a 33 byte array. */
+ assert(len == sizeof(compressed_pubkey));
+
+ /*** Signing ***/
+
+ /* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a
+ * custom nonce function, passing `NULL` will use the RFC-6979 safe default.
+ * Signing with a valid context, verified secret key
+ * and the default nonce function should never fail. */
+ return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL);
+ assert(return_val);
+
+ /* Serialize the signature in a compact form. Should always return 1
+ * according to the documentation in secp256k1.h. */
+ return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig);
+ assert(return_val);
+
+
+ /*** Verification ***/
+
+ /* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */
+ if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) {
+ printf("Failed parsing the signature\n");
+ return 1;
+ }
+
+ /* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
+ if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {
+ printf("Failed parsing the public key\n");
+ return 1;
+ }
+
+ /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
+ is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey);
+
+ printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
+ printf("Secret Key: ");
+ print_hex(seckey, sizeof(seckey));
+ printf("Public Key: ");
+ print_hex(compressed_pubkey, sizeof(compressed_pubkey));
+ printf("Signature: ");
+ print_hex(serialized_signature, sizeof(serialized_signature));
+
+
+ /* This will clear everything from the context and free the memory */
+ secp256k1_context_destroy(ctx);
+
+ /* It's best practice to try to clear secrets from memory after using them.
+ * This is done because some bugs can allow an attacker to leak memory, for
+ * example through "out of bounds" array access (see Heartbleed), Or the OS
+ * swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
+ *
+ * TODO: Prevent these writes from being optimized out, as any good compiler
+ * will remove any writes that aren't used. */
+ memset(seckey, 0, sizeof(seckey));
+
+ return 0;
+}
diff --git a/src/secp256k1/examples/random.h b/src/secp256k1/examples/random.h
new file mode 100644
index 0000000000..439226f09f
--- /dev/null
+++ b/src/secp256k1/examples/random.h
@@ -0,0 +1,73 @@
+/*************************************************************************
+ * Copyright (c) 2020-2021 Elichai Turkel *
+ * Distributed under the CC0 software license, see the accompanying file *
+ * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
+ *************************************************************************/
+
+/*
+ * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
+ * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
+ *
+ * Platform randomness sources:
+ * Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
+ * macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
+ * FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
+ * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
+ * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
+ */
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <ntstatus.h>
+#include <bcrypt.h>
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/random.h>
+#elif defined(__OpenBSD__)
+#include <unistd.h>
+#else
+#error "Couldn't identify the OS"
+#endif
+
+#include <stddef.h>
+#include <limits.h>
+#include <stdio.h>
+
+
+/* Returns 1 on success, and 0 on failure. */
+static int fill_random(unsigned char* data, size_t size) {
+#if defined(_WIN32)
+ NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+ if (res != STATUS_SUCCESS || size > ULONG_MAX) {
+ return 0;
+ } else {
+ return 1;
+ }
+#elif defined(__linux__) || defined(__FreeBSD__)
+ /* If `getrandom(2)` is not available you should fallback to /dev/urandom */
+ ssize_t res = getrandom(data, size, 0);
+ if (res < 0 || (size_t)res != size ) {
+ return 0;
+ } else {
+ return 1;
+ }
+#elif defined(__APPLE__) || defined(__OpenBSD__)
+ /* If `getentropy(2)` is not available you should fallback to either
+ * `SecRandomCopyBytes` or /dev/urandom */
+ int res = getentropy(data, size);
+ if (res == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+#endif
+ return 0;
+}
+
+static void print_hex(unsigned char* data, size_t size) {
+ size_t i;
+ printf("0x");
+ for (i = 0; i < size; i++) {
+ printf("%02x", data[i]);
+ }
+ printf("\n");
+}
diff --git a/src/secp256k1/examples/schnorr.c b/src/secp256k1/examples/schnorr.c
new file mode 100644
index 0000000000..82eb07d5d7
--- /dev/null
+++ b/src/secp256k1/examples/schnorr.c
@@ -0,0 +1,152 @@
+/*************************************************************************
+ * Written in 2020-2022 by Elichai Turkel *
+ * To the extent possible under law, the author(s) have dedicated all *
+ * copyright and related and neighboring rights to the software in this *
+ * file to the public domain worldwide. This software is distributed *
+ * without any warranty. For the CC0 Public Domain Dedication, see *
+ * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
+ *************************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include <secp256k1.h>
+#include <secp256k1_extrakeys.h>
+#include <secp256k1_schnorrsig.h>
+
+#include "random.h"
+
+int main(void) {
+ unsigned char msg[12] = "Hello World!";
+ unsigned char msg_hash[32];
+ unsigned char tag[17] = "my_fancy_protocol";
+ unsigned char seckey[32];
+ unsigned char randomize[32];
+ unsigned char auxiliary_rand[32];
+ unsigned char serialized_pubkey[32];
+ unsigned char signature[64];
+ int is_signature_valid;
+ int return_val;
+ secp256k1_xonly_pubkey pubkey;
+ secp256k1_keypair keypair;
+ /* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create`
+ * needs a context object initialized for signing. And in secp256k1_schnorrsig.h
+ * they state that `secp256k1_schnorrsig_verify` needs a context initialized for
+ * verification, which is why we create a context for both signing and verification
+ * with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */
+ secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ if (!fill_random(randomize, sizeof(randomize))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+ /* Randomizing the context is recommended to protect against side-channel
+ * leakage See `secp256k1_context_randomize` in secp256k1.h for more
+ * information about it. This should never fail. */
+ return_val = secp256k1_context_randomize(ctx, randomize);
+ assert(return_val);
+
+ /*** Key Generation ***/
+
+ /* If the secret key is zero or out of range (bigger than secp256k1's
+ * order), we try to sample a new key. Note that the probability of this
+ * happening is negligible. */
+ while (1) {
+ if (!fill_random(seckey, sizeof(seckey))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+ /* Try to create a keypair with a valid context, it should only fail if
+ * the secret key is zero or out of range. */
+ if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
+ break;
+ }
+ }
+
+ /* Extract the X-only public key from the keypair. We pass NULL for
+ * `pk_parity` as the parity isn't needed for signing or verification.
+ * `secp256k1_keypair_xonly_pub` supports returning the parity for
+ * other use cases such as tests or verifying Taproot tweaks.
+ * This should never fail with a valid context and public key. */
+ return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair);
+ assert(return_val);
+
+ /* Serialize the public key. Should always return 1 for a valid public key. */
+ return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey);
+ assert(return_val);
+
+ /*** Signing ***/
+
+ /* Instead of signing (possibly very long) messages directly, we sign a
+ * 32-byte hash of the message in this example.
+ *
+ * We use secp256k1_tagged_sha256 to create this hash. This function expects
+ * a context-specific "tag", which restricts the context in which the signed
+ * messages should be considered valid. For example, if protocol A mandates
+ * to use the tag "my_fancy_protocol" and protocol B mandates to use the tag
+ * "my_boring_protocol", then signed messages from protocol A will never be
+ * valid in protocol B (and vice versa), even if keys are reused across
+ * protocols. This implements "domain separation", which is considered good
+ * practice. It avoids attacks in which users are tricked into signing a
+ * message that has intended consequences in the intended context (e.g.,
+ * protocol A) but would have unintended consequences if it were valid in
+ * some other context (e.g., protocol B). */
+ return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
+ assert(return_val);
+
+ /* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */
+ if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) {
+ printf("Failed to generate randomness\n");
+ return 1;
+ }
+
+ /* Generate a Schnorr signature.
+ *
+ * We use the secp256k1_schnorrsig_sign32 function that provides a simple
+ * interface for signing 32-byte messages (which in our case is a hash of
+ * the actual message). BIP-340 recommends passing 32 bytes of randomness
+ * to the signing function to improve security against side-channel attacks.
+ * Signing with a valid context, a 32-byte message, a verified keypair, and
+ * any 32 bytes of auxiliary random data should never fail. */
+ return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand);
+ assert(return_val);
+
+ /*** Verification ***/
+
+ /* Deserialize the public key. This will return 0 if the public key can't
+ * be parsed correctly */
+ if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) {
+ printf("Failed parsing the public key\n");
+ return 1;
+ }
+
+ /* Compute the tagged hash on the received messages using the same tag as the signer. */
+ return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
+ assert(return_val);
+
+ /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
+ is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey);
+
+
+ printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
+ printf("Secret Key: ");
+ print_hex(seckey, sizeof(seckey));
+ printf("Public Key: ");
+ print_hex(serialized_pubkey, sizeof(serialized_pubkey));
+ printf("Signature: ");
+ print_hex(signature, sizeof(signature));
+
+ /* This will clear everything from the context and free the memory */
+ secp256k1_context_destroy(ctx);
+
+ /* It's best practice to try to clear secrets from memory after using them.
+ * This is done because some bugs can allow an attacker to leak memory, for
+ * example through "out of bounds" array access (see Heartbleed), Or the OS
+ * swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
+ *
+ * TODO: Prevent these writes from being optimized out, as any good compiler
+ * will remove any writes that aren't used. */
+ memset(seckey, 0, sizeof(seckey));
+
+ return 0;
+}
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 57114b8f26..86ab7e556d 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -169,6 +169,17 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_ARG_NONNULL(_x)
# endif
+/** Attribute for marking functions, types, and variables as deprecated */
+#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
+# if __has_attribute(__deprecated__)
+# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
+# else
+# define SECP256K1_DEPRECATED(_msg)
+# endif
+#else
+# define SECP256K1_DEPRECATED(_msg)
+#endif
+
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
@@ -641,7 +652,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
const secp256k1_context* ctx,
unsigned char *seckey
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
+ SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
/** Negates a public key in place.
*
@@ -681,7 +693,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
+ SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead");
/** Tweak a public key by adding tweak times the generator to it.
*
@@ -727,7 +740,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
+ SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead");
/** Tweak a public key by multiplying it by a tweak value.
*
@@ -800,7 +814,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
* implementations optimized for a specific tag can precompute the SHA256 state
* after hashing the tag hashes.
*
- * Returns 0 if the arguments are invalid and 1 otherwise.
+ * Returns: 1 always.
* Args: ctx: pointer to a context object
* Out: hash32: pointer to a 32-byte array to store the resulting hash
* In: tag: pointer to an array containing the tag
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
index a64d561b60..09cbeaaa80 100644
--- a/src/secp256k1/include/secp256k1_extrakeys.h
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -81,8 +81,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp(
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
*
- * Returns: 1 if the public key was successfully converted
- * 0 otherwise
+ * Returns: 1 always.
*
* Args: ctx: pointer to a context object.
* Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key.
@@ -172,7 +171,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
/** Get the secret key from a keypair.
*
- * Returns: 0 if the arguments are invalid. 1 otherwise.
+ * Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: seckey: pointer to a 32-byte buffer for the secret key.
* In: keypair: pointer to a keypair.
@@ -185,7 +184,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
/** Get the public key from a keypair.
*
- * Returns: 0 if the arguments are invalid. 1 otherwise.
+ * Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
* the keypair public key. If not, it's set to an invalid value.
@@ -202,7 +201,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
* This is the same as calling secp256k1_keypair_pub and then
* secp256k1_xonly_pubkey_from_pubkey.
*
- * Returns: 0 if the arguments are invalid. 1 otherwise.
+ * Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
* to the keypair public key after converting it to an
diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h
index e971ddc2aa..5fedcb07b0 100644
--- a/src/secp256k1/include/secp256k1_schnorrsig.h
+++ b/src/secp256k1/include/secp256k1_schnorrsig.h
@@ -116,7 +116,7 @@ typedef struct {
* BIP-340 "Default Signing" for a full explanation of this
* argument and for guidance if randomness is expensive.
*/
-SECP256K1_API int secp256k1_schnorrsig_sign(
+SECP256K1_API int secp256k1_schnorrsig_sign32(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg32,
@@ -124,6 +124,17 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
const unsigned char *aux_rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
+ * future versions. */
+SECP256K1_API int secp256k1_schnorrsig_sign(
+ const secp256k1_context* ctx,
+ unsigned char *sig64,
+ const unsigned char *msg32,
+ const secp256k1_keypair *keypair,
+ const unsigned char *aux_rand32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
+ SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead");
+
/** Create a Schnorr signature with a more flexible API.
*
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
index b200bfeae3..9305c215d5 100644
--- a/src/secp256k1/sage/group_prover.sage
+++ b/src/secp256k1/sage/group_prover.sage
@@ -164,6 +164,9 @@ class constraints:
def negate(self):
return constraints(zero=self.nonzero, nonzero=self.zero)
+ def map(self, fun):
+ return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()})
+
def __add__(self, other):
zero = self.zero.copy()
zero.update(other.zero)
@@ -177,6 +180,30 @@ class constraints:
def __repr__(self):
return "%s" % self
+def normalize_factor(p):
+ """Normalizes the sign of primitive polynomials (as returned by factor())
+
+ This function ensures that the polynomial has a positive leading coefficient.
+
+ This is necessary because recent sage versions (starting with v9.3 or v9.4,
+ we don't know) are inconsistent about the placement of the minus sign in
+ polynomial factorizations:
+ ```
+ sage: R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
+ sage: R((-2 * (bx - ax)) ^ 1).factor()
+ (-2) * (bx - ax)
+ sage: R((-2 * (bx - ax)) ^ 2).factor()
+ (4) * (-bx + ax)^2
+ sage: R((-2 * (bx - ax)) ^ 3).factor()
+ (8) * (-bx + ax)^3
+ ```
+ """
+ # Assert p is not 0 and that its non-zero coeffients are coprime.
+ # (We could just work with the primitive part p/p.content() but we want to be
+ # aware if factor() does not return a primitive part in future sage versions.)
+ assert p.content() == 1
+ # Ensure that the first non-zero coefficient is positive.
+ return p if p.lc() > 0 else -p
def conflicts(R, con):
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
@@ -204,10 +231,10 @@ def get_nonzero_set(R, assume):
nonzero = set()
for nz in map(numerator, assume.nonzero):
for (f,n) in nz.factor():
- nonzero.add(f)
+ nonzero.add(normalize_factor(f))
rnz = zero.reduce(nz)
for (f,n) in rnz.factor():
- nonzero.add(f)
+ nonzero.add(normalize_factor(f))
return nonzero
@@ -222,27 +249,27 @@ def prove_nonzero(R, exprs, assume):
return (False, [exprs[expr]])
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
for (f, n) in allexprs.factor():
- if f not in nonzero:
+ if normalize_factor(f) not in nonzero:
ok = False
if ok:
return (True, None)
ok = True
- for (f, n) in zero.reduce(numerator(allexprs)).factor():
- if f not in nonzero:
+ for (f, n) in zero.reduce(allexprs).factor():
+ if normalize_factor(f) not in nonzero:
ok = False
if ok:
return (True, None)
ok = True
for expr in exprs:
for (f,n) in numerator(expr).factor():
- if f not in nonzero:
+ if normalize_factor(f) not in nonzero:
ok = False
if ok:
return (True, None)
ok = True
for expr in exprs:
for (f,n) in zero.reduce(numerator(expr)).factor():
- if f not in nonzero:
+ if normalize_factor(f) not in nonzero:
expl.add(exprs[expr])
if expl:
return (False, list(expl))
@@ -254,7 +281,7 @@ def prove_zero(R, exprs, assume):
"""Check whether all of the passed expressions are provably zero, given assumptions"""
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
if not r:
- return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
+ return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e)))
zero = R.ideal(list(map(numerator, assume.zero)))
nonzero = prod(x for x in assume.nonzero)
expl = []
@@ -279,8 +306,8 @@ def describe_extra(R, assume, assumeExtra):
if base not in zero:
add = []
for (f, n) in numerator(base).factor():
- if f not in nonzero:
- add += ["%s" % f]
+ if normalize_factor(f) not in nonzero:
+ add += ["%s" % normalize_factor(f)]
if add:
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
# Iterate over the extra nonzero expressions
@@ -288,8 +315,8 @@ def describe_extra(R, assume, assumeExtra):
nzr = zeroextra.reduce(numerator(nz))
if nzr not in zeroextra:
for (f,n) in nzr.factor():
- if zeroextra.reduce(f) not in nonzero:
- ret.add("%s != 0" % zeroextra.reduce(f))
+ if normalize_factor(zeroextra.reduce(f)) not in nonzero:
+ ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f)))
return ", ".join(x for x in ret)
@@ -299,22 +326,21 @@ def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
if conflicts(R, assume):
# This formula does not apply
- return None
+ return (True, None)
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
+ if describe != "":
+ describe = " (assuming " + describe + ")"
ok, msg = prove_zero(R, require.zero, assume)
if not ok:
- return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
+ return (False, "FAIL, %s fails%s" % (str(msg), describe))
res, expl = prove_nonzero(R, require.nonzero, assume)
if not res:
- return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
+ return (False, "FAIL, %s fails%s" % (str(expl), describe))
- if describe != "":
- return "OK (assuming %s)" % describe
- else:
- return "OK"
+ return (True, "OK%s" % describe)
def concrete_verify(c):
diff --git a/src/secp256k1/sage/prove_group_implementations.sage b/src/secp256k1/sage/prove_group_implementations.sage
index a97e732f7f..96ce33506a 100644
--- a/src/secp256k1/sage/prove_group_implementations.sage
+++ b/src/secp256k1/sage/prove_group_implementations.sage
@@ -8,25 +8,20 @@ load("weierstrass_prover.sage")
def formula_secp256k1_gej_double_var(a):
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
rz = a.Z * a.Y
- rz = rz * 2
- t1 = a.X^2
- t1 = t1 * 3
- t2 = t1^2
- t3 = a.Y^2
- t3 = t3 * 2
- t4 = t3^2
- t4 = t4 * 2
- t3 = t3 * a.X
- rx = t3
- rx = rx * 4
- rx = -rx
- rx = rx + t2
- t2 = -t2
- t3 = t3 * 6
- t3 = t3 + t2
- ry = t1 * t3
- t2 = -t4
- ry = ry + t2
+ s = a.Y^2
+ l = a.X^2
+ l = l * 3
+ l = l / 2
+ t = -s
+ t = t * a.X
+ rx = l^2
+ rx = rx + t
+ rx = rx + t
+ s = s^2
+ t = t + rx
+ ry = t * l
+ ry = ry + s
+ ry = -ry
return jacobianpoint(rx, ry, rz)
def formula_secp256k1_gej_add_var(branch, a, b):
@@ -197,7 +192,8 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
rr_alt = rr
m_alt = m
n = m_alt^2
- q = n * t
+ q = -t
+ q = q * n
n = n^2
if degenerate:
n = m
@@ -210,8 +206,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
zeroes.update({rz : 'r.z=0'})
else:
nonzeroes.update({rz : 'r.z!=0'})
- rz = rz * 2
- q = -q
t = t + q
rx = t
t = t * 2
@@ -219,8 +213,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
t = t * rr_alt
t = t + n
ry = -t
- rx = rx * 4
- ry = ry * 4
+ ry = ry / 2
if a_infinity:
rx = b.X
ry = b.Y
@@ -292,15 +285,18 @@ def formula_secp256k1_gej_add_ge_old(branch, a, b):
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
if __name__ == "__main__":
- check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
- check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
- check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
- check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
- check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
+ success = True
+ success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
+ success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
+ success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
+ success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
+ success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old))
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
- check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
- check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
- check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
- check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
- check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
+ success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
+ success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
+ success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
+ success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
+ success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43))
+
+ sys.exit(int(not success))
diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage
index b770c6dafe..be9cfd4c76 100644
--- a/src/secp256k1/sage/weierstrass_prover.sage
+++ b/src/secp256k1/sage/weierstrass_prover.sage
@@ -184,6 +184,7 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
if r:
points.append(point)
+ ret = True
for za in range(1, p):
for zb in range(1, p):
for pa in points:
@@ -211,8 +212,11 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
match = True
r, e = concrete_verify(require)
if not r:
+ ret = False
print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e))
+
print()
+ return ret
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
@@ -244,15 +248,21 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
print("Formula " + name + ":")
count = 0
+ ret = True
for branch in range(branches):
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
+ assumeBranch = assumeBranch.map(lift)
+ assumeFormula = assumeFormula.map(lift)
pC.X = lift(pC.X)
pC.Y = lift(pC.Y)
pC.Z = lift(pC.Z)
pC.Infinity = lift(pC.Infinity)
for key in laws_jacobian_weierstrass:
- res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
+ success, msg = check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC)
+ if not success:
+ ret = False
+ res[key].append((msg, branch))
for key in res:
print(" %s:" % key)
@@ -262,3 +272,4 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
print(" branch %i: %s" % (x[1], x[0]))
print()
+ return ret
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index aed8216127..3c145f306c 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -140,6 +140,15 @@ void bench_scalar_inverse_var(void* arg, int iters) {
CHECK(j <= iters);
}
+void bench_field_half(void* arg, int iters) {
+ int i;
+ bench_inv *data = (bench_inv*)arg;
+
+ for (i = 0; i < iters; i++) {
+ secp256k1_fe_half(&data->fe[0]);
+ }
+}
+
void bench_field_normalize(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -354,6 +363,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);
diff --git a/src/secp256k1/src/ecmult_compute_table.h b/src/secp256k1/src/ecmult_compute_table.h
new file mode 100644
index 0000000000..665f87ff3d
--- /dev/null
+++ b/src/secp256k1/src/ecmult_compute_table.h
@@ -0,0 +1,16 @@
+/*****************************************************************************************************
+ * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
+ *****************************************************************************************************/
+
+#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_H
+#define SECP256K1_ECMULT_COMPUTE_TABLE_H
+
+/* Construct table of all odd multiples of gen in range 1..(2**(window_g-1)-1). */
+static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen);
+
+/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */
+static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen);
+
+#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_H */
diff --git a/src/secp256k1/src/ecmult_compute_table_impl.h b/src/secp256k1/src/ecmult_compute_table_impl.h
new file mode 100644
index 0000000000..69d59ce595
--- /dev/null
+++ b/src/secp256k1/src/ecmult_compute_table_impl.h
@@ -0,0 +1,49 @@
+/*****************************************************************************************************
+ * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
+ *****************************************************************************************************/
+
+#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H
+#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H
+
+#include "ecmult_compute_table.h"
+#include "group_impl.h"
+#include "field_impl.h"
+#include "ecmult.h"
+#include "util.h"
+
+static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) {
+ secp256k1_gej gj;
+ secp256k1_ge ge, dgen;
+ int j;
+
+ gj = *gen;
+ secp256k1_ge_set_gej_var(&ge, &gj);
+ secp256k1_ge_to_storage(&table[0], &ge);
+
+ secp256k1_gej_double_var(&gj, gen, NULL);
+ secp256k1_ge_set_gej_var(&dgen, &gj);
+
+ for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) {
+ secp256k1_gej_set_ge(&gj, &ge);
+ secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL);
+ secp256k1_ge_set_gej_var(&ge, &gj);
+ secp256k1_ge_to_storage(&table[j], &ge);
+ }
+}
+
+/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */
+static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen) {
+ secp256k1_gej gj;
+ int i;
+
+ secp256k1_gej_set_ge(&gj, gen);
+ secp256k1_ecmult_compute_table(table, window_g, &gj);
+ for (i = 0; i < 128; ++i) {
+ secp256k1_gej_double_var(&gj, &gj, NULL);
+ }
+ secp256k1_ecmult_compute_table(table_128, window_g, &gj);
+}
+
+#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 30b151ff9a..12dbcc6c5b 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -12,6 +12,19 @@
#include "ecmult_const.h"
#include "ecmult_impl.h"
+/** 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.
+ */
+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)];
+
+ 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);
+}
+
/* 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; \
@@ -40,7 +53,6 @@
secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \
} while(0)
-
/** Convert a number to WNAF notation.
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
* It has the following guarantees:
@@ -56,7 +68,7 @@
*/
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
int global_sign;
- int skew = 0;
+ int skew;
int word = 0;
/* 1 2 3 */
@@ -64,9 +76,7 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
int u;
int flip;
- int bit;
- secp256k1_scalar s;
- int not_neg_one;
+ secp256k1_scalar s = *scalar;
VERIFY_CHECK(w > 0);
VERIFY_CHECK(size > 0);
@@ -74,33 +84,19 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
/* Note that we cannot handle even numbers by negating them to be odd, as is
* done in other implementations, since if our scalars were specified to have
* width < 256 for performance reasons, their negations would have width 256
- * and we'd lose any performance benefit. Instead, we use a technique from
- * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
- * or 2 (for odd) to the number we are encoding, returning a skew value indicating
+ * 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.
*
* 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, inverting which of
- * {1, 2} we want to add to the scalar when ensuring that it's odd. Further
- * complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
- * we need to special-case it in this logic. */
- flip = secp256k1_scalar_is_high(scalar);
- /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
- bit = flip ^ !secp256k1_scalar_is_even(scalar);
- /* We check for negative one, since adding 2 to it will cause an overflow */
- secp256k1_scalar_negate(&s, scalar);
- not_neg_one = !secp256k1_scalar_is_one(&s);
- s = *scalar;
- secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
- /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
- * that we added two to it and flipped it. In fact for -1 these operations are
- * identical. We only flipped, but since skewing is required (in the sense that
- * the skew must be 1 or 2, never zero) and flipping is not, we need to change
- * our flags to claim that we only skewed. */
+ * 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);
- global_sign *= not_neg_one * 2 - 1;
- skew = 1 << bit;
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
@@ -214,42 +210,22 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
}
}
- secp256k1_fe_mul(&r->z, &r->z, &Z);
-
{
/* Correct for wNAF skew */
- secp256k1_ge correction = *a;
- secp256k1_ge_storage correction_1_stor;
- secp256k1_ge_storage correction_lam_stor;
- secp256k1_ge_storage a2_stor;
secp256k1_gej tmpj;
- secp256k1_gej_set_ge(&tmpj, &correction);
- secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
- secp256k1_ge_set_gej(&correction, &tmpj);
- secp256k1_ge_to_storage(&correction_1_stor, a);
- if (size > 128) {
- secp256k1_ge_to_storage(&correction_lam_stor, a);
- }
- secp256k1_ge_to_storage(&a2_stor, &correction);
- /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
- secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
- if (size > 128) {
- secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
- }
-
- /* Apply the correction */
- secp256k1_ge_from_storage(&correction, &correction_1_stor);
- secp256k1_ge_neg(&correction, &correction);
- secp256k1_gej_add_ge(r, r, &correction);
+ secp256k1_ge_neg(&tmpa, &pre_a[0]);
+ secp256k1_gej_add_ge(&tmpj, r, &tmpa);
+ secp256k1_gej_cmov(r, &tmpj, skew_1);
if (size > 128) {
- secp256k1_ge_from_storage(&correction, &correction_lam_stor);
- secp256k1_ge_neg(&correction, &correction);
- secp256k1_ge_mul_lambda(&correction, &correction);
- secp256k1_gej_add_ge(r, r, &correction);
+ secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
+ secp256k1_gej_add_ge(&tmpj, r, &tmpa);
+ secp256k1_gej_cmov(r, &tmpj, skew_lam);
}
}
+
+ secp256k1_fe_mul(&r->z, &r->z, &Z);
}
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_gen_prec.h b/src/secp256k1/src/ecmult_gen_compute_table.h
index 0cfcde9b79..e577158d92 100644
--- a/src/secp256k1/src/ecmult_gen_prec.h
+++ b/src/secp256k1/src/ecmult_gen_compute_table.h
@@ -4,11 +4,11 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#ifndef SECP256K1_ECMULT_GEN_PREC_H
-#define SECP256K1_ECMULT_GEN_PREC_H
+#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H
+#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H
#include "ecmult_gen.h"
-static void secp256k1_ecmult_gen_create_prec_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits);
+static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits);
-#endif /* SECP256K1_ECMULT_GEN_PREC_H */
+#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */
diff --git a/src/secp256k1/src/ecmult_gen_prec_impl.h b/src/secp256k1/src/ecmult_gen_compute_table_impl.h
index bac76c8b13..ff6a2992dc 100644
--- a/src/secp256k1/src/ecmult_gen_prec_impl.h
+++ b/src/secp256k1/src/ecmult_gen_compute_table_impl.h
@@ -4,16 +4,16 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#ifndef SECP256K1_ECMULT_GEN_PREC_IMPL_H
-#define SECP256K1_ECMULT_GEN_PREC_IMPL_H
+#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H
+#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H
-#include "ecmult_gen_prec.h"
+#include "ecmult_gen_compute_table.h"
#include "group_impl.h"
#include "field_impl.h"
#include "ecmult_gen.h"
#include "util.h"
-static void secp256k1_ecmult_gen_create_prec_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits) {
+static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits) {
int g = ECMULT_GEN_PREC_G(bits);
int n = ECMULT_GEN_PREC_N(bits);
@@ -78,4 +78,4 @@ static void secp256k1_ecmult_gen_create_prec_table(secp256k1_ge_storage* table,
free(prec);
}
-#endif /* SECP256K1_ECMULT_GEN_PREC_IMPL_H */
+#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 6a6ab9a4b5..2c8a503acc 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -12,7 +12,7 @@
#include "group.h"
#include "ecmult_gen.h"
#include "hash_impl.h"
-#include "ecmult_gen_static_prec_table.h"
+#include "precomputed_ecmult_gen.h"
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) {
secp256k1_ecmult_gen_blind(ctx, NULL);
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 5bd4d4d23d..bbc820c77c 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -14,7 +14,7 @@
#include "group.h"
#include "scalar.h"
#include "ecmult.h"
-#include "ecmult_static_pre_g.h"
+#include "precomputed_ecmult.h"
#if defined(EXHAUSTIVE_TEST_ORDER)
/* We need to lower these values for exhaustive tests because
@@ -47,7 +47,7 @@
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
#define PIPPENGER_SCRATCH_OBJECTS 6
-#define STRAUSS_SCRATCH_OBJECTS 7
+#define STRAUSS_SCRATCH_OBJECTS 5
#define PIPPENGER_MAX_BUCKET_WINDOW 12
@@ -56,14 +56,23 @@
#define ECMULT_MAX_POINTS_PER_BATCH 5000000
-/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
- * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
- * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
- * Prej's Z values are undefined, except for the last value.
+/** Fill a table 'pre_a' with precomputed odd multiples of a.
+ * pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements.
+ * zr needs space for n field elements.
+ *
+ * Although pre_a is an array of _ge rather than _gej, it actually represents elements
+ * in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates
+ * can be recovered using z and zr. Using the notation z(b) to represent the omitted
+ * z coordinate of b:
+ * - z(pre_a[n-1]) = 'z'
+ * - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0
+ *
+ * Lastly the zr[0] value, which isn't used above, is set so that:
+ * - a.z = z(pre_a[0]) / zr[0]
*/
-static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {
- secp256k1_gej d;
- secp256k1_ge a_ge, d_ge;
+static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
+ secp256k1_gej d, ai;
+ secp256k1_ge d_ge;
int i;
VERIFY_CHECK(!a->infinity);
@@ -71,75 +80,74 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, sec
secp256k1_gej_double_var(&d, a, NULL);
/*
- * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate
- * of 'd', and scale the 1P starting value's x/y coordinates without changing its z.
+ * Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z.
+ * The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve.
+ * In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C).
+ *
+ * phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C)
+ * d_ge := phi(d) = (d.x, d.y, 1)
+ * ai := phi(a) = (a.x*C^2, a.y*C^3, a.z)
+ *
+ * The group addition functions work correctly on these isomorphic curves.
+ * In particular phi(d) is easy to represent in affine coordinates under this isomorphism.
+ * This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise.
*/
- d_ge.x = d.x;
- d_ge.y = d.y;
- d_ge.infinity = 0;
-
- secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);
- prej[0].x = a_ge.x;
- prej[0].y = a_ge.y;
- prej[0].z = a->z;
- prej[0].infinity = 0;
+ secp256k1_ge_set_xy(&d_ge, &d.x, &d.y);
+ secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z);
+ secp256k1_gej_set_ge(&ai, &pre_a[0]);
+ ai.z = a->z;
+ /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a.
+ * Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
+ */
zr[0] = d.z;
+
for (i = 1; i < n; i++) {
- secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);
+ secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]);
+ secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y);
}
- /*
- * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only
- * the final point's z coordinate is actually used though, so just update that.
+ /* Multiply the last z-coordinate by C to undo the isomorphism.
+ * Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios,
+ * undoing the isomorphism here undoes the isomorphism for all pre_a values.
*/
- secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);
+ secp256k1_fe_mul(z, &ai.z, &d.z);
}
-/** 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 rz.
- * It only operates on tables sized for WINDOW_A wnaf multiples.
- *
- * To compute a*P + b*G, we compute a table for P using this function,
- * and use the precomputed table in <ecmult_static_pre_g.h> for G.
- */
-static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
- secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
- secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
+#define SECP256K1_ECMULT_TABLE_VERIFY(n,w) \
+ VERIFY_CHECK(((n) & 1) == 1); \
+ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
+ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1));
- /* Compute the odd multiples in Jacobian form. */
- secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);
- /* Bring them to the same Z denominator. */
- secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
+SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) {
+ SECP256K1_ECMULT_TABLE_VERIFY(n,w)
+ if (n > 0) {
+ *r = pre[(n-1)/2];
+ } else {
+ *r = pre[(-n-1)/2];
+ secp256k1_fe_negate(&(r->y), &(r->y), 1);
+ }
}
-/** The following two macro retrieves a particular odd multiple from a table
- * of precomputed multiples. */
-#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \
- VERIFY_CHECK(((n) & 1) == 1); \
- VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
- VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
- if ((n) > 0) { \
- *(r) = (pre)[((n)-1)/2]; \
- } else { \
- *(r) = (pre)[(-(n)-1)/2]; \
- secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
- } \
-} while(0)
-
-#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \
- VERIFY_CHECK(((n) & 1) == 1); \
- VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
- VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
- if ((n) > 0) { \
- secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
- } else { \
- secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
- secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
- } \
-} while(0)
+SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) {
+ SECP256K1_ECMULT_TABLE_VERIFY(n,w)
+ if (n > 0) {
+ secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y);
+ } else {
+ secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y);
+ secp256k1_fe_negate(&(r->y), &(r->y), 1);
+ }
+}
+
+SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) {
+ SECP256K1_ECMULT_TABLE_VERIFY(n,w)
+ if (n > 0) {
+ secp256k1_ge_from_storage(r, &pre[(n-1)/2]);
+ } else {
+ secp256k1_ge_from_storage(r, &pre[(-n-1)/2]);
+ secp256k1_fe_negate(&(r->y), &(r->y), 1);
+ }
+}
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
* with the following guarantees:
@@ -201,19 +209,16 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
}
struct secp256k1_strauss_point_state {
- secp256k1_scalar na_1, na_lam;
int wnaf_na_1[129];
int wnaf_na_lam[129];
int bits_na_1;
int bits_na_lam;
- size_t input_pos;
};
struct secp256k1_strauss_state {
- secp256k1_gej* prej;
- secp256k1_fe* zr;
+ /* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */
+ secp256k1_fe* aux;
secp256k1_ge* pre_a;
- secp256k1_ge* pre_a_lam;
struct secp256k1_strauss_point_state* ps;
};
@@ -231,17 +236,19 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
size_t np;
size_t no = 0;
+ secp256k1_fe_set_int(&Z, 1);
for (np = 0; np < num; ++np) {
+ secp256k1_gej tmp;
+ secp256k1_scalar na_1, na_lam;
if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
continue;
}
- state->ps[no].input_pos = np;
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
- secp256k1_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]);
+ secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]);
/* build wnaf representation for na_1 and na_lam. */
- state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &state->ps[no].na_1, WINDOW_A);
- state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &state->ps[no].na_lam, WINDOW_A);
+ state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A);
+ state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A);
VERIFY_CHECK(state->ps[no].bits_na_1 <= 129);
VERIFY_CHECK(state->ps[no].bits_na_lam <= 129);
if (state->ps[no].bits_na_1 > bits) {
@@ -250,40 +257,36 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
if (state->ps[no].bits_na_lam > bits) {
bits = state->ps[no].bits_na_lam;
}
- ++no;
- }
- /* Calculate odd multiples of a.
- * All multiples are brought to the same Z 'denominator', which is stored
- * in Z. Due to secp256k1' isomorphism we can do all operations pretending
- * that the Z coordinate was 1, use affine addition formulae, and correct
- * the Z coordinate of the result once at the end.
- * The exception is the precomputed G table points, which are actually
- * affine. Compared to the base used for other points, they have a Z ratio
- * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
- * isomorphism to efficiently add with a known Z inverse.
- */
- if (no > 0) {
- /* Compute the odd multiples in Jacobian form. */
- secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]);
- for (np = 1; np < no; ++np) {
- secp256k1_gej tmp = a[state->ps[np].input_pos];
+ /* Calculate odd multiples of a.
+ * All multiples are brought to the same Z 'denominator', which is stored
+ * in Z. Due to secp256k1' isomorphism we can do all operations pretending
+ * that the Z coordinate was 1, use affine addition formulae, and correct
+ * the Z coordinate of the result once at the end.
+ * The exception is the precomputed G table points, which are actually
+ * affine. Compared to the base used for other points, they have a Z ratio
+ * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
+ * isomorphism to efficiently add with a known Z inverse.
+ */
+ tmp = a[np];
+ if (no) {
#ifdef VERIFY
- secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
+ secp256k1_fe_normalize_var(&Z);
#endif
- secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
- secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp);
- secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z));
+ secp256k1_gej_rescale(&tmp, &Z);
}
- /* Bring them to the same Z denominator. */
- secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr);
- } else {
- secp256k1_fe_set_int(&Z, 1);
+ secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
+ if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z));
+
+ ++no;
}
+ /* Bring them to the same Z denominator. */
+ secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
+
for (np = 0; np < no; ++np) {
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]);
+ secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta);
}
}
@@ -309,20 +312,20 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
secp256k1_gej_double_var(r, r, NULL);
for (np = 0; np < no; ++np) {
if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
+ secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
+ secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
}
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
- ECMULT_TABLE_GET_GE_STORAGE(&tmpa, secp256k1_pre_g, n, WINDOW_G);
+ secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G);
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
- ECMULT_TABLE_GET_GE_STORAGE(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
+ secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
}
@@ -333,23 +336,19 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
}
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
- secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
- secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
struct secp256k1_strauss_point_state ps[1];
- secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
struct secp256k1_strauss_state state;
- state.prej = prej;
- state.zr = zr;
+ state.aux = aux;
state.pre_a = pre_a;
- state.pre_a_lam = pre_a_lam;
state.ps = ps;
secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng);
}
static size_t secp256k1_strauss_scratch_size(size_t n_points) {
- static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
+ static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
return n_points*point_size;
}
@@ -370,13 +369,11 @@ static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callba
* constant and strauss_scratch_size accordingly. */
points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
- state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
- state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
+ state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
- state.pre_a_lam = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
- if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL || state.pre_a_lam == NULL || state.ps == NULL) {
+ if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 55679a2fc1..2584a494ee 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -32,6 +32,12 @@
#error "Please select wide multiplication implementation"
#endif
+static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
+ 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
+ 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
+);
+
/** Normalize a field element. This brings the field element to a canonical representation, reduces
* its magnitude to 1, and reduces it modulo field size `p`.
*/
@@ -124,4 +130,13 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
+/** Halves the value of a field element modulo the field prime. Constant-time.
+ * For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'.
+ * The output is not guaranteed to be normalized, regardless of the input. */
+static void secp256k1_fe_half(secp256k1_fe *r);
+
+/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its
+ * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
+static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
+
#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 4363e727e7..21742bf6eb 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -11,6 +11,15 @@
#include "field.h"
#include "modinv32_impl.h"
+/** See the comment at the top of field_5x52_impl.h for more details.
+ *
+ * Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first,
+ * where limbs can contain >26 bits.
+ * A magnitude M means:
+ * - 2*M*(2^22-1) is the max (inclusive) of the most significant limb
+ * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs
+ */
+
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) {
const uint32_t *d = a->n;
@@ -40,6 +49,26 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
#endif
+static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
+ VERIFY_CHECK(m >= 0);
+ VERIFY_CHECK(m <= 2048);
+ r->n[0] = 0x3FFFFFFUL * 2 * m;
+ r->n[1] = 0x3FFFFFFUL * 2 * m;
+ r->n[2] = 0x3FFFFFFUL * 2 * m;
+ r->n[3] = 0x3FFFFFFUL * 2 * m;
+ r->n[4] = 0x3FFFFFFUL * 2 * m;
+ r->n[5] = 0x3FFFFFFUL * 2 * m;
+ r->n[6] = 0x3FFFFFFUL * 2 * m;
+ r->n[7] = 0x3FFFFFFUL * 2 * m;
+ r->n[8] = 0x3FFFFFFUL * 2 * m;
+ r->n[9] = 0x03FFFFFUL * 2 * m;
+#ifdef VERIFY
+ r->magnitude = m;
+ r->normalized = (m == 0);
+ secp256k1_fe_verify(r);
+#endif
+}
+
static void secp256k1_fe_normalize(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -391,6 +420,10 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_verify(a);
+ VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
+ VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
+ VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
+ VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m);
#endif
r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0];
r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1];
@@ -1120,6 +1153,82 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
#endif
}
+static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
+ uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
+ t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
+ uint32_t one = (uint32_t)1;
+ uint32_t mask = -(t0 & one) >> 6;
+
+#ifdef VERIFY
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(r->magnitude < 32);
+#endif
+
+ /* Bounds analysis (over the rationals).
+ *
+ * Let m = r->magnitude
+ * C = 0x3FFFFFFUL * 2
+ * D = 0x03FFFFFUL * 2
+ *
+ * Initial bounds: t0..t8 <= C * m
+ * t9 <= D * m
+ */
+
+ t0 += 0x3FFFC2FUL & mask;
+ t1 += 0x3FFFFBFUL & mask;
+ t2 += mask;
+ t3 += mask;
+ t4 += mask;
+ t5 += mask;
+ t6 += mask;
+ t7 += mask;
+ t8 += mask;
+ t9 += mask >> 4;
+
+ VERIFY_CHECK((t0 & one) == 0);
+
+ /* t0..t8: added <= C/2
+ * t9: added <= D/2
+ *
+ * Current bounds: t0..t8 <= C * (m + 1/2)
+ * t9 <= D * (m + 1/2)
+ */
+
+ r->n[0] = (t0 >> 1) + ((t1 & one) << 25);
+ r->n[1] = (t1 >> 1) + ((t2 & one) << 25);
+ r->n[2] = (t2 >> 1) + ((t3 & one) << 25);
+ r->n[3] = (t3 >> 1) + ((t4 & one) << 25);
+ r->n[4] = (t4 >> 1) + ((t5 & one) << 25);
+ r->n[5] = (t5 >> 1) + ((t6 & one) << 25);
+ r->n[6] = (t6 >> 1) + ((t7 & one) << 25);
+ r->n[7] = (t7 >> 1) + ((t8 & one) << 25);
+ r->n[8] = (t8 >> 1) + ((t9 & one) << 25);
+ r->n[9] = (t9 >> 1);
+
+ /* t0..t8: shifted right and added <= C/4 + 1/2
+ * t9: shifted right
+ *
+ * Current bounds: t0..t8 <= C * (m/2 + 1/2)
+ * t9 <= D * (m/2 + 1/4)
+ */
+
+#ifdef VERIFY
+ /* Therefore the output magnitude (M) has to be set such that:
+ * t0..t8: C * M >= C * (m/2 + 1/2)
+ * t9: D * M >= D * (m/2 + 1/4)
+ *
+ * It suffices for all limbs that, for any input magnitude m:
+ * M >= m/2 + 1/2
+ *
+ * and since we want the smallest such integer value for M:
+ * M == floor(m/2) + 1
+ */
+ r->magnitude = (r->magnitude >> 1) + 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+#endif
+}
+
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index b56bdd1353..6bd202f587 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -22,11 +22,18 @@
#endif
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
- * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular,
- * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element
- * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
- * accept any input with magnitude at most M, and have different rules for propagating magnitude to their
- * output.
+ * represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to
+ * contain >52 bits each.
+ *
+ * Each field element has a 'magnitude' associated with it. Internally, a magnitude M means:
+ * - 2*M*(2^48-1) is the max (inclusive) of the most significant limb
+ * - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs
+ *
+ * Operations have different rules for propagating magnitude to their outputs. If an operation takes a
+ * magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive).
+ *
+ * Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either
+ * 0 or 1, and its value is already reduced modulo the order of the field.
*/
#ifdef VERIFY
@@ -51,6 +58,21 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
#endif
+static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
+ VERIFY_CHECK(m >= 0);
+ VERIFY_CHECK(m <= 2048);
+ r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
+ r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
+ r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
+ r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
+ r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
+#ifdef VERIFY
+ r->magnitude = m;
+ r->normalized = (m == 0);
+ secp256k1_fe_verify(r);
+#endif
+}
+
static void secp256k1_fe_normalize(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
@@ -377,6 +399,9 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_verify(a);
+ VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
+ VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
+ VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m);
#endif
r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];
@@ -467,6 +492,71 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
#endif
}
+static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
+ uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
+ uint64_t one = (uint64_t)1;
+ uint64_t mask = -(t0 & one) >> 12;
+
+#ifdef VERIFY
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(r->magnitude < 32);
+#endif
+
+ /* Bounds analysis (over the rationals).
+ *
+ * Let m = r->magnitude
+ * C = 0xFFFFFFFFFFFFFULL * 2
+ * D = 0x0FFFFFFFFFFFFULL * 2
+ *
+ * Initial bounds: t0..t3 <= C * m
+ * t4 <= D * m
+ */
+
+ t0 += 0xFFFFEFFFFFC2FULL & mask;
+ t1 += mask;
+ t2 += mask;
+ t3 += mask;
+ t4 += mask >> 4;
+
+ VERIFY_CHECK((t0 & one) == 0);
+
+ /* t0..t3: added <= C/2
+ * t4: added <= D/2
+ *
+ * Current bounds: t0..t3 <= C * (m + 1/2)
+ * t4 <= D * (m + 1/2)
+ */
+
+ r->n[0] = (t0 >> 1) + ((t1 & one) << 51);
+ r->n[1] = (t1 >> 1) + ((t2 & one) << 51);
+ r->n[2] = (t2 >> 1) + ((t3 & one) << 51);
+ r->n[3] = (t3 >> 1) + ((t4 & one) << 51);
+ r->n[4] = (t4 >> 1);
+
+ /* t0..t3: shifted right and added <= C/4 + 1/2
+ * t4: shifted right
+ *
+ * Current bounds: t0..t3 <= C * (m/2 + 1/2)
+ * t4 <= D * (m/2 + 1/4)
+ */
+
+#ifdef VERIFY
+ /* Therefore the output magnitude (M) has to be set such that:
+ * t0..t3: C * M >= C * (m/2 + 1/2)
+ * t4: D * M >= D * (m/2 + 1/4)
+ *
+ * It suffices for all limbs that, for any input magnitude m:
+ * M >= m/2 + 1/2
+ *
+ * and since we want the smallest such integer value for M:
+ * M == floor(m/2) + 1
+ */
+ r->magnitude = (r->magnitude >> 1) + 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+#endif
+}
+
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 374284a1f4..0a4a04d9ac 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -135,6 +135,4 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
return secp256k1_fe_equal(&t1, a);
}
-static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
-
#endif /* SECP256K1_FIELD_IMPL_H */
diff --git a/src/secp256k1/src/gen_ecmult_static_pre_g.c b/src/secp256k1/src/gen_ecmult_static_pre_g.c
deleted file mode 100644
index ba1d1f17d7..0000000000
--- a/src/secp256k1/src/gen_ecmult_static_pre_g.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*****************************************************************************************************
- * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
- *****************************************************************************************************/
-
-#include <inttypes.h>
-#include <stdio.h>
-
-/* Autotools creates libsecp256k1-config.h, of which ECMULT_WINDOW_SIZE is needed.
- ifndef guard so downstream users can define their own if they do not use autotools. */
-#if !defined(ECMULT_WINDOW_SIZE)
-#include "libsecp256k1-config.h"
-#endif
-
-#include "../include/secp256k1.h"
-#include "assumptions.h"
-#include "util.h"
-#include "field_impl.h"
-#include "group_impl.h"
-#include "ecmult.h"
-
-void print_table(FILE *fp, const char *name, int window_g, const secp256k1_gej *gen, int with_conditionals) {
- static secp256k1_gej gj;
- static secp256k1_ge ge, dgen;
- static secp256k1_ge_storage ges;
- int j;
- int i;
-
- gj = *gen;
- secp256k1_ge_set_gej_var(&ge, &gj);
- secp256k1_ge_to_storage(&ges, &ge);
-
- fprintf(fp, "static const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name);
- fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
- ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n",
- SECP256K1_GE_STORAGE_CONST_GET(ges));
-
- secp256k1_gej_double_var(&gj, gen, NULL);
- secp256k1_ge_set_gej_var(&dgen, &gj);
-
- j = 1;
- for(i = 3; i <= window_g; ++i) {
- if (with_conditionals) {
- fprintf(fp, "#if ECMULT_TABLE_SIZE(WINDOW_G) > %ld\n", ECMULT_TABLE_SIZE(i-1));
- }
- for(;j < ECMULT_TABLE_SIZE(i); ++j) {
- secp256k1_gej_set_ge(&gj, &ge);
- secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL);
- secp256k1_ge_set_gej_var(&ge, &gj);
- secp256k1_ge_to_storage(&ges, &ge);
-
- fprintf(fp, ",S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
- ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n",
- SECP256K1_GE_STORAGE_CONST_GET(ges));
- }
- if (with_conditionals) {
- fprintf(fp, "#endif\n");
- }
- }
- fprintf(fp, "};\n");
-}
-
-void print_two_tables(FILE *fp, int window_g, const secp256k1_ge *g, int with_conditionals) {
- secp256k1_gej gj;
- int i;
-
- secp256k1_gej_set_ge(&gj, g);
- print_table(fp, "secp256k1_pre_g", window_g, &gj, with_conditionals);
- for (i = 0; i < 128; ++i) {
- secp256k1_gej_double_var(&gj, &gj, NULL);
- }
- print_table(fp, "secp256k1_pre_g_128", window_g, &gj, with_conditionals);
-}
-
-int main(void) {
- const secp256k1_ge g = SECP256K1_G;
- const secp256k1_ge g_13 = SECP256K1_G_ORDER_13;
- const secp256k1_ge g_199 = SECP256K1_G_ORDER_199;
- const int window_g_13 = 4;
- const int window_g_199 = 8;
- FILE* fp;
-
- fp = fopen("src/ecmult_static_pre_g.h","w");
- if (fp == NULL) {
- fprintf(stderr, "Could not open src/ecmult_static_pre_g.h for writing!\n");
- return -1;
- }
-
- fprintf(fp, "/* This file was automatically generated by gen_ecmult_static_pre_g. */\n");
- fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
- fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
- fprintf(fp, " */\n");
- fprintf(fp, "#ifndef SECP256K1_ECMULT_STATIC_PRE_G_H\n");
- fprintf(fp, "#define SECP256K1_ECMULT_STATIC_PRE_G_H\n");
- fprintf(fp, "#include \"group.h\"\n");
- fprintf(fp, "#ifdef S\n");
- fprintf(fp, " #error macro identifier S already in use.\n");
- fprintf(fp, "#endif\n");
- fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) "
- "SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,"
- "0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n");
- fprintf(fp, "#if ECMULT_TABLE_SIZE(ECMULT_WINDOW_SIZE) > %ld\n", ECMULT_TABLE_SIZE(ECMULT_WINDOW_SIZE));
- fprintf(fp, " #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting ecmult_static_pre_g.h before the build.\n");
- fprintf(fp, "#endif\n");
- fprintf(fp, "#if defined(EXHAUSTIVE_TEST_ORDER)\n");
- fprintf(fp, "#if EXHAUSTIVE_TEST_ORDER == 13\n");
- fprintf(fp, "#define WINDOW_G %d\n", window_g_13);
-
- print_two_tables(fp, window_g_13, &g_13, 0);
-
- fprintf(fp, "#elif EXHAUSTIVE_TEST_ORDER == 199\n");
- fprintf(fp, "#define WINDOW_G %d\n", window_g_199);
-
- print_two_tables(fp, window_g_199, &g_199, 0);
-
- fprintf(fp, "#else\n");
- fprintf(fp, " #error No known generator for the specified exhaustive test group order.\n");
- fprintf(fp, "#endif\n");
- fprintf(fp, "#else /* !defined(EXHAUSTIVE_TEST_ORDER) */\n");
- fprintf(fp, "#define WINDOW_G ECMULT_WINDOW_SIZE\n");
-
- print_two_tables(fp, ECMULT_WINDOW_SIZE, &g, 1);
-
- fprintf(fp, "#endif\n");
- fprintf(fp, "#undef S\n");
- fprintf(fp, "#endif\n");
- fclose(fp);
-
- return 0;
-}
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index b9cd334dae..bb7dae1cf7 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -9,7 +9,10 @@
#include "field.h"
-/** A group element of the secp256k1 curve, in affine coordinates. */
+/** A group element in affine coordinates on the secp256k1 curve,
+ * or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6.
+ * Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve.
+ */
typedef struct {
secp256k1_fe x;
secp256k1_fe y;
@@ -19,7 +22,9 @@ typedef struct {
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
-/** A group element of the secp256k1 curve, in jacobian coordinates. */
+/** A group element of the secp256k1 curve, in jacobian coordinates.
+ * Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
+ */
typedef struct {
secp256k1_fe x; /* actual X: x/z^2 */
secp256k1_fe y; /* actual Y: y/z^3 */
@@ -64,12 +69,24 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
-/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
- * the same global z "denominator". zr must contain the known z-ratios such
- * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y
- * coordinates of the result are stored in r, the common z coordinate is
- * stored in globalz. */
-static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
+/** Bring a batch of inputs to the same global z "denominator", based on ratios between
+ * (omitted) z coordinates of adjacent elements.
+ *
+ * Although the elements a[i] are _ge rather than _gej, they actually represent elements
+ * in Jacobian coordinates with their z coordinates omitted.
+ *
+ * Using the notation z(b) to represent the omitted z coordinate of b, the array zr of
+ * z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len.
+ * The zr[0] value is unused.
+ *
+ * This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]).
+ * In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the
+ * a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is
+ * implicit.
+ *
+ * The coordinates of the final element a[len-1] are not changed.
+ */
+static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
/** Set a group element (affine) equal to the point at infinity. */
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
@@ -125,6 +142,9 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
+static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag);
+
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index bce9fbdad5..b19b02a01f 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -161,27 +161,26 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
}
}
-static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {
+static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) {
size_t i = len - 1;
secp256k1_fe zs;
if (len > 0) {
- /* The z of the final point gives us the "global Z" for the table. */
- r[i].x = a[i].x;
- r[i].y = a[i].y;
/* Ensure all y values are in weak normal form for fast negation of points */
- secp256k1_fe_normalize_weak(&r[i].y);
- *globalz = a[i].z;
- r[i].infinity = 0;
+ secp256k1_fe_normalize_weak(&a[i].y);
zs = zr[i];
/* Work our way backwards, using the z-ratios to scale the x/y values. */
while (i > 0) {
+ secp256k1_gej tmpa;
if (i != len - 1) {
secp256k1_fe_mul(&zs, &zs, &zr[i]);
}
i--;
- secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);
+ tmpa.x = a[i].x;
+ tmpa.y = a[i].y;
+ tmpa.infinity = 0;
+ secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
}
}
}
@@ -272,37 +271,35 @@ 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, 0 normalize, 12 mul_int/add/negate.
- *
- * Note that there is an implementation described at
- * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
- * which trades a multiply for a square, but in practice this is actually slower,
- * mainly because it requires more normalizations.
- */
- secp256k1_fe t1,t2,t3,t4;
+ /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
+ secp256k1_fe l, s, t;
r->infinity = a->infinity;
- secp256k1_fe_mul(&r->z, &a->z, &a->y);
- secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
- secp256k1_fe_sqr(&t1, &a->x);
- secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */
- secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */
- secp256k1_fe_sqr(&t3, &a->y);
- secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */
- secp256k1_fe_sqr(&t4, &t3);
- secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */
- secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */
- r->x = t3;
- secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */
- secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
- secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */
- secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */
- secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */
- secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */
- secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */
- secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */
- secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
+ /* Formula used:
+ * L = (3/2) * X1^2
+ * S = Y1^2
+ * T = -X1*S
+ * X3 = L^2 + 2*T
+ * Y3 = -(L*(X3 + T) + S^2)
+ * Z3 = Y1*Z1
+ */
+
+ secp256k1_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */
+ secp256k1_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */
+ secp256k1_fe_sqr(&l, &a->x); /* L = X1^2 (1) */
+ secp256k1_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */
+ secp256k1_fe_half(&l); /* L = 3/2*X1^2 (2) */
+ secp256k1_fe_negate(&t, &s, 1); /* T = -S (2) */
+ secp256k1_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */
+ secp256k1_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */
+ secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */
+ secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */
+ secp256k1_fe_sqr(&s, &s); /* S' = S^2 (1) */
+ secp256k1_fe_add(&t, &r->x); /* T' = X3 + T (4) */
+ secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
+ 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) */
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
@@ -327,7 +324,6 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
if (rzr != NULL) {
*rzr = a->y;
secp256k1_fe_normalize_weak(rzr);
- secp256k1_fe_mul_int(rzr, 2);
}
secp256k1_gej_double(r, a);
@@ -493,8 +489,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
- /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */
- static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+ /* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
int infinity, degenerate;
@@ -515,11 +510,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* Z = Z1*Z2
* T = U1+U2
* M = S1+S2
- * Q = T*M^2
+ * Q = -T*M^2
* R = T^2-U1*U2
- * X3 = 4*(R^2-Q)
- * Y3 = 4*(R*(3*Q-2*R^2)-M^4)
- * Z3 = 2*M*Z
+ * X3 = R^2+Q
+ * Y3 = -(R*(2*X3+Q)+M^4)/2
+ * Z3 = M*Z
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
*
* This formula has the benefit of being the same for both addition
@@ -583,7 +578,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* and denominator of lambda; R and M represent the explicit
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
- secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */
+ secp256k1_fe_negate(&q, &t, 2); /* q = -T (3) */
+ secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */
/* These two lines use the observation that either M == Malt or M == 0,
* so M^3 * Malt is either Malt^4 (which is computed by squaring), or
* zero (which is "computed" by cmov). So the cost is one squaring
@@ -591,26 +587,21 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_sqr(&n, &n);
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
- secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */
+ secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
- secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */
- secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
- secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */
- secp256k1_fe_normalize_weak(&t);
- r->x = t; /* r->x = Ralt^2-Q (1) */
- secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */
- secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */
- secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */
- secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */
- secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */
- secp256k1_fe_normalize_weak(&r->y);
- secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */
- secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
+ secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
+ r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */
+ secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
+ secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */
+ secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */
+ secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */
+ secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
+ secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
- secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);
+ secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity);
r->infinity = infinity;
}
@@ -642,18 +633,22 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
r->infinity = 0;
}
+static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
+ 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;
+}
+
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
secp256k1_fe_storage_cmov(&r->x, &a->x, flag);
secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
}
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
- static const secp256k1_fe beta = SECP256K1_FE_CONST(
- 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
- 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
- );
*r = *a;
- secp256k1_fe_mul(&r->x, &r->x, &beta);
+ secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
}
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index 0947a09694..4e0384cfbf 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -12,8 +12,8 @@
typedef struct {
uint32_t s[8];
- uint32_t buf[16]; /* In big endian */
- size_t bytes;
+ unsigned char buf[64];
+ uint64_t bytes;
} secp256k1_sha256;
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index f8cd3a1634..0991fe7838 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -28,12 +28,6 @@
(h) = t1 + t2; \
} while(0)
-#if defined(SECP256K1_BIG_ENDIAN)
-#define BE32(x) (x)
-#elif defined(SECP256K1_LITTLE_ENDIAN)
-#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
-#endif
-
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
hash->s[0] = 0x6a09e667ul;
hash->s[1] = 0xbb67ae85ul;
@@ -47,26 +41,26 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
}
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
-static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
+static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
- Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));
- Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
- Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
- Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
- Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
- Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
- Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
- Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
- Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
- Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
- Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
- Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
- Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
- Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
- Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
- Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
+ Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0]));
+ Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4]));
+ Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8]));
+ Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12]));
+ Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16]));
+ Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20]));
+ Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24]));
+ Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28]));
+ Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32]));
+ Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36]));
+ Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40]));
+ Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44]));
+ Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48]));
+ Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52]));
+ Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56]));
+ Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60]));
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
@@ -136,7 +130,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
while (len >= 64 - bufsize) {
/* Fill the buffer, and process it. */
size_t chunk_len = 64 - bufsize;
- memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
+ memcpy(hash->buf + bufsize, data, chunk_len);
data += chunk_len;
len -= chunk_len;
secp256k1_sha256_transform(hash->s, hash->buf);
@@ -149,19 +143,19 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
}
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
- static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- uint32_t sizedesc[2];
- uint32_t out[8];
- int i = 0;
- sizedesc[0] = BE32(hash->bytes >> 29);
- sizedesc[1] = BE32(hash->bytes << 3);
+ static const unsigned char pad[64] = {0x80};
+ unsigned char sizedesc[8];
+ int i;
+ /* The maximum message size of SHA256 is 2^64-1 bits. */
+ VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
+ secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
+ secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
- secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);
+ secp256k1_sha256_write(hash, sizedesc, 8);
for (i = 0; i < 8; i++) {
- out[i] = BE32(hash->s[i]);
+ secp256k1_write_be32(&out32[4*i], hash->s[i]);
hash->s[i] = 0;
}
- memcpy(out32, (const unsigned char*)out, 32);
}
/* Initializes a sha256 struct and writes the 64 byte string
@@ -285,7 +279,6 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
rng->retry = 0;
}
-#undef BE32
#undef Round
#undef sigma1
#undef sigma0
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index be07447a4b..10b7075c38 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -60,7 +60,7 @@ void test_ecdh_generator_basepoint(void) {
s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */
- for (i = 0; i < 100; ++i) {
+ for (i = 0; i < 2 * count; ++i) {
secp256k1_sha256 sha;
unsigned char s_b32[32];
unsigned char output_ecdh[65];
@@ -123,10 +123,43 @@ void test_bad_scalar(void) {
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
}
+/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
+void test_result_basepoint(void) {
+ secp256k1_pubkey point;
+ secp256k1_scalar rand;
+ unsigned char s[32];
+ unsigned char s_inv[32];
+ unsigned char out[32];
+ unsigned char out_inv[32];
+ unsigned char out_base[32];
+ int i;
+
+ unsigned char s_one[32] = { 0 };
+ s_one[31] = 1;
+ CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_one) == 1);
+ CHECK(secp256k1_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1);
+
+ for (i = 0; i < 2 * count; i++) {
+ random_scalar_order(&rand);
+ secp256k1_scalar_get_b32(s, &rand);
+ secp256k1_scalar_inverse(&rand, &rand);
+ secp256k1_scalar_get_b32(s_inv, &rand);
+
+ CHECK(secp256k1_ec_pubkey_create(ctx, &point, s) == 1);
+ CHECK(secp256k1_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1);
+ CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
+
+ CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_inv) == 1);
+ CHECK(secp256k1_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1);
+ CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
+ }
+}
+
void run_ecdh_tests(void) {
test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();
+ test_result_basepoint();
}
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h
index 94e3ee414d..cd651591c4 100644
--- a/src/secp256k1/src/modules/schnorrsig/main_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h
@@ -192,11 +192,15 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
return ret;
}
-int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
+int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
/* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32);
}
+int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
+ return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32);
+}
+
int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) {
secp256k1_nonce_function_hardened noncefp = NULL;
void *ndata = NULL;
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
index 2efec8a2b9..25840b8fa7 100644
--- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
@@ -87,7 +87,7 @@ void run_nonce_function_bip340_tests(void) {
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
/* Other algo is fine */
- secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, algo, algolen);
+ secp256k1_testrand_bytes_test(algo, algolen);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
for (i = 0; i < count; i++) {
@@ -160,21 +160,21 @@ void test_schnorrsig_api(void) {
/** main test body **/
ecount = 0;
- CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_schnorrsig_sign(sttc, sig, msg, &keypairs[0], NULL) == 0);
+ CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 5);
ecount = 0;
@@ -202,7 +202,7 @@ void test_schnorrsig_api(void) {
CHECK(ecount == 6);
ecount = 0;
- CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1);
@@ -247,7 +247,7 @@ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const un
secp256k1_xonly_pubkey pk, pk_expected;
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
- CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg32, &keypair, aux_rand));
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg32, &keypair, aux_rand));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
@@ -740,8 +740,11 @@ void test_schnorrsig_sign(void) {
secp256k1_testrand256(aux_rand);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
- CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
+ /* Check that deprecated alias gives the same result */
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1);
+ CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
/* Test different nonce functions */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
@@ -764,7 +767,7 @@ void test_schnorrsig_sign(void) {
extraparams.noncefp = NULL;
extraparams.ndata = aux_rand;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
- CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
}
@@ -787,7 +790,7 @@ void test_schnorrsig_sign_verify(void) {
for (i = 0; i < N_SIGS; i++) {
secp256k1_testrand256(msg[i]);
- CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL));
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
}
@@ -795,18 +798,18 @@ void test_schnorrsig_sign_verify(void) {
/* Flip a few bits in the signature and in the message and check that
* verify and verify_batch (TODO) fail */
size_t sig_idx = secp256k1_testrand_int(N_SIGS);
- size_t byte_idx = secp256k1_testrand_int(32);
+ size_t byte_idx = secp256k1_testrand_bits(5);
unsigned char xorbyte = secp256k1_testrand_int(254)+1;
sig[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
sig[sig_idx][byte_idx] ^= xorbyte;
- byte_idx = secp256k1_testrand_int(32);
+ byte_idx = secp256k1_testrand_bits(5);
sig[sig_idx][32+byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
sig[sig_idx][32+byte_idx] ^= xorbyte;
- byte_idx = secp256k1_testrand_int(32);
+ byte_idx = secp256k1_testrand_bits(5);
msg[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
msg[sig_idx][byte_idx] ^= xorbyte;
@@ -816,13 +819,13 @@ void test_schnorrsig_sign_verify(void) {
}
/* Test overflowing s */
- CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
memset(&sig[0][32], 0xFF, 32);
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
/* Test negative s */
- CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
secp256k1_scalar_negate(&s, &s);
@@ -873,7 +876,7 @@ void test_schnorrsig_taproot(void) {
/* Key spend */
secp256k1_testrand256(msg);
- CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
/* Verify key spend */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1);
diff --git a/src/secp256k1/src/precompute_ecmult.c b/src/secp256k1/src/precompute_ecmult.c
new file mode 100644
index 0000000000..5ccbcb3c57
--- /dev/null
+++ b/src/secp256k1/src/precompute_ecmult.c
@@ -0,0 +1,96 @@
+/*****************************************************************************************************
+ * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
+ *****************************************************************************************************/
+
+#include <inttypes.h>
+#include <stdio.h>
+
+/* Autotools creates libsecp256k1-config.h, of which ECMULT_WINDOW_SIZE is needed.
+ ifndef guard so downstream users can define their own if they do not use autotools. */
+#if !defined(ECMULT_WINDOW_SIZE)
+#include "libsecp256k1-config.h"
+#endif
+
+#include "../include/secp256k1.h"
+#include "assumptions.h"
+#include "util.h"
+#include "field_impl.h"
+#include "group_impl.h"
+#include "ecmult.h"
+#include "ecmult_compute_table_impl.h"
+
+static void print_table(FILE *fp, const char *name, int window_g, const secp256k1_ge_storage* table) {
+ int j;
+ int i;
+
+ fprintf(fp, "const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name);
+ fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
+ ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n",
+ SECP256K1_GE_STORAGE_CONST_GET(table[0]));
+
+ j = 1;
+ for(i = 3; i <= window_g; ++i) {
+ fprintf(fp, "#if WINDOW_G > %d\n", i-1);
+ for(;j < ECMULT_TABLE_SIZE(i); ++j) {
+ fprintf(fp, ",S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
+ ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n",
+ SECP256K1_GE_STORAGE_CONST_GET(table[j]));
+ }
+ fprintf(fp, "#endif\n");
+ }
+ fprintf(fp, "};\n");
+}
+
+static void print_two_tables(FILE *fp, int window_g) {
+ secp256k1_ge_storage* table = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage));
+ secp256k1_ge_storage* table_128 = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage));
+
+ secp256k1_ecmult_compute_two_tables(table, table_128, window_g, &secp256k1_ge_const_g);
+
+ print_table(fp, "secp256k1_pre_g", window_g, table);
+ print_table(fp, "secp256k1_pre_g_128", window_g, table_128);
+
+ free(table);
+ free(table_128);
+}
+
+int main(void) {
+ /* Always compute all tables for window sizes up to 15. */
+ int window_g = (ECMULT_WINDOW_SIZE < 15) ? 15 : ECMULT_WINDOW_SIZE;
+ FILE* fp;
+
+ fp = fopen("src/precomputed_ecmult.c","w");
+ if (fp == NULL) {
+ fprintf(stderr, "Could not open src/precomputed_ecmult.h for writing!\n");
+ return -1;
+ }
+
+ fprintf(fp, "/* This file was automatically generated by precompute_ecmult. */\n");
+ fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
+ fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
+ fprintf(fp, " */\n");
+ fprintf(fp, "#if defined HAVE_CONFIG_H\n");
+ fprintf(fp, "# include \"libsecp256k1-config.h\"\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "#include \"../include/secp256k1.h\"\n");
+ fprintf(fp, "#include \"group.h\"\n");
+ fprintf(fp, "#include \"ecmult.h\"\n");
+ fprintf(fp, "#include \"precomputed_ecmult.h\"\n");
+ fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n");
+ fprintf(fp, "#if ECMULT_WINDOW_SIZE > %d\n", window_g);
+ fprintf(fp, " #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build.\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n");
+ fprintf(fp, "# error Cannot compile precomputed_ecmult.c in exhaustive test mode\n");
+ fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n");
+ fprintf(fp, "#define WINDOW_G ECMULT_WINDOW_SIZE\n");
+
+ print_two_tables(fp, window_g);
+
+ fprintf(fp, "#undef S\n");
+ fclose(fp);
+
+ return 0;
+}
diff --git a/src/secp256k1/src/gen_ecmult_gen_static_prec_table.c b/src/secp256k1/src/precompute_ecmult_gen.c
index 22923df313..7c6359c402 100644
--- a/src/secp256k1/src/gen_ecmult_gen_static_prec_table.c
+++ b/src/secp256k1/src/precompute_ecmult_gen.c
@@ -1,8 +1,8 @@
-/***********************************************************************
- * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
- ***********************************************************************/
+/*********************************************************************************
+ * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
+ *********************************************************************************/
#include <inttypes.h>
#include <stdio.h>
@@ -12,10 +12,10 @@
#include "util.h"
#include "group.h"
#include "ecmult_gen.h"
-#include "ecmult_gen_prec_impl.h"
+#include "ecmult_gen_compute_table_impl.h"
int main(int argc, char **argv) {
- const char outfile[] = "src/ecmult_gen_static_prec_table.h";
+ const char outfile[] = "src/precomputed_ecmult_gen.c";
FILE* fp;
int bits;
@@ -28,21 +28,20 @@ int main(int argc, char **argv) {
return -1;
}
- fprintf(fp, "/* This file was automatically generated by gen_ecmult_gen_static_prec_table. */\n");
+ fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n");
fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n");
- fprintf(fp, "#ifndef SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H\n");
- fprintf(fp, "#define SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H\n");
-
+ fprintf(fp, "#if defined HAVE_CONFIG_H\n");
+ fprintf(fp, "# include \"libsecp256k1-config.h\"\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
-
- fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) "
- "SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,"
- "0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n");
-
+ fprintf(fp, "#include \"ecmult_gen.h\"\n");
+ fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n");
fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n");
- fprintf(fp, "static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)];\n");
- fprintf(fp, "#else\n");
- fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = {\n");
+ fprintf(fp, "# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode\n");
+ fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n");
+ fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n");
+ fprintf(fp, "const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = {\n");
for (bits = 2; bits <= 8; bits *= 2) {
int g = ECMULT_GEN_PREC_G(bits);
@@ -50,7 +49,7 @@ int main(int argc, char **argv) {
int inner, outer;
secp256k1_ge_storage* table = checked_malloc(&default_error_callback, n * g * sizeof(secp256k1_ge_storage));
- secp256k1_ecmult_gen_create_prec_table(table, &secp256k1_ge_const_g, bits);
+ secp256k1_ecmult_gen_compute_table(table, &secp256k1_ge_const_g, bits);
fprintf(fp, "#if ECMULT_GEN_PREC_BITS == %d\n", bits);
for(outer = 0; outer != n; outer++) {
@@ -74,9 +73,7 @@ int main(int argc, char **argv) {
}
fprintf(fp, "};\n");
- fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n");
- fprintf(fp, "#undef SC\n");
- fprintf(fp, "#endif /* SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H */\n");
+ fprintf(fp, "#undef S\n");
fclose(fp);
return 0;
diff --git a/src/secp256k1/src/ecmult_static_pre_g.h b/src/secp256k1/src/precomputed_ecmult.c
index 9072fb2688..3e67f37b74 100644
--- a/src/secp256k1/src/ecmult_static_pre_g.h
+++ b/src/secp256k1/src/precomputed_ecmult.c
@@ -1,187 +1,38 @@
-/* This file was automatically generated by gen_ecmult_static_pre_g. */
+/* This file was automatically generated by precompute_ecmult. */
/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and
* an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.
*/
-#ifndef SECP256K1_ECMULT_STATIC_PRE_G_H
-#define SECP256K1_ECMULT_STATIC_PRE_G_H
-#include "group.h"
-#ifdef S
- #error macro identifier S already in use.
+#if defined HAVE_CONFIG_H
+# include "libsecp256k1-config.h"
#endif
+#include "../include/secp256k1.h"
+#include "group.h"
+#include "ecmult.h"
+#include "precomputed_ecmult.h"
#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)
-#if ECMULT_TABLE_SIZE(ECMULT_WINDOW_SIZE) > 8192
- #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting ecmult_static_pre_g.h before the build.
+#if ECMULT_WINDOW_SIZE > 15
+ #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build.
#endif
-#if defined(EXHAUSTIVE_TEST_ORDER)
-#if EXHAUSTIVE_TEST_ORDER == 13
-#define WINDOW_G 4
-static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = {
- S(c3459c3d,35326167,cd86cce8,7a2417f,5b8bd567,de8538ee,d507b0c,d128f5bb,8e467fec,cd30000a,6cc1184e,25d382c2,a2f4494e,2fbe9abc,8b64abac,d005fb24)
-,S(ae64a1bd,38872f22,f637b457,125cc859,e4c7a31b,cf553cf5,b96e7096,cc61cc10,8e467fec,cd30000a,6cc1184e,25d382c2,a2f4494e,2fbe9abc,8b64abac,d005fb24)
-,S(851695d4,9a83f8ef,919bb861,53cbcb16,630fb68a,ed0a766a,3ec693d6,8e6afa40,3c915051,a5fb60b4,fec49de6,e4385101,59f30035,b6502bc0,f5edba86,9753a96c)
-,S(0,0,0,0,0,0,0,1,c36eafae,5a049f4b,13b6219,1bc7aefe,a60cffca,49afd43f,a124578,68ac52c3)
-};
-static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = {
- S(8e55c205,92466f75,3c417ec0,e600f626,bfac877c,52258a1c,3941145a,62753693,8e467fec,cd30000a,6cc1184e,25d382c2,a2f4494e,2fbe9abc,8b64abac,d005fb24)
-,S(c3459c3d,35326167,cd86cce8,7a2417f,5b8bd567,de8538ee,d507b0c,d128f5bb,8e467fec,cd30000a,6cc1184e,25d382c2,a2f4494e,2fbe9abc,8b64abac,d005fb24)
-,S(0,0,0,0,0,0,0,1,3c915051,a5fb60b4,fec49de6,e4385101,59f30035,b6502bc0,f5edba86,9753a96c)
-,S(7ae96a2b,657c0710,6e64479e,ac3434e9,9cf04975,12f58995,c1396c28,719501ee,c36eafae,5a049f4b,13b6219,1bc7aefe,a60cffca,49afd43f,a124578,68ac52c3)
-};
-#elif EXHAUSTIVE_TEST_ORDER == 199
-#define WINDOW_G 8
-static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = {
- S(226e653f,c8df7744,9bacbf12,7d1dcbf9,87f05b2a,e7edbd28,1f564575,c48dcf18,a13872c2,e933bb17,5d9ffd5b,b5b6e10c,57fe3c00,baaaa15a,e003ec3e,9c269bae)
-,S(ff1755e,623c8369,f55edda4,2a5deef0,b32c57f4,80c5884f,d2a2dde1,b1c078c4,640db9f3,9dda2f51,ee3ef3db,775315aa,c06346f1,e31ff76f,83a24bb0,8fc93242)
-,S(64dd1439,5d19a544,a7a1e81b,b9d079b3,593e7022,6bcd444e,6dc8197a,1a6dc3e6,2c7f2dce,e421d852,d3bff68e,993c8bb4,c189d3be,bd4fa667,6a599f9f,8c639c50)
-,S(199d1eb1,5a28f0aa,7258651b,ff07ff13,1c988fa,dc41dc67,390c3172,54b98016,d670e3f1,6fc2382,46bf323f,127e7c14,576e3a64,5d5c41da,40f22b29,4fca876c)
-,S(3d303d12,f8eb67d0,ecaee514,bdd90e57,b58b6d6a,c896a26f,78c06103,52225b04,d282f481,b04bece2,60de6995,b58c4f0d,9c6121e0,d94f45da,f5da7f13,cfefef99)
-,S(76bb4d25,c7a005dc,49a5295f,bb92bf1e,5d0dd5f6,609c2008,54f37361,23a6f9f3,e2295c71,21478f52,d4d18aa,72cd82ae,1995d37e,6ef2e05a,4dea6ee2,6371fbe3)
-,S(8735fb32,6950ae71,31cd03f7,cc1511d8,65c87e84,748c9824,8ccc576e,5480ed8,39cfeb15,665f371f,535d56c1,317a8d62,29ea2827,943a98f1,cee7f685,86e47eec)
-,S(8521a020,a8e7cc5e,d9534d74,d4656581,33869bc,1940548d,6cc35ba4,e3c4323a,c63014ea,99a0c8e0,aca2a93e,ce85729d,d615d7d8,6bc5670e,31180979,791b7d43)
-,S(2f63a396,4d14ca73,2167e033,306863d8,f75605c7,4ea6c917,890dd50d,fc20f53b,e2295c71,21478f52,d4d18aa,72cd82ae,1995d37e,6ef2e05a,4dea6ee2,6371fbe3)
-,S(c479fee8,e2202b42,1c9346fb,4e59f720,95a70dea,2ade9641,58bad01c,2c37f,6897db9d,5a3d8948,ea97069e,de75661,b1ad74e4,2b1daa4f,533d88ba,67137731)
-,S(4d756b2,e61d9806,e02ec830,f1fd44f8,46438689,c528346,15a1addf,ac864bcd,c90704c9,8f72d8be,638a36dc,e8768909,fac7921c,dc54d314,89fbb3e,6da9018a)
-,S(baeab1a8,bca6e88,740deeb5,93887afe,295155ba,fa50f307,baf2de95,2841dca6,a88e0162,de086e20,587faa5c,bca8f572,318c17e9,5668819c,13c4d5d9,2d1c75dc)
-,S(47bbafcd,f612ca3e,703f7721,623bde14,926fc00d,a6bf9e9,41ddb2d5,587626e3,d160b834,5807531a,327a7269,3627dab6,f9770a12,14eb182d,fa73ad15,41b57ff0)
-,S(f9d5cda0,a41aea0e,f0afc533,e1b50808,3acc6043,e04e55bb,77421ab,1cebb8ec,f8a4cc8e,538e1b7f,627c6713,7c896eb1,c5548159,f434695a,ea394c63,592d41cf)
-,S(26e2e75b,aeb04a72,8b893f67,d27ebfc6,b8984a88,6fbd8eee,5719107d,5a413f0f,61b51308,ac8643f0,7c18eda7,ef9a4196,aa66221,1b809acc,2b2cb538,23010ef8)
-,S(318ef624,4d411c97,913a7bb3,8f07b960,e6c57afa,f1edc5bf,e708da8a,954f68ac,37d97203,d25d9c14,53827e27,9474afb2,92943df0,8ba1108a,43644c86,ee6c87e4)
-,S(eac612b0,84cb452a,35d49c60,c0d0c0bd,359eb909,68a80186,92a028f,ece4c331,23575727,9da3d12b,c0004d12,e06a9cda,8405c91e,b8118260,2793e62f,16c2a29e)
-,S(9f5ed380,fa5188a1,cb1c84df,cb7e2aad,939cdfde,581d765b,95c1c25,43016afb,423923ad,75aa7eb1,259434a7,1d58c469,f6268a38,5cd8fb7c,4be64d63,fad9bcea)
-,S(ee534645,42ff07e2,8cf783ee,1da96e00,b81f531,9b9a4885,27f92302,acd12cac,c90704c9,8f72d8be,638a36dc,e8768909,fac7921c,dc54d314,89fbb3e,6da9018a)
-,S(1130e02f,29480660,b2cb4f68,81da3f2c,1bdaf64,8df3b6ce,1a333738,29e4165e,ef2b477b,a9c921df,5ff65b6e,7c6f96a8,627743ff,a53e3858,cd9d7673,f7435ac4)
-,S(e8d3f45a,b5be455f,dc3c2270,34100ca2,b8d203e1,35a9ed3d,5c8b703c,ef4d9b48,2d7d0b7e,4fb4131d,9f21966a,4a73b0f2,639ede1f,26b0ba25,a2580eb,30100c96)
-,S(eb5c4120,4917d176,6fea883b,e680dfd9,233d9654,97fac48b,76f5d0d4,7f6dbf73,97682462,a5c276b7,1568f961,f218a99e,4e528b1b,d4e255b0,acc27744,98ec84fe)
-,S(4097892c,5478baea,62e8da20,6d17fcd8,b8eed45f,24fb7648,fe742508,8da60a4e,10d4b884,5636de20,a009a491,83906957,9d88bc00,5ac1c7a7,3262898b,8bca16b)
-,S(9963e528,754cbba8,29622664,1aec11b0,3fba2739,40f61cbd,5d4c0478,5429f40,d670e3f1,6fc2382,46bf323f,127e7c14,576e3a64,5d5c41da,40f22b29,4fca876c)
-,S(853cffd4,4cb0a29e,390ad886,455566cc,2776ab74,55210e57,9bf1fcc0,c8d767ed,621fdd8d,dd929f3f,681a6f83,bf8061f8,2b4396a6,5df86be6,ec656a86,b1b730b0)
-,S(7fe309bb,e3e8edd3,3f5f94b,4247256e,41e62e69,fd9f2063,d878c6d6,3d85675f,23575727,9da3d12b,c0004d12,e06a9cda,8405c91e,b8118260,2793e62f,16c2a29e)
-,S(851695d4,9a83f8ef,919bb861,53cbcb16,630fb68a,ed0a766a,3ec693d6,8e6afa40,cb47a6a4,91313828,f036dbd7,64173a40,473d3969,5cc47758,511d0a81,badb02f1)
-,S(f31a7dfe,4d2e4a98,aaf3dd70,25441c7a,2da056b0,db6795e8,3a39d76f,b316bd92,17e98bbd,6e144db,959b7aea,cd766958,7be26db5,445ea19d,dab8bc90,1f527cb4)
-,S(2266b5e,d5cef55,81e36315,c5fc5c53,a1c73b12,c24c8de7,9afef2a0,7a50212c,7a60fc27,e4ab0ba6,ea71c036,52b83c5c,5ab5dac8,ea43dec2,84719f8c,6d7c3c81)
-,S(e0089ec9,4b25ac6,ff44b5da,2dfedb37,9fdaedf1,6bc8cecd,b1a95fa0,32431c73,17e98bbd,6e144db,959b7aea,cd766958,7be26db5,445ea19d,dab8bc90,1f527cb4)
-,S(896c7bc,5cfeaecc,37b111ea,2deee270,c7cb24eb,6eb1cb80,a84e87d3,89d997c1,66446d0d,b01a679b,59afb34a,2bbf8cfe,f0a44870,f0e074ce,78a51a36,9bbbf33c)
-,S(709c8403,ed2fd0f9,5fac44f0,dfa96ec2,e7b357e4,4ebb3dcf,6f688f20,39d3d67d,d160b834,5807531a,327a7269,3627dab6,f9770a12,14eb182d,fa73ad15,41b57ff0)
-,S(142f854d,ba0b87a2,9826f018,86ab51ff,b9f19214,c23c07c0,f008a375,a1effdb6,74bafd32,bdf2bdfd,c65a52c3,5ef4f4d,9332f7b2,a0512a9f,f821f858,484bb9c)
-,S(66abbf18,f58dd1c9,4b6072c,eb182abe,c31d3af9,6d91060b,d233f462,5716f289,d380d231,1bde27ad,2c400971,66c3744b,3e762c41,42b05998,95a6605f,739c5fdf)
-,S(7a1b727f,c05c6de2,79b2e027,108fae3e,87ca9249,eb44207f,286e1cbe,4728027,9de02272,226d60c0,97e5907c,407f9e07,d4bc6959,a2079419,139a9578,4e48cb7f)
-,S(3d98fe85,5d42f661,e35d8ce3,cfee5f17,57bc3de9,ecec02fa,11a2d90,378ac0e8,bdc6dc52,8a55814e,da6bcb58,e2a73b96,9d975c7,a3270483,b419b29b,5263f45)
-,S(34f8450b,18bffd3f,cbadcd08,5da5411b,ba2ef195,55753768,bf777307,3a2d4cb4,5771fe9d,21f791df,a78055a3,43570a8d,ce73e816,a9977e63,ec3b2a25,d2e38653)
-,S(76dac07e,bc240289,791e6a9a,56abdc7,bdf2fac1,e7a0100b,5a0ee09e,3455cc33,8b4502cd,420d4202,39a5ad3c,fa10b0b2,6ccd084d,5faed560,7de07a6,fb7b4093)
-,S(929effed,d3b91ccb,a985ab23,bef45c16,6d5ffaa3,22562529,b84d051c,f94044a1,640db9f3,9dda2f51,ee3ef3db,775315aa,c06346f1,e31ff76f,83a24bb0,8fc93242)
-,S(1ea4ff3b,5a0a78a9,fda9d73a,ea5f0629,886b083a,6d3beea4,d6bc96e1,b50da944,9edf1300,7f2b7fb2,92301e8c,77ddb63e,5f2d23c4,315118c1,8b1b6273,86bba11a)
-,S(86fef7a7,b4d3b079,2c83a223,d1c929d6,6ca15202,f4b956a1,cf7ed2cb,83dba7c4,61b51308,ac8643f0,7c18eda7,ef9a4196,aa66221,1b809acc,2b2cb538,23010ef8)
-,S(c979de1c,1318f60f,a9929ff3,a6621b9,d15226e8,2883556e,36a5f77b,28e3b585,d7bd974a,b40a1bd3,a35a1ee9,16d32768,48e7bcfc,be70851d,8ba758b9,996d2099)
-,S(2cdce338,ae1f5aa0,55c76cb5,acbd084e,3284bb5d,b8cf9b4a,141cc8ee,1aa61e59,17e98bbd,6e144db,959b7aea,cd766958,7be26db5,445ea19d,dab8bc90,1f527cb4)
-,S(80c5672b,3f773975,b5829101,6fa9de9b,33863263,8a978db,934f04c1,3a909b85,55ebf47c,6835f232,5ea232b3,8af64478,65cbdce1,2f2c5a79,abc445fd,518ab677)
-,S(521e20fc,9c7c0514,47f31e74,5bb81662,dac66374,9b891a6f,d9681cb6,21e3155c,61b51308,ac8643f0,7c18eda7,ef9a4196,aa66221,1b809acc,2b2cb538,23010ef8)
-,S(b084fee5,5da62ee0,ebdebf3b,245e0d4e,def46aac,bfdc9f43,261d3e2b,eed946a0,80f3b79c,ba5f8457,3f2aa473,1d10c1f,9b6543e1,b8cec5e0,e89cd6df,868cc2aa)
-,S(d8a3fd95,b7ed8e8a,674da307,94911393,303917c2,60944d1f,76261274,fba45757,5ec78d3d,16cc44e8,a26002a4,4a491ef3,a801c3ff,45555ea5,1ffc13c0,63d96081)
-,S(c2d4b350,75ee5eb,3e2c8d3c,f33649dc,dd4f4c29,728bbdae,3f3ff02d,f3dc7415,6120ecff,80d4804d,6dcfe173,882249c1,a0d2dc3b,ceaee73e,74e49d8b,79445b15)
-,S(9fa3c7bd,6b8544f2,df48309,596ea267,8f8537e1,dc406ec7,cf2c67d1,ae5f1e8a,c8268dfc,2da263eb,ac7d81d8,6b8b504d,6d6bc20f,745eef75,bc9bb378,1193744b)
-,S(0,0,0,0,0,0,0,1,34b8595b,6ecec7d7,fc92428,9be8c5bf,b8c2c696,a33b88a7,aee2f57d,4524f93e)
-,S(969360d2,54e2dba9,e79d0789,c339250d,c438330a,a66addf9,f27e2ee8,fc9036ac,99bb92f2,4fe59864,a6504cb5,d4407301,f5bb78f,f1f8b31,875ae5c8,644408f3)
-,S(318f2c1f,3dc109ad,ed9d8958,e2e6eb8c,e26eec32,f2725ad1,68e116c7,497e7044,75b3371,ac71e480,9d8398ec,8376914e,3aab7ea6,bcb96a5,15c6b39b,a6d2ba60)
-,S(bcea96e9,4ff1b11e,6e8a09d6,ec594b00,597e2b0a,37b0e581,50a58d59,33220419,7f0c4863,45a07ba8,c0d55b8c,fe2ef3e0,649abc1e,47313a1f,1763291f,79733985)
-,S(4ed9d2a,7f32fa30,fd059de5,ee512073,47d68d12,b77df5b8,6a83a814,3fcdd5c0,5ec78d3d,16cc44e8,a26002a4,4a491ef3,a801c3ff,45555ea5,1ffc13c0,63d96081)
-,S(875c93a1,8ac5a86e,9e85e4aa,3c5ad0ac,3d697192,6384b05b,568604b3,8fee8fb6,3738dc95,97add4e5,c0a39af1,b98ccba2,7bb43333,e35ab481,54c52779,9191144b)
-,S(47a7cc2e,1cbd64c8,301443ed,be1ab328,85dce80e,a6d8c847,4eb9be09,6db5fecf,d160b834,5807531a,327a7269,3627dab6,f9770a12,14eb182d,fa73ad15,41b57ff0)
-,S(3e8a6608,17f28243,f363d67e,b874856f,1fc9810a,9da6c3f3,a72dd23f,ec45513e,8a8d4c8f,37d2572,6ca66369,59c9eca3,82bd076e,867092a0,b428ad99,2c54a63b)
-,S(9556e393,974bcd02,c6356a53,fce819d4,887b188c,99b8de16,1e5d3697,d595cdce,23575727,9da3d12b,c0004d12,e06a9cda,8405c91e,b8118260,2793e62f,16c2a29e)
-,S(5245e215,52c6f785,2cccef32,e9f54774,cfb6bb9b,c363ae72,71174df4,6d77fdcc,ca78f1f0,894a6670,19609169,78c251dc,64f969e,c25be4b4,202508d3,22d07f3b)
-,S(5d6f8ab3,ca0a5fca,611b7738,16adb4f8,df73ad68,5ce45286,75101d00,54ff3eca,640db9f3,9dda2f51,ee3ef3db,775315aa,c06346f1,e31ff76f,83a24bb0,8fc93242)
-,S(a4465b18,b7f702e2,a8165184,834ce490,68fb0a51,6658734b,6229eda0,605911a2,c8c7236a,68522b1a,3f5c650e,4673345d,844bcccc,1ca54b7e,ab3ad885,6e6ee7e4)
-,S(d49b0640,1e240c43,21b2b173,3b640c6a,e2c4b389,2d3f4f73,8faac78b,9995cf2e,75b3371,ac71e480,9d8398ec,8376914e,3aab7ea6,bcb96a5,15c6b39b,a6d2ba60)
-,S(599db82f,8229ad47,7a662726,d2d351a6,f76cefd7,8fc376b1,ef6e344e,4e4dae3a,284268b5,4bf5e42c,5ca5e116,e92cd897,b7184303,418f7ae2,7458a745,6692db96)
-,S(a0627644,ebc6a423,1f3e113b,eedbf9d8,21d9374a,af2e7c55,14ee7395,aa9992b7,859f03d8,1b54f459,158e3fc9,ad47c3a3,a54a2537,15bc213d,7b8e6072,9283bfae)
-};
-static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = {
- S(ec823227,1d0e875a,8e1cf7e6,f9a35a15,749be650,1cc885c4,f383060b,46bd3d33,aa140b83,97ca0dcd,a15dcd4c,7509bb87,9a34231e,d0d3a586,543bba01,ae7545b8)
-,S(66abbf18,f58dd1c9,4b6072c,eb182abe,c31d3af9,6d91060b,d233f462,5716f289,d380d231,1bde27ad,2c400971,66c3744b,3e762c41,42b05998,95a6605f,739c5fdf)
-,S(4d756b2,e61d9806,e02ec830,f1fd44f8,46438689,c528346,15a1addf,ac864bcd,36f8fb36,708d2741,9c75c923,178976f6,5386de3,23ab2ceb,f76044c0,9256faa5)
-,S(875c93a1,8ac5a86e,9e85e4aa,3c5ad0ac,3d697192,6384b05b,568604b3,8fee8fb6,c8c7236a,68522b1a,3f5c650e,4673345d,844bcccc,1ca54b7e,ab3ad885,6e6ee7e4)
-,S(f3a864ac,edc7852f,f4dfae93,5f8588a6,96ff17bf,7233134e,6704ceb,16f3b74c,39cfeb15,665f371f,535d56c1,317a8d62,29ea2827,943a98f1,cee7f685,86e47eec)
-,S(3e8a6608,17f28243,f363d67e,b874856f,1fc9810a,9da6c3f3,a72dd23f,ec45513e,8a8d4c8f,37d2572,6ca66369,59c9eca3,82bd076e,867092a0,b428ad99,2c54a63b)
-,S(47bbafcd,f612ca3e,703f7721,623bde14,926fc00d,a6bf9e9,41ddb2d5,587626e3,d160b834,5807531a,327a7269,3627dab6,f9770a12,14eb182d,fa73ad15,41b57ff0)
-,S(709c8403,ed2fd0f9,5fac44f0,dfa96ec2,e7b357e4,4ebb3dcf,6f688f20,39d3d67d,2e9f47cb,a7f8ace5,cd858d96,c9d82549,688f5ed,eb14e7d2,58c52e9,be4a7c3f)
-,S(66fd0ada,7159c2df,fdd925e7,2eb70772,743e39e3,4c10d5cf,f58eac4e,a30e4157,8a8d4c8f,37d2572,6ca66369,59c9eca3,82bd076e,867092a0,b428ad99,2c54a63b)
-,S(60d5d771,4e1e7589,e0b1e68c,ed7f881,73fca809,eae35685,65334942,79962dc2,99bb92f2,4fe59864,a6504cb5,d4407301,f5bb78f,f1f8b31,875ae5c8,644408f3)
-,S(3d98fe85,5d42f661,e35d8ce3,cfee5f17,57bc3de9,ecec02fa,11a2d90,378ac0e8,bdc6dc52,8a55814e,da6bcb58,e2a73b96,9d975c7,a3270483,b419b29b,5263f45)
-,S(2f63a396,4d14ca73,2167e033,306863d8,f75605c7,4ea6c917,890dd50d,fc20f53b,1dd6a38e,deb870ad,f2b2e755,8d327d51,e66a2c81,910d1fa5,b215911c,9c8e004c)
-,S(bcea96e9,4ff1b11e,6e8a09d6,ec594b00,597e2b0a,37b0e581,50a58d59,33220419,80f3b79c,ba5f8457,3f2aa473,1d10c1f,9b6543e1,b8cec5e0,e89cd6df,868cc2aa)
-,S(ae3796a4,823f3eb4,ea4bd677,110dc3fb,45537c3c,4d10d2e8,e758a3be,4875db83,ef2b477b,a9c921df,5ff65b6e,7c6f96a8,627743ff,a53e3858,cd9d7673,f7435ac4)
-,S(5245e215,52c6f785,2cccef32,e9f54774,cfb6bb9b,c363ae72,71174df4,6d77fdcc,ca78f1f0,894a6670,19609169,78c251dc,64f969e,c25be4b4,202508d3,22d07f3b)
-,S(26e2e75b,aeb04a72,8b893f67,d27ebfc6,b8984a88,6fbd8eee,5719107d,5a413f0f,61b51308,ac8643f0,7c18eda7,ef9a4196,aa66221,1b809acc,2b2cb538,23010ef8)
-,S(e0089ec9,4b25ac6,ff44b5da,2dfedb37,9fdaedf1,6bc8cecd,b1a95fa0,32431c73,e8167442,f91ebb24,6a648515,328996a7,841d924a,bba15e62,2547436e,e0ad7f7b)
-,S(f8f16642,266d8dc6,abfdbbc6,f6c47711,a192c051,7f00a633,b78076a7,a7884e72,4f6d0e5,148ce7e1,772f84c,b08903b8,71d2beb5,d0934488,8ab1c75d,42232790)
-,S(23082df9,a86b80fc,5185ee3c,6493763b,14a6e237,baf686aa,f589b649,8573d04c,bdc6dc52,8a55814e,da6bcb58,e2a73b96,9d975c7,a3270483,b419b29b,5263f45)
-,S(76dac07e,bc240289,791e6a9a,56abdc7,bdf2fac1,e7a0100b,5a0ee09e,3455cc33,8b4502cd,420d4202,39a5ad3c,fa10b0b2,6ccd084d,5faed560,7de07a6,fb7b4093)
-,S(8735fb32,6950ae71,31cd03f7,cc1511d8,65c87e84,748c9824,8ccc576e,5480ed8,c63014ea,99a0c8e0,aca2a93e,ce85729d,d615d7d8,6bc5670e,31180979,791b7d43)
-,S(969360d2,54e2dba9,e79d0789,c339250d,c438330a,a66addf9,f27e2ee8,fc9036ac,66446d0d,b01a679b,59afb34a,2bbf8cfe,f0a44870,f0e074ce,78a51a36,9bbbf33c)
-,S(74f5ba33,89d075d3,eebaa54d,73e9f038,881b7329,5623e833,b5e87beb,29ba3246,74bafd32,bdf2bdfd,c65a52c3,5ef4f4d,9332f7b2,a0512a9f,f821f858,484bb9c)
-,S(a4465b18,b7f702e2,a8165184,834ce490,68fb0a51,6658734b,6229eda0,605911a2,c8c7236a,68522b1a,3f5c650e,4673345d,844bcccc,1ca54b7e,ab3ad885,6e6ee7e4)
-,S(eac612b0,84cb452a,35d49c60,c0d0c0bd,359eb909,68a80186,92a028f,ece4c331,23575727,9da3d12b,c0004d12,e06a9cda,8405c91e,b8118260,2793e62f,16c2a29e)
-,S(f31a7dfe,4d2e4a98,aaf3dd70,25441c7a,2da056b0,db6795e8,3a39d76f,b316bd92,e8167442,f91ebb24,6a648515,328996a7,841d924a,bba15e62,2547436e,e0ad7f7b)
-,S(470ce05d,53f77ff0,c5ab8770,a4c11a3e,23f7d4fe,f5c0ab36,1b940a8a,6b8cf7b9,57d6adb1,5f0b1daa,1fce91d7,ccf75d45,9480b056,6f81ff8a,85612173,1cd8f2b8)
-,S(d9fbce92,515652cf,3714f87b,e16e505,91a28eb4,1bf7053,2ab42ebd,be900212,2d7d0b7e,4fb4131d,9f21966a,4a73b0f2,639ede1f,26b0ba25,a2580eb,30100c96)
-,S(1ea4ff3b,5a0a78a9,fda9d73a,ea5f0629,886b083a,6d3beea4,d6bc96e1,b50da944,9edf1300,7f2b7fb2,92301e8c,77ddb63e,5f2d23c4,315118c1,8b1b6273,86bba11a)
-,S(3d303d12,f8eb67d0,ecaee514,bdd90e57,b58b6d6a,c896a26f,78c06103,52225b04,2d7d0b7e,4fb4131d,9f21966a,4a73b0f2,639ede1f,26b0ba25,a2580eb,30100c96)
-,S(9fa3c7bd,6b8544f2,df48309,596ea267,8f8537e1,dc406ec7,cf2c67d1,ae5f1e8a,37d97203,d25d9c14,53827e27,9474afb2,92943df0,8ba1108a,43644c86,ee6c87e4)
-,S(92906a31,52682000,a59736ed,ef48a7b0,c78d6a49,8727b3b,893d3478,de04ada5,80f3b79c,ba5f8457,3f2aa473,1d10c1f,9b6543e1,b8cec5e0,e89cd6df,868cc2aa)
-,S(599db82f,8229ad47,7a662726,d2d351a6,f76cefd7,8fc376b1,ef6e344e,4e4dae3a,284268b5,4bf5e42c,5ca5e116,e92cd897,b7184303,418f7ae2,7458a745,6692db96)
-,S(ee534645,42ff07e2,8cf783ee,1da96e00,b81f531,9b9a4885,27f92302,acd12cac,c90704c9,8f72d8be,638a36dc,e8768909,fac7921c,dc54d314,89fbb3e,6da9018a)
-,S(7fe309bb,e3e8edd3,3f5f94b,4247256e,41e62e69,fd9f2063,d878c6d6,3d85675f,dca8a8d8,625c2ed4,3fffb2ed,1f956325,7bfa36e1,47ee7d9f,d86c19cf,e93d5991)
-,S(64eaaad1,9c7e9d01,5cc997ff,c2f23022,c59805d,48a48e1,970b8847,10211659,fb092f1a,eb73181e,f88d07b3,4f76fc47,8e2d414a,2f6cbb77,754e38a1,bddcd49f)
-,S(59e10f43,eb4b2fb0,94f2f66d,1404dd08,ab9c2442,50bd16e0,21feb78f,e0380d01,e2295c71,21478f52,d4d18aa,72cd82ae,1995d37e,6ef2e05a,4dea6ee2,6371fbe3)
-,S(c979de1c,1318f60f,a9929ff3,a6621b9,d15226e8,2883556e,36a5f77b,28e3b585,d7bd974a,b40a1bd3,a35a1ee9,16d32768,48e7bcfc,be70851d,8ba758b9,996d2099)
-,S(64dd1439,5d19a544,a7a1e81b,b9d079b3,593e7022,6bcd444e,6dc8197a,1a6dc3e6,d380d231,1bde27ad,2c400971,66c3744b,3e762c41,42b05998,95a6605f,739c5fdf)
-,S(d8a3fd95,b7ed8e8a,674da307,94911393,303917c2,60944d1f,76261274,fba45757,a13872c2,e933bb17,5d9ffd5b,b5b6e10c,57fe3c00,baaaa15a,e003ec3e,9c269bae)
-,S(acee4285,57fc32a1,d3d14199,30cadaf0,613a630a,7a7e8c14,d08d05df,19143c3a,ca78f1f0,894a6670,19609169,78c251dc,64f969e,c25be4b4,202508d3,22d07f3b)
-,S(5d771e5d,6dc6c87,5ede8bae,4b27a9d4,3c5f8da2,8e84f5c3,501299c8,db16484c,859f03d8,1b54f459,158e3fc9,ad47c3a3,a54a2537,15bc213d,7b8e6072,9283bfae)
-,S(e8d3f45a,b5be455f,dc3c2270,34100ca2,b8d203e1,35a9ed3d,5c8b703c,ef4d9b48,2d7d0b7e,4fb4131d,9f21966a,4a73b0f2,639ede1f,26b0ba25,a2580eb,30100c96)
-,S(9963e528,754cbba8,29622664,1aec11b0,3fba2739,40f61cbd,5d4c0478,5429f40,298f1c0e,f903dc7d,b940cdc0,ed8183eb,a891c59b,a2a3be25,bf0dd4d5,b03574c3)
-,S(cbdb65,553cd5d8,ff61cf33,e53fdd9a,cf0ee159,c21dc578,be5bac2b,7973c229,ca78f1f0,894a6670,19609169,78c251dc,64f969e,c25be4b4,202508d3,22d07f3b)
-,S(5029bff6,d4c80347,738230c8,cb252906,471b5bc1,3d26a533,304f5f0d,808f756c,97682462,a5c276b7,1568f961,f218a99e,4e528b1b,d4e255b0,acc27744,98ec84fe)
-,S(80c5672b,3f773975,b5829101,6fa9de9b,33863263,8a978db,934f04c1,3a909b85,55ebf47c,6835f232,5ea232b3,8af64478,65cbdce1,2f2c5a79,abc445fd,518ab677)
-,S(226e653f,c8df7744,9bacbf12,7d1dcbf9,87f05b2a,e7edbd28,1f564575,c48dcf18,5ec78d3d,16cc44e8,a26002a4,4a491ef3,a801c3ff,45555ea5,1ffc13c0,63d96081)
-,S(521e20fc,9c7c0514,47f31e74,5bb81662,dac66374,9b891a6f,d9681cb6,21e3155c,9e4aecf7,5379bc0f,83e71258,1065be69,f5599dde,e47f6533,d4d34ac6,dcfeed37)
-,S(5472b5d0,4ba1ca80,236183b1,46e596e5,4b20b83b,248988c8,bbe8460e,3666f262,a829524e,a0f4e255,e0316e28,3308a2ba,6b7f4fa9,907e0075,7a9ede8b,e3270977)
-,S(2ecd421e,47399e76,60d10143,1789a437,89b54d23,31d1cb78,49cabda2,bc5174f9,c8268dfc,2da263eb,ac7d81d8,6b8b504d,6d6bc20f,745eef75,bc9bb378,1193744b)
-,S(4097892c,5478baea,62e8da20,6d17fcd8,b8eed45f,24fb7648,fe742508,8da60a4e,10d4b884,5636de20,a009a491,83906957,9d88bc00,5ac1c7a7,3262898b,8bca16b)
-,S(eb5c4120,4917d176,6fea883b,e680dfd9,233d9654,97fac48b,76f5d0d4,7f6dbf73,6897db9d,5a3d8948,ea97069e,de75661,b1ad74e4,2b1daa4f,533d88ba,67137731)
-,S(92b866ad,a37a3f2f,bc607717,96b2c74f,57dde74c,da8e015f,792df531,7eb21fa6,55ebf47c,6835f232,5ea232b3,8af64478,65cbdce1,2f2c5a79,abc445fd,518ab677)
-,S(a78dab,f2f2ef7f,4d424752,aa1aeaf5,50bec241,bf9ad129,3b9fe680,32b6141b,9de02272,226d60c0,97e5907c,407f9e07,d4bc6959,a2079419,139a9578,4e48cb7f)
-,S(b084fee5,5da62ee0,ebdebf3b,245e0d4e,def46aac,bfdc9f43,261d3e2b,eed946a0,80f3b79c,ba5f8457,3f2aa473,1d10c1f,9b6543e1,b8cec5e0,e89cd6df,868cc2aa)
-,S(ff1755e,623c8369,f55edda4,2a5deef0,b32c57f4,80c5884f,d2a2dde1,b1c078c4,640db9f3,9dda2f51,ee3ef3db,775315aa,c06346f1,e31ff76f,83a24bb0,8fc93242)
-,S(2cdce338,ae1f5aa0,55c76cb5,acbd084e,3284bb5d,b8cf9b4a,141cc8ee,1aa61e59,e8167442,f91ebb24,6a648515,328996a7,841d924a,bba15e62,2547436e,e0ad7f7b)
-,S(3faf6744,2aebb675,c6b75911,e3d34f4c,a8f5b669,a4c438f2,2c163659,3e36c1ea,fc0b579e,cbaf2c74,7b5c792d,7b66abf2,dfb1a44d,2ed6a417,7e1fc6bd,a989b623)
-,S(34772cad,ad5888f2,53a810b7,5b175b8d,e3a454e4,26a1b5a5,c003f222,8e7b45c0,d380d231,1bde27ad,2c400971,66c3744b,3e762c41,42b05998,95a6605f,739c5fdf)
-,S(853cffd4,4cb0a29e,390ad886,455566cc,2776ab74,55210e57,9bf1fcc0,c8d767ed,621fdd8d,dd929f3f,681a6f83,bf8061f8,2b4396a6,5df86be6,ec656a86,b1b730b0)
-,S(1130e02f,29480660,b2cb4f68,81da3f2c,1bdaf64,8df3b6ce,1a333738,29e4165e,10d4b884,5636de20,a009a491,83906957,9d88bc00,5ac1c7a7,3262898b,8bca16b)
-,S(a0627644,ebc6a423,1f3e113b,eedbf9d8,21d9374a,af2e7c55,14ee7395,aa9992b7,7a60fc27,e4ab0ba6,ea71c036,52b83c5c,5ab5dac8,ea43dec2,84719f8c,6d7c3c81)
-,S(1e864d74,9e96a16a,c4299b88,226aaff9,9a45ab9c,203853ac,ea0378ef,5715ded6,6120ecff,80d4804d,6dcfe173,882249c1,a0d2dc3b,ceaee73e,74e49d8b,79445b15)
-};
-#else
- #error No known generator for the specified exhaustive test group order.
-#endif
-#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
+#ifdef EXHAUSTIVE_TEST_ORDER
+# error Cannot compile precomputed_ecmult.c in exhaustive test mode
+#endif /* EXHAUSTIVE_TEST_ORDER */
#define WINDOW_G ECMULT_WINDOW_SIZE
-static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = {
+const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = {
S(79be667e,f9dcbbac,55a06295,ce870b07,29bfcdb,2dce28d9,59f2815b,16f81798,483ada77,26a3c465,5da4fbfc,e1108a8,fd17b448,a6855419,9c47d08f,fb10d4b8)
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 1
+#if WINDOW_G > 2
,S(f9308a01,9258c310,49344f85,f89d5229,b531c845,836f99b0,8601f113,bce036f9,388f7b0f,632de814,fe337e6,2a37f356,6500a999,34c2231b,6cb9fd75,84b8e672)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 2
+#if WINDOW_G > 3
,S(2f8bde4d,1a072093,55b4a725,a5c5128,e88b84bd,dc619ab7,cba8d569,b240efe4,d8ac2226,36e5e3d6,d4dba9dd,a6c9c426,f788271b,ab0d6840,dca87d3a,a6ac62d6)
,S(5cbdf064,6e5db4ea,a398f365,f2ea7a0e,3d419b7e,330e39c,e92bdded,cac4f9bc,6aebca40,ba255960,a3178d6d,861a54db,a813d0b8,13fde7b5,a5082628,87264da)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 4
+#if WINDOW_G > 4
,S(acd484e2,f0c7f653,9ad178a,9f559abd,e0979697,4c57e714,c35f110d,fc27ccbe,cc338921,b0a7d9fd,64380971,763b61e9,add888a4,375f8e0f,5cc262a,c64f9c37)
,S(774ae7f8,58a9411e,5ef4246b,70c65aac,5649980b,e5c17891,bbec1789,5da008cb,d984a032,eb6b5e19,243dd56,d7b7b365,372db1e2,dff9d6a8,301d74c9,c953c61b)
,S(f28773c2,d975288b,c7d1d205,c3748651,b075fbc6,610e58cd,deeddf8f,19405aa8,ab0902e,8d880a89,758212eb,65cdaf47,3a1a06da,521fa91f,29b5cb52,db03ed81)
,S(d7924d4f,7d43ea96,5a465ae3,95ff411,31e5946f,3c85f79e,44adbcf8,e27e080e,581e2872,a86c72a6,83842ec2,28cc6def,ea40af2b,d896d3a5,c504dc9f,f6a26b58)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 8
+#if WINDOW_G > 5
,S(defdea4c,db677750,a420fee8,7eacf21,eb9898ae,79b97687,66e4faa0,4a2d4a34,4211ab06,94635168,e997b0ea,d2a93dae,ced1f4a0,4a95c0f6,cfb199f6,9e56eb77)
,S(2b4ea0a7,97a443d2,93ef5cff,444f4979,f06acfeb,d7e86d27,74756561,38385b6c,85e89bc0,37945d93,b343083b,5a1c8613,1a01f60c,50269763,b570c854,e5c09b7a)
,S(352bbf4a,4cdd1256,4f93fa33,2ce33330,1d9ad402,71f81071,81340aef,25be59d5,321eb407,5348f534,d59c1825,9dda3e1f,4a1b3b2e,71b1039c,67bd3d8b,cf81998c)
@@ -191,7 +42,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(c44d12c7,65d812e,8acf28d7,cbb19f90,11ecd9e9,fdf281b0,e6a3b5e8,7d22e7db,2119a460,ce326cdc,76c45926,c982fdac,e106e86,1edf61c5,a039063f,e0e6482)
,S(6a245bf6,dc698504,c89a20cf,ded60853,152b6953,36c28063,b61c65cb,d269e6b4,e022cf42,c2bd4a70,8b3f5126,f16a24ad,8b33ba48,d0423b6e,fd5e6348,100d8a82)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 16
+#if WINDOW_G > 6
,S(1697ffa6,fd9de627,c077e3d2,fe541084,ce13300b,bec1146,f95ae57f,d0bd6a5,b9c398f1,86806f5d,27561506,e4557433,a2cf1500,9e498ae7,adee9d63,d01b2396)
,S(605bdb01,9981718b,986d0f07,e834cb0d,9deb8360,ffb7f61d,f982345e,f27a7479,2972d2d,e4f8d206,81a78d93,ec96fe23,c26bfae8,4fb14db4,3b01e1e9,56b8c49)
,S(62d14dab,4150bf49,7402fdc4,5a215e10,dcb01c35,4959b10c,fe31c7e9,d87ff33d,80fc06bd,8cc5b010,98088a19,50eed0db,1aa1329,67ab4722,35f56424,83b25eaf)
@@ -209,7 +60,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(754e3239,f325570c,dbbf4a87,deee8a66,b7f2b334,79d468fb,c1a50743,bf56cc18,673fb86,e5bda30f,b3cd0ed3,4ea49a0,23ee33d0,197a695d,c5d9809,3c536683)
,S(e3e6bd10,71a1e96a,ff57859c,82d570f0,33080066,1d1c952f,9fe26946,91d9b9e8,59c9e0bb,a394e76f,40c0aa58,379a3cb6,a5a22839,93e90c41,67002af4,920e37f5)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 32
+#if WINDOW_G > 7
,S(186b483d,56a0338,26ae73d8,8f732985,c4ccb1f3,2ba35f4b,4cc47fdc,f04aa6eb,3b952d32,c67cf77e,2e17446e,204180ab,21fb8090,895138b4,a4a797f8,6e80888b)
,S(df9d70a6,b9876ce5,44c98561,f4be4f72,5442e6d2,b737d9c9,1a832172,4ce0963f,55eb2daf,d84d6ccd,5f862b78,5dc39d4a,b1572227,20ef9da2,17b8c45c,f2ba2417)
,S(5edd5cc2,3c51e87a,497ca815,d5dce0f8,ab52554f,849ed899,5de64c5f,34ce7143,efae9c8d,bc141306,61e8cec0,30c89ad0,c13c66c0,d17a2905,cdc706ab,7399a868)
@@ -243,7 +94,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(c4191636,5abb2b5d,9192f5f,2dbeafec,208f020f,12570a18,4dbadc3e,58595997,4f14351,d0087efa,49d245b3,28984989,d5caf945,f34bfc0,ed16e96b,58fa9913)
,S(841d6063,a586fa47,5a724604,da03bc5b,92a2e0d2,e0a36acf,e4c73a55,14742881,73867f5,9c0659e8,1904f9a1,c7543698,e62562d6,744c169c,e7a36de0,1a8d6154)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 64
+#if WINDOW_G > 8
,S(5e95bb39,9a6971d3,76026947,f89bde2f,282b3381,928be4d,ed112ac4,d70e20d5,39f23f36,6809085b,eebfc711,81313775,a99c9aed,7d8ba38b,161384c7,46012865)
,S(36e4641a,53948fd4,76c39f8a,99fd974e,5ec07564,b5315d8b,f99471bc,a0ef2f66,d2424b1b,1abe4eb8,164227b0,85c9aa94,56ea1349,3fd563e0,6fd51cf5,694c78fc)
,S(336581e,a7bfbbb2,90c191a2,f507a41c,f5643842,170e914f,aeab27c2,c579f726,ead12168,595fe1be,99252129,b6e56b33,91f7ab14,10cd1e0e,f3dcdcab,d2fda224)
@@ -309,7 +160,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(809a20c6,7d64900f,fb698c4c,825f6d5f,2310fb04,51c86934,5b7319f6,45605721,9e994980,d9917e22,b76b0619,27fa0414,3d096ccc,54963e6a,5ebfa5f3,f8e286c1)
,S(1b38903a,43f7f114,ed4500b4,eac7083f,defece1c,f29c6352,8d563446,f972c180,4036edc9,31a60ae8,89353f77,fd53de4a,2708b26b,6f5da72a,d3394119,daf408f9)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 128
+#if WINDOW_G > 9
,S(90a80db6,eb294b9e,ab0b4e8d,dfa3efe7,263458ce,2d07566d,f4e6c588,68feef23,753c8b9f,9754f18d,87f21145,d9e2936b,5ee050b2,7bbd9681,442c76e9,2fcf91e6)
,S(c2c80f84,4b705998,12d62546,f60340e,3e6f3605,4a14546e,6dc25d47,376bea9b,86ca160d,68f4d4e7,18b495b8,91d3b1b5,73b871a7,2b4cf61,23abd448,3aa79c64)
,S(9cf60674,4cf4b5f3,fdf989d3,f19fb265,2d00cfe1,d5fcd692,a323ce11,a28e7553,8147cbf7,b973fcc1,5b57b6a3,cfad6863,edd0f30e,3c45b85d,c300c513,c247759d)
@@ -439,7 +290,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(367807c9,a3606b4e,1b8c2616,ad528030,1dfcf686,40eddf02,fc59317c,230e9a86,1f023f2f,a2bbece7,3dba14c,124095cb,fdc4f92f,281a14,8304a412,c16ecae6)
,S(8ec4fdc3,9891f6af,1374e06f,c44b815,1b82541,75fc4909,acba5941,201af62b,2dc6cae5,cac2d887,83dca0e5,3c798f8,fe067bcf,5fc29751,13756cf7,ef4e5f1b)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 256
+#if WINDOW_G > 10
,S(5cc24a6d,4c5b24f9,14542f91,e5fa937f,ffa08551,51b8b842,8729b06a,9178a263,b1da8635,81531a1f,bfb38a4e,419fa1fe,ca8d55a8,3ddbcb98,da19d5cf,fb7da472)
,S(83905926,c03905c3,a9644a6c,da810dd2,92602a50,50c52a21,9134fc4d,e3599e9f,4293260f,e8af6792,a20b115e,aa837638,9094298b,21d9de16,cf20e0c5,7a46089a)
,S(944b097e,4721e9dd,f8204ac3,d3878fa,e8fa6c14,34ae4822,481b2985,6589b6c7,5fc47565,30e9b095,f8b79643,1e745b99,1525bd4c,4764e8e,e8af4b96,9bd6ddf6)
@@ -697,7 +548,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(d9a0c689,95283291,972d6a72,897181b2,6b4ae317,4e98a676,f75bbfbf,81be876e,d36ae886,a0acbc9a,d1564d97,4d3f0309,e9039b93,bb350d92,2b7f8c7a,c6bfa042)
,S(c7a36324,6aeb7c8c,991b2aa7,10abdf5c,fff29912,30b3a69f,be2dd481,7c7c3e0a,1298fdd7,e448d2d,79986302,6b4b2d49,2b32148,d6d1e5f8,15f5b0c0,5c9e21f)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 512
+#if WINDOW_G > 11
,S(635cd7a0,5064d3bc,66535a0,4dbf563a,640d2464,c7fe0ac4,8304214f,e4985a86,e40265,913e77f6,46735cfc,af9e2f30,e8d5f047,f3281a4c,e0453e27,e9e3ae1f)
,S(5da624f,38edea25,37f5b632,695b481a,eca54bb7,2169cadc,c5b91e10,989ee5f5,d3ea6dba,a1080300,fffaeeb2,43a5256e,48c28822,37b16505,a220d771,ca721779)
,S(aa4f64a2,b19775ec,92c1f687,1fe4b6d5,ce05278c,2976c80e,fe19284f,e87d4d5e,f39f117e,95fce0fb,6976e949,9583a66c,224ea028,8396518e,293793dc,3ed4f240)
@@ -1211,7 +1062,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(dd879eba,f870ee3d,f6e3f03,60833e12,fbdf844c,d6a5b76c,19802485,6649bbc1,e7bb04c3,a99a5c11,dd7a324c,1d5696c8,b041a12a,c6a538f7,3094716c,9943c55a)
,S(7aa4afbe,29b06a1e,da9319d5,72572b13,1df68f74,1b5f8d8e,d00ccc04,80f8016e,15f79a9f,b77b8587,7f02e3c1,3202b972,423fd00d,937c0d2d,c9d94b17,53fe7130)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 1024
+#if WINDOW_G > 12
,S(9145f3f5,876a3265,5d7fee64,f2d6e660,c34354e9,1571d68b,a19e4cc5,8c39f890,45e0a95d,cf369fd0,5bc9ba7f,da108d6f,37650c1d,5766b6c9,98ecda28,b285d8ff)
,S(5450b752,36fb010d,1ef37afa,2077f3dc,a5a7f6c8,91a21317,13df740f,4511ac9e,a7c7ed57,62bef86d,4de1084d,3ded2d7b,13ff563a,67109ef0,8b6f0180,fe6ba175)
,S(ba6c0d72,5e48de2c,cb8256d6,7417d075,bbf2766f,d13501b8,4c32cf88,c0666a0f,cd2a9132,7137299f,50eda669,3a599032,bdecd64b,91bcc640,5ed186f3,e525e442)
@@ -2237,7 +2088,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(6d109d8c,2505808f,7b4052d6,b170ec80,c68373bb,e02f2b62,1cd29773,a96acb3e,c8dea0de,511f6e40,5141088e,cb023bff,200c870b,9cb952ad,c5038b28,eadc9a57)
,S(9c219898,6d202467,c055c734,73557505,6105b3e,2874dbf2,8f7f0c39,66e1af88,8637496c,8eddff12,f9dd4146,36565e0f,efddf5cd,52d48455,ec9fb2d,8dd0914a)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 2048
+#if WINDOW_G > 13
,S(22ca5039,e660f60,1036dd75,2bb973b,dcd104b5,dcb8f2e7,4de8edc6,c292b03a,86fd4471,1ef6b81e,4416449a,708fa0c9,cb6731ba,c403e58e,da5e915f,646b11e8)
,S(cfc18f02,cc004640,f2116fdd,1f6ca202,2e39be25,df75e27c,80bde842,e6b6f938,d62b58df,4f79d0e5,97ba2923,f708cbe5,c09236a4,d9d01398,6451d684,6290df7d)
,S(3388bcc2,3425458e,991f46ca,6235c50a,57490556,becbaf25,9d3c14f9,9a80a087,7d4aa2f8,6f65783,1c22316,6958fbf3,6c3dca5,d4ac413b,3102e13e,a645c016)
@@ -4287,7 +4138,7 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(d5acff71,e82a455c,3a1ce292,689e8686,f441ce1b,e644e79a,bd6d0efe,29270865,aac6d48f,1b46e970,a044971a,ad13f033,ca8cde96,958d870e,dc7d80,1d26d5e8)
,S(5cf51c1b,2210d85,9d765e17,32109514,8f03fc57,51004b6a,91f098e2,e2711596,1eeb19e0,610df459,2c31e58e,aa2a2148,17fe9ee,a3995838,f395bdcf,26d5c3b3)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 4096
+#if WINDOW_G > 14
,S(21456873,b58e3687,52c75800,8d3bcae,9efaf1f5,c5727842,25e3d854,8fd421cb,a2f2d10,c85e8a0f,4a136ad0,5df991ce,7d3c5585,a263d5cf,da50a4f4,3db76cb0)
,S(c10de5c0,51ae2d73,28ac06ca,cca840b4,ed7ab204,21c6122f,1d68fe7f,7893d38d,ee30e086,a891484,2ad4041,f9ab9c57,cff1a315,f0642d31,b31c2914,faac99e0)
,S(be778032,f12c1b77,9bba3d9e,d290ca90,30ac7050,bdd77a2,7eac09be,eea65c0b,8657348b,a1e27a63,1dd2a54b,e2d5270f,4cca817a,219c5378,4d4f73ba,2c932e63)
@@ -8386,22 +8237,22 @@ static const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] =
,S(1e70619c,381a6adc,e5d925e0,c9c74f97,3c02ff64,ff2662d7,34efc485,d2bce895,c923f771,f543ffed,42935c28,8474aaaf,80a46ad4,3c579ce0,bb5e663d,668b24b3)
#endif
};
-static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = {
+const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = {
S(8f68b9d2,f63b5f33,9239c1ad,981f162e,e88c5678,723ea335,1b7b444c,9ec4c0da,662a9f2d,ba063986,de1d90c2,b6be215d,bbea2cfe,95510bfd,f23cbf79,501fff82)
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 1
+#if WINDOW_G > 2
,S(38381dbe,2e509f22,8ba93363,f2451f08,fd845cb3,51d954be,18e2b8ed,d23809fa,e4a32d0a,fb917dc,b09405a5,520eb1cc,3681fccb,32d8f24d,bd707518,331fed52)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 2
+#if WINDOW_G > 3
,S(49262724,e4372ae6,f6921b82,aa4699a1,f186aea5,40122630,3ea42648,97c2a310,1337e773,bca7abf9,5a2cfa56,9714303b,6d163612,a75ff8ce,c41b681,5e27ded0)
,S(e306568c,1a240c90,d5e253b3,e477e2f8,4dcc1a56,ff06db8d,1384b079,cebd2d31,eac6fe3,78934260,888f2b10,7f7d0db6,ffbc8042,be373826,692b4083,92546e44)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 4
+#if WINDOW_G > 4
,S(3b9e100e,2428cefc,271b0e76,23fbd633,74ebf8d9,aab41dd9,c530c39e,363136b0,fafb9815,2d16bb71,df1533eb,8f475b26,a2ae28a3,3ad31f81,953ec16f,6cdbbc8a)
,S(bb0aad49,712ac9a9,2b76ca80,f5dedef7,17ca0768,8107beee,9608f047,2f485d3f,ea699c53,c5835479,8ecd201f,7297da34,895a5afa,31670bff,e7939250,3ca2f975)
,S(79090ac8,e4eefcc0,d4e8eb19,7afe0113,e1e58b4d,b01123de,4aeed33a,36718dc9,eaab722b,91905b8f,13d816cb,cd9aaa56,dd36afb7,ba9008b,963322b1,1cfae7c5)
,S(e77c81ad,e9f97b55,1c03dbbc,e549ba66,8dd71de7,cd775ad2,a269694c,7f60c7d1,3acf1478,eef81321,c5fc3b32,3ea81543,631470f7,1c2986d3,4ec581f2,82d72449)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 8
+#if WINDOW_G > 5
,S(de2b5ce9,dbce511c,f2d8878e,3ded87cc,3d633dae,a2d45341,501fb3a4,55ccf6b0,f10576f3,d3c3e0e1,bbf717e9,8b1a3744,65b8c45a,c66318bb,34829eb7,11100666)
,S(d07bddff,d491a2fe,1ea59fbd,7c121217,29659ca5,de46658b,26b1460b,13c03c56,b2ad4708,cd3c97dd,f9c40e2,a1de04d5,61d963ff,8cc2eea7,6be3f60c,2b405ce7)
,S(82403e7c,5d3016af,3765ec4c,396ce8e1,f8da45c,434b8257,10edab41,bb6a4d51,d09661b,e27cb767,4456badd,b3e84051,99ab6ccc,4ec67c1b,11e92ead,7b463b19)
@@ -8411,7 +8262,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(1f56f096,b18a7499,a153a5ae,acf8be05,8496dd23,da8e6c19,215628fb,c0567ed0,fef22b8a,3b52f490,83004436,b65cd69,c94189f4,1a93c0d5,1fc13cb4,379dff58)
,S(1d9f69b1,a4a47432,e386f525,234aa30,79e947cf,cf203297,4e0fc05b,638e213b,d898ec17,949c0761,b38500c3,a2b1da24,5438d5b3,d3f6f720,41f15d6e,e4d4ccbb)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 16
+#if WINDOW_G > 6
,S(128c913,4d9dcb78,12fc4361,5c67ad0,55213354,dc8008b1,aeb5a9dc,fb629efd,fee3e54a,dd152610,d9725936,99d662,c160c8e4,ec6f76e4,5ff41818,be67c96)
,S(21ec012f,5a95b94d,244b8d51,9756075c,301f2854,8e2c51fc,49c0e3d9,d1a9685,2def2105,77af497f,4c7fef71,6949f28e,7418eda6,fd5fc162,d128de19,3cde08ae)
,S(688f5202,fb9d8bc0,9e480e89,4c7cfc74,761c3be7,7dafb11c,58422836,3e331cc5,96ba7d59,63b541a7,2ec7cabd,92403434,1a393eaf,89eebd94,62d9c218,c7302cd3)
@@ -8429,7 +8280,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(144e88f6,3e73abff,72cac11e,7ddccf79,19e744e6,278941ae,18d1b797,e098e4e5,63cdbf3,5df3c655,c58197f,ea54633d,158705cf,7dc2eb3b,4e09f83c,3021837c)
,S(9436e3dc,489ecd8e,2d16a739,c9c73e3d,60e5bc93,68157039,75b8efbd,5c3a9081,1460531f,50cb6ebf,d1aa7806,ea84e7f7,8e8d76b2,b3a66d5e,3a0bf60,39a7e59c)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 32
+#if WINDOW_G > 7
,S(9d3c2561,7a56d10b,46d9b01a,1710d193,e840e005,df669e76,1936c275,20890db9,6bbdc0bc,4c4ae9bc,c2dfee9b,82da9b94,1f89ffcd,e8af2aca,4467ce3,78521ea3)
,S(29f98e50,f51b7f8b,e18c6ae0,b453c4f2,d0aca5a8,b0e61d2d,dda8506,3fdb76c8,daf3bcdc,ae8e031c,73eb8b21,14058063,58a6ec30,ad379186,df80e3c7,f0e5d28f)
,S(d67d30c2,c71daa36,1805e31,1dd6046e,17a89752,94d76e1a,538af074,4dc22c94,48b9b0e7,12c807b0,b92e690a,a2e068cc,e87ebbbe,aaf4bd96,9c1114bb,a54f670c)
@@ -8463,7 +8314,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(6f97ac0f,27b87905,6b442d13,e566978e,91f0cc1d,d6ac1e64,e9764a35,325dd1b7,83c6e70c,fac6c707,226ce1cc,691b38a0,7e937f5a,5f2d9c81,4dd0d3ff,9f433d32)
,S(72c5d60f,eb014e2d,ba8265ca,d454f261,2d6abcd4,b2236bad,c94c4801,561dce1f,e3119a19,7ef91963,b3b28216,3c5d3acb,97b281b6,d246cbf0,690b40da,63978fe2)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 64
+#if WINDOW_G > 8
,S(a96d2da0,1b10186,6998659d,f441a1b0,2af32b94,aae8c6ea,707d9ed0,d5f33825,660d7d83,5da5235,9f7cfd41,28c370aa,5659ea71,16a91690,6c0e8108,a513f9f)
,S(2cce6f63,4d815ecc,1981d200,87616677,d906aa27,990c4875,17314dc5,5be3c4fa,615210dd,bd599e91,1b6f997a,fd05475,b33cb274,c9ecb6e5,d3c23323,beba4b50)
,S(992b0084,525dd399,d98602d9,8b8d53b2,4558fafc,758a2f46,60e89bd6,a645f0c4,83ca98d2,26545a29,8c45f40b,11420602,f5a5c70e,595eea57,2da64d61,a4e2f98d)
@@ -8529,7 +8380,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(7590a4a,627d5e90,e42a4b0f,6be6497a,f906182d,d2dddc48,a8b6bbfd,f56c0504,d611e21a,b5498760,5c97e878,baa464bc,cc5bd875,353b69f8,1f93ce2a,a6c38587)
,S(94b1da0f,b310e056,db0dff72,81db3362,1fcc555d,bf3c973b,76097908,7fe19d6a,8318893d,d5b41a56,33a2ab4,ae4b953c,45c42e9c,8f2fd159,85286de3,fd4fc217)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 128
+#if WINDOW_G > 9
,S(b5af4299,bcdacef1,e07d081,daec2cfa,d6f8f821,38e151a5,f20e6d52,84c9a6cb,c0984407,8a7db82d,f572987e,b137dc09,c8cf65fd,aedcb20,43b2479b,ab95448d)
,S(5f49ad43,70744587,3980a153,c851829b,f8ef6141,9889bb0c,3c476847,6939c3e3,5c40d385,20f56c3d,ba08ae1,b40fc24a,2ae25c94,45cae0f7,d01d1800,747e04eb)
,S(f6bb067f,88ccc11c,64e30d1a,e6893942,16bea3bf,26ec9c64,5cde1b9e,487da385,315a476d,7268978c,d89d4ec8,adde4a83,28dbfdd9,f2bf44fe,ad4ed721,78288f55)
@@ -8659,7 +8510,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(8ac79852,75673818,69fe93c9,6141493e,72ca344,790487b,d5425ed6,9f5c5c18,bb314248,fcbfc867,d1972e04,b9ef1f90,775375f9,9d25bcec,684c72c9,bdd1c08e)
,S(560e9711,88cbc7ce,c61f3bf4,45f0ade3,6f3f174d,219a160,5f9c8692,3f848b9d,9e92dace,6775cc67,bfbbf21f,c64e6e9d,4d133f8a,c18ee277,bc80ef6d,d1b9cd2f)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 256
+#if WINDOW_G > 10
,S(8c464204,4b95eb66,cc95ca08,8469a1c0,28eea52f,7f709fe,e6d90700,f5fb943a,bf10fc5d,7bc25181,301b3a61,5ebea597,a3492025,953c3aa5,1a11271e,689d0223)
,S(d293f74c,f3578b71,35377247,cd8b0367,7f2245da,f87453cb,4d8d1cc2,871eb5aa,86c2013a,61dfea14,63e45931,eb09050f,f080e3d4,ae357423,ba7afbed,a64a6f26)
,S(35997241,ae757b1f,c767611e,c76eb935,fefbf7a7,33666aff,4c6bd744,d7687d35,bcbea61f,246bcd4c,c3c7fd35,7bd393da,2f36e0ef,cca0df9c,5994f96f,c44b2aa0)
@@ -8917,7 +8768,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(6ca7e032,8bf5d67a,b804d431,e5f709e,bd3156e0,1d4511da,1dc67394,24d2e659,c428b133,f3683909,6551c2ff,2f870d80,d80aaaf4,6d2b1a69,7722057,5eca2647)
,S(60df19a9,83e9086c,4cbd20ba,fbafa8b2,346ae4ee,9c1ad4dd,99959e91,2df530d3,dae7b854,29f817a0,421c2f1e,e4e8e4d,a09d60f8,84701e31,d7a8b7b0,3b79cc48)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 512
+#if WINDOW_G > 11
,S(6f18d50e,5ef5f2ad,bad80ea1,c59a3847,5c22ff05,6ba52c7,e1d26d6d,d3686bce,d1d7ea0f,a166efd0,facf5c83,bc3786e0,d3f3405d,5b4578f5,13a336ad,f0d7d7a9)
,S(b634dc9d,5ed51336,4ac9569a,8ddee9d9,fcdfe00e,65e59233,b3be8a07,2fd949e0,d72e46e2,c61b2575,f25a505c,bdc3456e,fdf18976,6562a1a7,e86d036,eb31db69)
,S(5a37fcf0,2dba24f3,e6646171,43dbc5ab,40d91983,69f5cf0e,4fc566fd,97445910,a960d1d8,13f8746c,662a9582,614c7847,33e6153d,2975cb59,c3342463,75c69d1e)
@@ -9431,7 +9282,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(edc9e8b1,3c61a1e0,8f93be12,495084ed,b5a90eca,4f11dc03,cd217b1a,56285a2c,66c2fd21,7e8fac7,4fd43b1b,58c80661,b0e8df85,a2fddfda,5e9f99fe,621e1f3d)
,S(dd94295f,8388a498,2aaa4164,927b81ba,cae9d002,b3ddb6b6,97082c70,f1e2c66e,838c060c,d409c1ea,9bcd9e8c,b1fac83f,3b08c2b2,482d8f4b,fd3ebc18,8d6706b)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 1024
+#if WINDOW_G > 12
,S(7e068e04,dfc0be48,e5c0d3b3,5bfc734e,96e96ddd,d0ac4876,92f74535,685ab7e,df2cd146,90d225c8,d04052e6,93f14bf,69351e08,79883646,2c88401e,4ec70d0a)
,S(73a9bfcf,d10aac9b,46e659f,76c439a0,b7c2a073,7dec217a,21f43f39,949a5052,73b91529,3ea7b052,682062c,8f86cbf,bf379df6,91a9cec2,4a1424a9,b3be10dd)
,S(efddff84,c8cc754,e6e34678,d85809bc,55cc224b,f69be05a,daa847ec,d408c55b,65dd8f41,8264aab2,efe6ed7e,c45b4ac,8aac218a,3b6713fc,1736dd6d,c2f188d5)
@@ -10457,7 +10308,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(8a663e7,40cad237,12dad6f9,1bb5d266,30542933,853e02eb,665e198d,a5c6e53b,e206b399,51175d15,daccf711,63b0918c,786a8fe,2077812,c0c1eee6,bb5c1e99)
,S(2b0956cb,e0ca91ee,f44fac0a,76cc0b00,5f4a5ae8,27e63696,fe1aa8b4,a92941a1,a31e6fa8,dd454eaf,90ee1e11,62627e3,3f84b8fe,da29f423,ddf2a962,386cffd2)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 2048
+#if WINDOW_G > 13
,S(e0144151,7a2ac970,eb6381df,7e11fb4c,6b009980,6a0d330,d5429126,e662c3bd,8238ce9b,a691c80c,21563934,18d18dbf,aeb3fd34,48863a1e,7f4ba360,408dfcee)
,S(be3213e,8b062f33,caf16c53,5a0b666,f344e0d7,1e28aeba,8b215a3,7ec86c37,552523ba,eaca38a4,cd795683,852a2643,550fb83d,d1db0adc,3f1b29c9,7d51cd1f)
,S(623393b6,bfbfbd64,fc7aa1db,9e58e274,1c18eb6d,b5eb30ab,c4fe167e,a9e8ff2b,7c0e4174,f0fd5bf2,a025e316,fa3b7b97,1339a197,b52b0b50,bad4dfe,34e42cd3)
@@ -12507,7 +12358,7 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(4beaa213,3c6161d0,c7da6d7c,8eb09cba,2e8ca505,a790a7d3,9d0c16b,8053bb52,da4c083c,9cbdda2e,c6626d8f,e4b2ee13,703496c,c298bffa,db1acdca,99d4f6d5)
,S(a8d31ec6,53ce1834,a78de363,c5f9abd1,8594b34,4d34f5fc,8a10e81f,5804831,b4d6a9cd,7cbbe370,9edb5601,cb7c8ba4,8c462c18,594a4bce,64f4c286,dac5cff9)
#endif
-#if ECMULT_TABLE_SIZE(WINDOW_G) > 4096
+#if WINDOW_G > 14
,S(a8f11586,f3df4945,a753c485,ee0fd4d,e410771d,bddc1b26,c9ff10e0,77b915b7,a4ad6f16,dbd741bc,71b2dfd2,dd2d340,3816bf73,4e73cc10,abcfa6bb,d0f161a4)
,S(13e697c3,812d4772,254082da,372892d4,e1a66e1a,eb16bbd4,f7a0d531,c979cb2,87fa7baa,f6def12d,31e42c14,f672c0d6,a9d0e2e1,ceee2546,d65bd01,c18df57f)
,S(3cae4590,821a9697,a5963269,b44f0222,98f60021,b6048b3f,49c6fd4d,8650c7a,e03f8745,60418449,ad97f28,41664745,349329d,268c1c43,86e25147,6e44b234)
@@ -16606,6 +16457,4 @@ static const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G
,S(1b9a142f,fc4d03ea,4b079f2d,b05fad98,8ddb2d32,b359967f,c173801f,63320825,59bda7ed,5b691c20,4fc8f8ac,f53be298,ae628954,a8134d0f,dd097e67,be9ff9b6)
#endif
};
-#endif
#undef S
-#endif
diff --git a/src/secp256k1/src/precomputed_ecmult.h b/src/secp256k1/src/precomputed_ecmult.h
new file mode 100644
index 0000000000..949b62c874
--- /dev/null
+++ b/src/secp256k1/src/precomputed_ecmult.h
@@ -0,0 +1,35 @@
+/*****************************************************************************************************
+ * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
+ *****************************************************************************************************/
+
+#ifndef SECP256K1_PRECOMPUTED_ECMULT_H
+#define SECP256K1_PRECOMPUTED_ECMULT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "group.h"
+#if defined(EXHAUSTIVE_TEST_ORDER)
+#if EXHAUSTIVE_TEST_ORDER == 13
+# define WINDOW_G 4
+# elif EXHAUSTIVE_TEST_ORDER == 199
+# define WINDOW_G 8
+# else
+# error No known generator for the specified exhaustive test group order.
+# endif
+static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)];
+static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)];
+#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
+# define WINDOW_G ECMULT_WINDOW_SIZE
+extern const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)];
+extern const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)];
+#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_PRECOMPUTED_ECMULT_H */
diff --git a/src/secp256k1/src/ecmult_gen_static_prec_table.h b/src/secp256k1/src/precomputed_ecmult_gen.c
index bf4e5ea248..d67291fcf5 100644
--- a/src/secp256k1/src/ecmult_gen_static_prec_table.h
+++ b/src/secp256k1/src/precomputed_ecmult_gen.c
@@ -1,13 +1,17 @@
-/* This file was automatically generated by gen_ecmult_gen_static_prec_table. */
+/* This file was automatically generated by precompute_ecmult_gen. */
/* See ecmult_gen_impl.h for details about the contents of this file. */
-#ifndef SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H
-#define SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H
+#if defined HAVE_CONFIG_H
+# include "libsecp256k1-config.h"
+#endif
+#include "../include/secp256k1.h"
#include "group.h"
-#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)
+#include "ecmult_gen.h"
+#include "precomputed_ecmult_gen.h"
#ifdef EXHAUSTIVE_TEST_ORDER
-static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)];
-#else
-static const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = {
+# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode
+#endif /* EXHAUSTIVE_TEST_ORDER */
+#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)
+const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = {
#if ECMULT_GEN_PREC_BITS == 2
{S(3a9ed373,6eed3eec,9aeb5ac0,21b54652,56817b1f,8de6cd0,fbcee548,ba044bb5,7bcc5928,bdc9c023,dfc663b8,9e4f6969,ab751798,8e600ec1,d242010c,45c7974a),
S(e44d7675,c3cb2857,4e133c01,a74f4afc,5ce684f8,4a789711,603f7c4f,50abef58,25bcb62f,fe2e2ce2,196ad86c,a006e20,8c64d21b,b25320a3,b5574b9c,1e1bfb4b),
@@ -9743,6 +9747,4 @@ S(244b87a4,fcecef37,76c16c5c,24c7785,be3b3c13,46595363,b8c066ec,45bfe561,9642f5f
S(9de52b81,157165cc,aef44485,4c2b3535,a599a79,80d024de,5334b385,ecbb2e91,74fca165,26fe2f87,a41ce510,4dd5634,5cf98c11,803c0392,3eb4b8b7,60240c02)}
#endif
};
-#endif /* EXHAUSTIVE_TEST_ORDER */
-#undef SC
-#endif /* SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H */
+#undef S
diff --git a/src/secp256k1/src/precomputed_ecmult_gen.h b/src/secp256k1/src/precomputed_ecmult_gen.h
new file mode 100644
index 0000000000..7256ad2e30
--- /dev/null
+++ b/src/secp256k1/src/precomputed_ecmult_gen.h
@@ -0,0 +1,26 @@
+/*********************************************************************************
+ * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
+ *********************************************************************************/
+
+#ifndef SECP256K1_PRECOMPUTED_ECMULT_GEN_H
+#define SECP256K1_PRECOMPUTED_ECMULT_GEN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "group.h"
+#include "ecmult_gen.h"
+#ifdef EXHAUSTIVE_TEST_ORDER
+static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)];
+#else
+extern const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)];
+#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_PRECOMPUTED_ECMULT_GEN_H */
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 36fde24c3d..8f34c35283 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -423,8 +423,12 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
unsigned int offset = 0;
secp256k1_rfc6979_hmac_sha256 rng;
unsigned int i;
+ secp256k1_scalar msg;
+ unsigned char msgmod32[32];
+ secp256k1_scalar_set_b32(&msg, msg32, NULL);
+ secp256k1_scalar_get_b32(msgmod32, &msg);
/* We feed a byte array to the PRNG as input, consisting of:
- * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
+ * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d.
* - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
* - optionally 16 extra bytes with the algorithm name.
* Because the arguments have distinct fixed lengths it is not possible for
@@ -432,7 +436,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
* nonces.
*/
buffer_append(keydata, &offset, key32, 32);
- buffer_append(keydata, &offset, msg32, 32);
+ buffer_append(keydata, &offset, msgmod32, 32);
if (data != NULL) {
buffer_append(keydata, &offset, data, 32);
}
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index 667d1867bd..bd149bb1b4 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -17,11 +17,14 @@
SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16);
/** Generate a pseudorandom number in the range [0..2**32-1]. */
-static uint32_t secp256k1_testrand32(void);
+SECP256K1_INLINE static uint32_t secp256k1_testrand32(void);
+
+/** Generate a pseudorandom number in the range [0..2**64-1]. */
+SECP256K1_INLINE static uint64_t secp256k1_testrand64(void);
/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or
* more. */
-static uint32_t secp256k1_testrand_bits(int bits);
+SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits);
/** Generate a pseudorandom number in the range [0..range-1]. */
static uint32_t secp256k1_testrand_int(uint32_t range);
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index c8d30ef6a8..e9b9d7ded4 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -14,37 +14,64 @@
#include "testrand.h"
#include "hash.h"
-static secp256k1_rfc6979_hmac_sha256 secp256k1_test_rng;
-static uint32_t secp256k1_test_rng_precomputed[8];
-static int secp256k1_test_rng_precomputed_used = 8;
+static uint64_t secp256k1_test_state[4];
static uint64_t secp256k1_test_rng_integer;
static int secp256k1_test_rng_integer_bits_left = 0;
SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) {
- secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16);
+ static const unsigned char PREFIX[19] = "secp256k1 test init";
+ unsigned char out32[32];
+ secp256k1_sha256 hash;
+ int i;
+
+ /* Use SHA256(PREFIX || seed16) as initial state. */
+ secp256k1_sha256_initialize(&hash);
+ secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX));
+ secp256k1_sha256_write(&hash, seed16, 16);
+ secp256k1_sha256_finalize(&hash, out32);
+ for (i = 0; i < 4; ++i) {
+ uint64_t s = 0;
+ int j;
+ for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j];
+ secp256k1_test_state[i] = s;
+ }
+ secp256k1_test_rng_integer_bits_left = 0;
}
-SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) {
- if (secp256k1_test_rng_precomputed_used == 8) {
- secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed));
- secp256k1_test_rng_precomputed_used = 0;
- }
- return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++];
+SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) {
+ return (x << k) | (x >> (64 - k));
+}
+
+SECP256K1_INLINE static uint64_t secp256k1_testrand64(void) {
+ /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */
+ const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0];
+ const uint64_t t = secp256k1_test_state[1] << 17;
+ secp256k1_test_state[2] ^= secp256k1_test_state[0];
+ secp256k1_test_state[3] ^= secp256k1_test_state[1];
+ secp256k1_test_state[1] ^= secp256k1_test_state[2];
+ secp256k1_test_state[0] ^= secp256k1_test_state[3];
+ secp256k1_test_state[2] ^= t;
+ secp256k1_test_state[3] = rotl(secp256k1_test_state[3], 45);
+ return result;
}
-static uint32_t secp256k1_testrand_bits(int bits) {
- uint32_t ret;
+SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits) {
+ uint64_t ret;
if (secp256k1_test_rng_integer_bits_left < bits) {
- secp256k1_test_rng_integer |= (((uint64_t)secp256k1_testrand32()) << secp256k1_test_rng_integer_bits_left);
- secp256k1_test_rng_integer_bits_left += 32;
+ secp256k1_test_rng_integer = secp256k1_testrand64();
+ secp256k1_test_rng_integer_bits_left = 64;
}
ret = secp256k1_test_rng_integer;
secp256k1_test_rng_integer >>= bits;
secp256k1_test_rng_integer_bits_left -= bits;
- ret &= ((~((uint32_t)0)) >> (32 - bits));
+ ret &= ((~((uint64_t)0)) >> (64 - bits));
return ret;
}
+SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) {
+ return secp256k1_testrand_bits(32);
+}
+
static uint32_t secp256k1_testrand_int(uint32_t range) {
/* We want a uniform integer between 0 and range-1, inclusive.
* B is the smallest number such that range <= 2**B.
@@ -85,7 +112,19 @@ static uint32_t secp256k1_testrand_int(uint32_t range) {
}
static void secp256k1_testrand256(unsigned char *b32) {
- secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32);
+ int i;
+ for (i = 0; i < 4; ++i) {
+ uint64_t val = secp256k1_testrand64();
+ b32[0] = val;
+ b32[1] = val >> 8;
+ b32[2] = val >> 16;
+ b32[3] = val >> 24;
+ b32[4] = val >> 32;
+ b32[5] = val >> 40;
+ b32[6] = val >> 48;
+ b32[7] = val >> 56;
+ b32 += 8;
+ }
}
static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len) {
@@ -109,7 +148,7 @@ static void secp256k1_testrand256_test(unsigned char *b32) {
}
static void secp256k1_testrand_flip(unsigned char *b, size_t len) {
- b[secp256k1_testrand_int(len)] ^= (1 << secp256k1_testrand_int(8));
+ b[secp256k1_testrand_int(len)] ^= (1 << secp256k1_testrand_bits(3));
}
static void secp256k1_testrand_init(const char* hexseed) {
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 712fc655fa..dd53173930 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -28,6 +28,8 @@
#include "modinv64_impl.h"
#endif
+#define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
+
static int count = 64;
static secp256k1_context *ctx = NULL;
@@ -100,6 +102,12 @@ void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *
gej->infinity = ge->infinity;
}
+void random_gej_test(secp256k1_gej *gej) {
+ secp256k1_ge ge;
+ random_group_element_test(&ge);
+ random_group_element_jacobian_test(gej, &ge);
+}
+
void random_scalar_order_test(secp256k1_scalar *num) {
do {
unsigned char b32[32];
@@ -443,14 +451,18 @@ void run_ctz_tests(void) {
/***** HASH TESTS *****/
-void run_sha256_tests(void) {
- static const char *inputs[8] = {
+void run_sha256_known_output_tests(void) {
+ static const char *inputs[] = {
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"For this sample, this 63-byte string will be used as input data",
- "This is exactly 64 bytes long, not counting the terminating byte"
+ "This is exactly 64 bytes long, not counting the terminating byte",
+ "aaaaa",
};
- static const unsigned char outputs[8][32] = {
+ static const unsigned int repeat[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1000000/5
+ };
+ static const unsigned char outputs[][32] = {
{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55},
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50},
@@ -458,27 +470,146 @@ void run_sha256_tests(void) {
{0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30},
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},
- {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}
+ {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8},
+ {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0},
};
- int i;
- for (i = 0; i < 8; i++) {
+ unsigned int i, ninputs;
+
+ /* Skip last input vector for low iteration counts */
+ ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1;
+ CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++;
+
+ for (i = 0; i < ninputs; i++) {
unsigned char out[32];
secp256k1_sha256 hasher;
+ unsigned int j;
+ /* 1. Run: simply write the input bytestrings */
+ j = repeat[i];
secp256k1_sha256_initialize(&hasher);
- secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
+ while (j > 0) {
+ secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
+ j--;
+ }
secp256k1_sha256_finalize(&hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
+ /* 2. Run: split the input bytestrings randomly before writing */
if (strlen(inputs[i]) > 0) {
int split = secp256k1_testrand_int(strlen(inputs[i]));
secp256k1_sha256_initialize(&hasher);
- secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
- secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
+ j = repeat[i];
+ while (j > 0) {
+ secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
+ secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
+ j--;
+ }
secp256k1_sha256_finalize(&hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
}
}
}
+/** SHA256 counter tests
+
+The tests verify that the SHA256 counter doesn't wrap around at message length
+2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the
+implementation of the counter and it catches multiple natural 32-bit overflows
+(e.g., counting bits, counting bytes, counting blocks, ...).
+
+The test vectors have been generated using following Python script which relies
+on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2).
+
+```
+from sha256 import sha256
+from copy import copy
+
+def midstate_c_definition(hasher):
+ ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n'
+ ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}'
+ return ret
+
+def output_c_literal(hasher):
+ return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}'
+
+MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno'
+assert(len(MESSAGE) == 64)
+BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)]
+
+midstates = []
+digests = []
+hasher = sha256()
+for i in range(BYTE_BOUNDARIES[-1] + 1):
+ if i in BYTE_BOUNDARIES:
+ midstates.append(midstate_c_definition(hasher))
+ hasher_copy = copy(hasher)
+ hasher_copy.update(MESSAGE)
+ digests.append(output_c_literal(hasher_copy))
+ hasher.update(MESSAGE)
+
+for x in midstates:
+ print(x + ',')
+
+for x in digests:
+ print(x + ',')
+```
+*/
+void run_sha256_counter_tests(void) {
+ static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno";
+ static const secp256k1_sha256 midstates[] = {
+ {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda},
+ {0x00}, 0xfffc0},
+ {{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26},
+ {0x00}, 0x1fffc0},
+ {{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1},
+ {0x00}, 0x3fffc0},
+ {{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6},
+ {0x00}, 0x7fffc0},
+ {{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c},
+ {0x00}, 0xffffc0},
+ {{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2},
+ {0x00}, 0x1ffffc0},
+ {{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c},
+ {0x00}, 0x3ffffc0},
+ {{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0},
+ {0x00}, 0x7ffffc0},
+ {{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad},
+ {0x00}, 0xfffffc0},
+ {{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023},
+ {0x00}, 0x1fffffc0},
+ {{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1},
+ {0x00}, 0x3fffffc0},
+ {{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec},
+ {0x00}, 0x7fffffc0},
+ {{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162},
+ {0x00}, 0xffffffc0},
+ {{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a},
+ {0x00}, 0x1ffffffc0},
+ };
+ static const unsigned char outputs[][32] = {
+ {0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15},
+ {0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb},
+ {0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e},
+ {0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9},
+ {0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7},
+ {0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07},
+ {0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76},
+ {0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0},
+ {0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8},
+ {0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6},
+ {0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e},
+ {0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b},
+ {0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34},
+ {0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e},
+ };
+ unsigned int i;
+ for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) {
+ unsigned char out[32];
+ secp256k1_sha256 hasher = midstates[i];
+ secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input));
+ secp256k1_sha256_finalize(&hasher, out);
+ CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
+ }
+}
+
void run_hmac_sha256_tests(void) {
static const char *keys[6] = {
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
@@ -790,7 +921,7 @@ void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) {
void mutate_sign_signed30(secp256k1_modinv32_signed30* x) {
int i;
for (i = 0; i < 16; ++i) {
- int pos = secp256k1_testrand_int(8);
+ int pos = secp256k1_testrand_bits(3);
if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) {
x->v[pos] -= 0x40000000;
x->v[pos + 1] += 1;
@@ -862,7 +993,7 @@ void mutate_sign_signed62(secp256k1_modinv64_signed62* x) {
static const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int i;
for (i = 0; i < 8; ++i) {
- int pos = secp256k1_testrand_int(4);
+ int pos = secp256k1_testrand_bits(2);
if (x->v[pos] > 0 && x->v[pos + 1] <= M62) {
x->v[pos] -= (M62 + 1);
x->v[pos + 1] += 1;
@@ -2451,13 +2582,65 @@ void run_field_convert(void) {
CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0);
}
-int fe_secp256k1_memcmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
- secp256k1_fe t = *b;
+/* Returns true if two field elements have the same representation. */
+int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
+ int ret = 1;
#ifdef VERIFY
- t.magnitude = a->magnitude;
- t.normalized = a->normalized;
+ ret &= (a->magnitude == b->magnitude);
+ ret &= (a->normalized == b->normalized);
#endif
- return secp256k1_memcmp_var(a, &t, sizeof(secp256k1_fe));
+ /* Compare the struct member that holds the limbs. */
+ ret &= (secp256k1_memcmp_var(a->n, b->n, sizeof(a->n)) == 0);
+ return ret;
+}
+
+void run_field_half(void) {
+ secp256k1_fe t, u;
+ int m;
+
+ /* Check magnitude 0 input */
+ secp256k1_fe_get_bounds(&t, 0);
+ secp256k1_fe_half(&t);
+#ifdef VERIFY
+ CHECK(t.magnitude == 1);
+ CHECK(t.normalized == 0);
+#endif
+ CHECK(secp256k1_fe_normalizes_to_zero(&t));
+
+ /* Check non-zero magnitudes in the supported range */
+ for (m = 1; m < 32; m++) {
+ /* Check max-value input */
+ secp256k1_fe_get_bounds(&t, m);
+
+ u = t;
+ secp256k1_fe_half(&u);
+#ifdef VERIFY
+ CHECK(u.magnitude == (m >> 1) + 1);
+ CHECK(u.normalized == 0);
+#endif
+ secp256k1_fe_normalize_weak(&u);
+ secp256k1_fe_add(&u, &u);
+ CHECK(check_fe_equal(&t, &u));
+
+ /* Check worst-case input: ensure the LSB is 1 so that P will be added,
+ * which will also cause all carries to be 1, since all limbs that can
+ * generate a carry are initially even and all limbs of P are odd in
+ * every existing field implementation. */
+ secp256k1_fe_get_bounds(&t, m);
+ CHECK(t.n[0] > 0);
+ CHECK((t.n[0] & 1) == 0);
+ --t.n[0];
+
+ u = t;
+ secp256k1_fe_half(&u);
+#ifdef VERIFY
+ CHECK(u.magnitude == (m >> 1) + 1);
+ CHECK(u.normalized == 0);
+#endif
+ secp256k1_fe_normalize_weak(&u);
+ secp256k1_fe_add(&u, &u);
+ CHECK(check_fe_equal(&t, &u));
+ }
}
void run_field_misc(void) {
@@ -2467,9 +2650,13 @@ void run_field_misc(void) {
secp256k1_fe q;
secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
int i, j;
- for (i = 0; i < 5*count; i++) {
+ for (i = 0; i < 1000 * count; i++) {
secp256k1_fe_storage xs, ys, zs;
- random_fe(&x);
+ if (i & 1) {
+ random_fe(&x);
+ } else {
+ random_fe_test(&x);
+ }
random_fe_non_zero(&y);
/* Test the fe equality and comparison operations. */
CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);
@@ -2483,13 +2670,13 @@ void run_field_misc(void) {
CHECK(x.normalized && x.magnitude == 1);
#endif
secp256k1_fe_cmov(&x, &x, 1);
- CHECK(fe_secp256k1_memcmp_var(&x, &z) != 0);
- CHECK(fe_secp256k1_memcmp_var(&x, &q) == 0);
+ CHECK(!fe_identical(&x, &z));
+ CHECK(fe_identical(&x, &q));
secp256k1_fe_cmov(&q, &z, 1);
#ifdef VERIFY
CHECK(!q.normalized && q.magnitude == z.magnitude);
#endif
- CHECK(fe_secp256k1_memcmp_var(&q, &z) == 0);
+ CHECK(fe_identical(&q, &z));
secp256k1_fe_normalize_var(&x);
secp256k1_fe_normalize_var(&z);
CHECK(!secp256k1_fe_equal_var(&x, &z));
@@ -2537,6 +2724,14 @@ void run_field_misc(void) {
secp256k1_fe_add(&q, &x);
CHECK(check_fe_equal(&y, &z));
CHECK(check_fe_equal(&q, &y));
+ /* Check secp256k1_fe_half. */
+ z = x;
+ secp256k1_fe_half(&z);
+ secp256k1_fe_add(&z, &z);
+ CHECK(check_fe_equal(&x, &z));
+ secp256k1_fe_add(&z, &z);
+ secp256k1_fe_half(&z);
+ CHECK(check_fe_equal(&x, &z));
}
}
@@ -3338,6 +3533,37 @@ void run_ge(void) {
test_intialized_inf();
}
+void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {
+ secp256k1_gej t = *a;
+ secp256k1_gej_cmov(&t, b, 0);
+ CHECK(gej_xyz_equals_gej(&t, a));
+ secp256k1_gej_cmov(&t, b, 1);
+ CHECK(gej_xyz_equals_gej(&t, b));
+}
+
+void run_gej(void) {
+ int i;
+ secp256k1_gej a, b;
+
+ /* Tests for secp256k1_gej_cmov */
+ for (i = 0; i < count; i++) {
+ secp256k1_gej_set_infinity(&a);
+ secp256k1_gej_set_infinity(&b);
+ test_gej_cmov(&a, &b);
+
+ random_gej_test(&a);
+ test_gej_cmov(&a, &b);
+ test_gej_cmov(&b, &a);
+
+ b = a;
+ test_gej_cmov(&a, &b);
+
+ random_gej_test(&b);
+ test_gej_cmov(&a, &b);
+ test_gej_cmov(&b, &a);
+ }
+}
+
void test_ec_combine(void) {
secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
secp256k1_pubkey data[6];
@@ -4052,6 +4278,174 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
}
+int test_ecmult_multi_random(secp256k1_scratch *scratch) {
+ /* Large random test for ecmult_multi_* functions which exercises:
+ * - Few or many inputs (0 up to 128, roughly exponentially distributed).
+ * - Few or many 0*P or a*INF inputs (roughly uniformly distributed).
+ * - Including or excluding an nonzero a*G term (or such a term at all).
+ * - Final expected result equal to infinity or not (roughly 50%).
+ * - ecmult_multi_var, ecmult_strauss_single_batch, ecmult_pippenger_single_batch
+ */
+
+ /* These 4 variables define the eventual input to the ecmult_multi function.
+ * g_scalar is the G scalar fed to it (or NULL, possibly, if g_scalar=0), and
+ * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points
+ * which form its normal inputs. */
+ int filled = 0;
+ secp256k1_scalar g_scalar = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ secp256k1_scalar scalars[128];
+ secp256k1_gej gejs[128];
+ /* The expected result, and the computed result. */
+ secp256k1_gej expected, computed;
+ /* Temporaries. */
+ secp256k1_scalar sc_tmp;
+ secp256k1_ge ge_tmp;
+ /* Variables needed for the actual input to ecmult_multi. */
+ secp256k1_ge ges[128];
+ ecmult_multi_data data;
+
+ int i;
+ /* Which multiplication function to use */
+ int fn = secp256k1_testrand_int(3);
+ secp256k1_ecmult_multi_func ecmult_multi = fn == 0 ? secp256k1_ecmult_multi_var :
+ fn == 1 ? secp256k1_ecmult_strauss_batch_single :
+ secp256k1_ecmult_pippenger_batch_single;
+ /* Simulate exponentially distributed num. */
+ int num_bits = 2 + secp256k1_testrand_int(6);
+ /* Number of (scalar, point) inputs (excluding g). */
+ int num = secp256k1_testrand_int((1 << num_bits) + 1);
+ /* Number of those which are nonzero. */
+ int num_nonzero = secp256k1_testrand_int(num + 1);
+ /* Whether we're aiming to create an input with nonzero expected result. */
+ int nonzero_result = secp256k1_testrand_bits(1);
+ /* Whether we will provide nonzero g multiplicand. In some cases our hand
+ * is forced here based on num_nonzero and nonzero_result. */
+ int g_nonzero = num_nonzero == 0 ? nonzero_result :
+ num_nonzero == 1 && !nonzero_result ? 1 :
+ (int)secp256k1_testrand_bits(1);
+ /* Which g_scalar pointer to pass into ecmult_multi(). */
+ const secp256k1_scalar* g_scalar_ptr = (g_nonzero || secp256k1_testrand_bits(1)) ? &g_scalar : NULL;
+ /* How many EC multiplications were performed in this function. */
+ int mults = 0;
+ /* How many randomization steps to apply to the input list. */
+ int rands = (int)secp256k1_testrand_bits(3);
+ if (rands > num_nonzero) rands = num_nonzero;
+
+ secp256k1_gej_set_infinity(&expected);
+ secp256k1_gej_set_infinity(&gejs[0]);
+ secp256k1_scalar_set_int(&scalars[0], 0);
+
+ if (g_nonzero) {
+ /* If g_nonzero, set g_scalar to nonzero value r. */
+ random_scalar_order_test(&g_scalar);
+ if (!nonzero_result) {
+ /* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */
+ CHECK(num_nonzero > filled);
+ random_scalar_order_test(&sc_tmp);
+ secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar);
+ secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp);
+ secp256k1_scalar_negate(&sc_tmp, &sc_tmp);
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &gejs[filled], &sc_tmp);
+ ++filled;
+ ++mults;
+ }
+ }
+
+ if (nonzero_result && filled < num_nonzero) {
+ /* If a nonzero result is desired, and there is space, add a random nonzero term. */
+ random_scalar_order_test(&scalars[filled]);
+ random_group_element_test(&ge_tmp);
+ secp256k1_gej_set_ge(&gejs[filled], &ge_tmp);
+ ++filled;
+ }
+
+ if (nonzero_result) {
+ /* Compute the expected result using normal ecmult. */
+ CHECK(filled <= 1);
+ secp256k1_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar);
+ mults += filled + g_nonzero;
+ }
+
+ /* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */
+ CHECK(filled <= 1 + !nonzero_result);
+ CHECK(filled <= num_nonzero);
+
+ /* Add entries to scalars,gejs so that there are num of them. All the added entries
+ * either have scalar=0 or point=infinity, so these do not change the expected result. */
+ while (filled < num) {
+ if (secp256k1_testrand_bits(1)) {
+ secp256k1_gej_set_infinity(&gejs[filled]);
+ random_scalar_order_test(&scalars[filled]);
+ } else {
+ secp256k1_scalar_set_int(&scalars[filled], 0);
+ random_group_element_test(&ge_tmp);
+ secp256k1_gej_set_ge(&gejs[filled], &ge_tmp);
+ }
+ ++filled;
+ }
+
+ /* Now perform cheapish transformations on gejs and scalars, for indices
+ * 0..num_nonzero-1, which do not change the expected result, but may
+ * convert some of them to be both non-0-scalar and non-infinity-point. */
+ for (i = 0; i < rands; ++i) {
+ int j;
+ secp256k1_scalar v, iv;
+ /* Shuffle the entries. */
+ for (j = 0; j < num_nonzero; ++j) {
+ int k = secp256k1_testrand_int(num_nonzero - j);
+ if (k != 0) {
+ secp256k1_gej gej = gejs[j];
+ secp256k1_scalar sc = scalars[j];
+ gejs[j] = gejs[j + k];
+ scalars[j] = scalars[j + k];
+ gejs[j + k] = gej;
+ scalars[j + k] = sc;
+ }
+ }
+ /* Perturb all consecutive pairs of inputs:
+ * a*P + b*Q -> (a+b)*P + b*(Q-P). */
+ for (j = 0; j + 1 < num_nonzero; j += 2) {
+ secp256k1_gej gej;
+ secp256k1_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]);
+ secp256k1_gej_neg(&gej, &gejs[j]);
+ secp256k1_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL);
+ }
+ /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */
+ CHECK(num_nonzero >= 1);
+ random_scalar_order_test(&v);
+ secp256k1_scalar_inverse(&iv, &v);
+ secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v);
+ secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL);
+ ++mults;
+ }
+
+ /* Shuffle all entries (0..num-1). */
+ for (i = 0; i < num; ++i) {
+ int j = secp256k1_testrand_int(num - i);
+ if (j != 0) {
+ secp256k1_gej gej = gejs[i];
+ secp256k1_scalar sc = scalars[i];
+ gejs[i] = gejs[i + j];
+ scalars[i] = scalars[i + j];
+ gejs[i + j] = gej;
+ scalars[i + j] = sc;
+ }
+ }
+
+ /* Compute affine versions of all inputs. */
+ secp256k1_ge_set_all_gej_var(ges, gejs, filled);
+ /* Invoke ecmult_multi code. */
+ data.sc = scalars;
+ data.pt = ges;
+ CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled));
+ mults += num_nonzero + g_nonzero;
+ /* Compare with expected result. */
+ secp256k1_gej_neg(&computed, &computed);
+ secp256k1_gej_add_var(&computed, &computed, &expected, NULL);
+ CHECK(secp256k1_gej_is_infinity(&computed));
+ return mults;
+}
+
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
secp256k1_scalar szero;
secp256k1_scalar sc;
@@ -4093,7 +4487,7 @@ void test_secp256k1_pippenger_bucket_window_inv(void) {
* for a given scratch space.
*/
void test_ecmult_multi_pippenger_max_points(void) {
- size_t scratch_size = secp256k1_testrand_int(256);
+ size_t scratch_size = secp256k1_testrand_bits(8);
size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12);
secp256k1_scratch *scratch;
size_t n_points_supported;
@@ -4242,6 +4636,7 @@ void test_ecmult_multi_batching(void) {
void run_ecmult_multi_tests(void) {
secp256k1_scratch *scratch;
+ int64_t todo = (int64_t)320 * count;
test_secp256k1_pippenger_bucket_window_inv();
test_ecmult_multi_pippenger_max_points();
@@ -4252,6 +4647,9 @@ void run_ecmult_multi_tests(void) {
test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single);
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
+ while (todo > 0) {
+ todo -= test_ecmult_multi_random(scratch);
+ }
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
/* Run test_ecmult_multi with space for exactly one point */
@@ -4347,7 +4745,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar_add(&x, &x, &t);
}
/* Skew num because when encoding numbers as odd we use an offset */
- secp256k1_scalar_set_int(&scalar_skew, 1 << (skew == 2));
+ secp256k1_scalar_set_int(&scalar_skew, skew);
secp256k1_scalar_add(&num, &num, &scalar_skew);
CHECK(secp256k1_scalar_eq(&x, &num));
}
@@ -4540,8 +4938,8 @@ void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, se
}
}
-void test_ecmult_constants(void) {
- /* Test ecmult_gen for:
+void test_ecmult_constants_2bit(void) {
+ /* Using test_ecmult_accumulate, test ecmult for:
* - For i in 0..36:
* - Key i
* - Key -i
@@ -4584,8 +4982,81 @@ void test_ecmult_constants(void) {
secp256k1_scratch_space_destroy(ctx, scratch);
}
+void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) {
+ /* Using test_ecmult_accumulate, test ecmult for:
+ * - Key 0
+ * - Key 1
+ * - Key -1
+ * - For i in range(iter):
+ * - Key SHA256(LE32(prefix) || LE16(i))
+ */
+ secp256k1_scalar x;
+ secp256k1_sha256 acc;
+ unsigned char b32[32];
+ unsigned char inp[6];
+ size_t i;
+ secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 65536);
+
+ inp[0] = prefix & 0xFF;
+ inp[1] = (prefix >> 8) & 0xFF;
+ inp[2] = (prefix >> 16) & 0xFF;
+ inp[3] = (prefix >> 24) & 0xFF;
+ secp256k1_sha256_initialize(&acc);
+ secp256k1_scalar_set_int(&x, 0);
+ test_ecmult_accumulate(&acc, &x, scratch);
+ secp256k1_scalar_set_int(&x, 1);
+ test_ecmult_accumulate(&acc, &x, scratch);
+ secp256k1_scalar_negate(&x, &x);
+ test_ecmult_accumulate(&acc, &x, scratch);
+
+ for (i = 0; i < iter; ++i) {
+ secp256k1_sha256 gen;
+ inp[4] = i & 0xff;
+ inp[5] = (i >> 8) & 0xff;
+ secp256k1_sha256_initialize(&gen);
+ secp256k1_sha256_write(&gen, inp, sizeof(inp));
+ secp256k1_sha256_finalize(&gen, b32);
+ secp256k1_scalar_set_b32(&x, b32, NULL);
+ test_ecmult_accumulate(&acc, &x, scratch);
+ }
+ secp256k1_sha256_finalize(&acc, b32);
+ CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
+
+ secp256k1_scratch_space_destroy(ctx, scratch);
+}
+
void run_ecmult_constants(void) {
- test_ecmult_constants();
+ /* Expected hashes of all points in the tests below. Computed using an
+ * independent implementation. */
+ static const unsigned char expected32_6bit20[32] = {
+ 0x68, 0xb6, 0xed, 0x6f, 0x28, 0xca, 0xc9, 0x7f,
+ 0x8e, 0x8b, 0xd6, 0xc0, 0x61, 0x79, 0x34, 0x6e,
+ 0x5a, 0x8f, 0x2b, 0xbc, 0x3e, 0x1f, 0xc5, 0x2e,
+ 0x2a, 0xd0, 0x45, 0x67, 0x7f, 0x95, 0x95, 0x8e
+ };
+ static const unsigned char expected32_8bit8[32] = {
+ 0x8b, 0x65, 0x8e, 0xea, 0x86, 0xae, 0x3c, 0x95,
+ 0x90, 0xb6, 0x77, 0xa4, 0x8c, 0x76, 0xd9, 0xec,
+ 0xf5, 0xab, 0x8a, 0x2f, 0xfd, 0xdb, 0x19, 0x12,
+ 0x1a, 0xee, 0xe6, 0xb7, 0x6e, 0x05, 0x3f, 0xc6
+ };
+ /* For every combination of 6 bit positions out of 256, restricted to
+ * 20-bit windows (i.e., the first and last bit position are no more than
+ * 19 bits apart), all 64 bit patterns occur in the input scalars used in
+ * this test. */
+ CONDITIONAL_TEST(1, "test_ecmult_constants_sha 1024") {
+ test_ecmult_constants_sha(4808378u, 1024, expected32_6bit20);
+ }
+
+ /* For every combination of 8 consecutive bit positions, all 256 bit
+ * patterns occur in the input scalars used in this test. */
+ CONDITIONAL_TEST(3, "test_ecmult_constants_sha 2048") {
+ test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8);
+ }
+
+ CONDITIONAL_TEST(35, "test_ecmult_constants_2bit") {
+ test_ecmult_constants_2bit();
+ }
}
void test_ecmult_gen_blind(void) {
@@ -5851,14 +6322,14 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
/* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */
nlow[n] = der ? 1 : (secp256k1_testrand_bits(3) != 0);
/* The length of the number in bytes (the first byte of which will always be nonzero) */
- nlen[n] = nlow[n] ? secp256k1_testrand_int(33) : 32 + secp256k1_testrand_int(200) * secp256k1_testrand_int(8) / 8;
+ nlen[n] = nlow[n] ? secp256k1_testrand_int(33) : 32 + secp256k1_testrand_int(200) * secp256k1_testrand_bits(3) / 8;
CHECK(nlen[n] <= 232);
/* The top bit of the number. */
nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_testrand_bits(1));
/* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */
nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_testrand_bits(7) : 1 + secp256k1_testrand_int(127));
/* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */
- nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_testrand_int(3) : secp256k1_testrand_int(300 - nlen[n]) * secp256k1_testrand_int(8) / 8);
+ nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_testrand_int(3) : secp256k1_testrand_int(300 - nlen[n]) * secp256k1_testrand_bits(3) / 8);
if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) {
*certainly_not_der = 1;
}
@@ -5867,7 +6338,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2);
if (!der) {
/* nlenlen[n] max 127 bytes */
- int add = secp256k1_testrand_int(127 - nlenlen[n]) * secp256k1_testrand_int(16) * secp256k1_testrand_int(16) / 256;
+ int add = secp256k1_testrand_int(127 - nlenlen[n]) * secp256k1_testrand_bits(4) * secp256k1_testrand_bits(4) / 256;
nlenlen[n] += add;
if (add != 0) {
*certainly_not_der = 1;
@@ -5881,7 +6352,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
CHECK(tlen <= 856);
/* The length of the garbage inside the tuple. */
- elen = (der || indet) ? 0 : secp256k1_testrand_int(980 - tlen) * secp256k1_testrand_int(8) / 8;
+ elen = (der || indet) ? 0 : secp256k1_testrand_int(980 - tlen) * secp256k1_testrand_bits(3) / 8;
if (elen != 0) {
*certainly_not_der = 1;
}
@@ -5889,7 +6360,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
CHECK(tlen <= 980);
/* The length of the garbage after the end of the tuple. */
- glen = der ? 0 : secp256k1_testrand_int(990 - tlen) * secp256k1_testrand_int(8) / 8;
+ glen = der ? 0 : secp256k1_testrand_int(990 - tlen) * secp256k1_testrand_bits(3) / 8;
if (glen != 0) {
*certainly_not_der = 1;
}
@@ -5904,7 +6375,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
} else {
int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2);
if (!der) {
- int add = secp256k1_testrand_int(127 - tlenlen) * secp256k1_testrand_int(16) * secp256k1_testrand_int(16) / 256;
+ int add = secp256k1_testrand_int(127 - tlenlen) * secp256k1_testrand_bits(4) * secp256k1_testrand_bits(4) / 256;
tlenlen += add;
if (add != 0) {
*certainly_not_der = 1;
@@ -6416,6 +6887,19 @@ void run_secp256k1_memczero_test(void) {
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
}
+void run_secp256k1_byteorder_tests(void) {
+ const uint32_t x = 0xFF03AB45;
+ const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
+ unsigned char buf[4];
+ uint32_t x_;
+
+ secp256k1_write_be32(buf, x);
+ CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
+
+ x_ = secp256k1_read_be32(buf);
+ CHECK(x == x_);
+}
+
void int_cmov_test(void) {
int r = INT_MAX;
int a = 0;
@@ -6616,7 +7100,8 @@ int main(int argc, char **argv) {
run_modinv_tests();
run_inverse_tests();
- run_sha256_tests();
+ run_sha256_known_output_tests();
+ run_sha256_counter_tests();
run_hmac_sha256_tests();
run_rfc6979_hmac_sha256_tests();
run_tagged_sha256_tests();
@@ -6625,6 +7110,7 @@ int main(int argc, char **argv) {
run_scalar_tests();
/* field tests */
+ run_field_half();
run_field_misc();
run_field_convert();
run_fe_mul();
@@ -6633,6 +7119,7 @@ int main(int argc, char **argv) {
/* group tests */
run_ge();
+ run_gej();
run_group_decompress();
/* ecmult tests */
@@ -6687,6 +7174,7 @@ int main(int argc, char **argv) {
/* util tests */
run_secp256k1_memczero_test();
+ run_secp256k1_byteorder_tests();
run_cmov_tests();
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index 6bae7a4778..6a4e2340f2 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -22,7 +22,8 @@
#include "assumptions.h"
#include "group.h"
#include "testrand_impl.h"
-#include "ecmult_gen_prec_impl.h"
+#include "ecmult_compute_table_impl.h"
+#include "ecmult_gen_compute_table_impl.h"
static int count = 2;
@@ -389,8 +390,9 @@ int main(int argc, char** argv) {
printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1);
}
- /* Recreate the ecmult_gen table using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */
- secp256k1_ecmult_gen_create_prec_table(&secp256k1_ecmult_gen_prec_table[0][0], &secp256k1_ge_const_g, ECMULT_GEN_PREC_BITS);
+ /* Recreate the ecmult{,_gen} tables using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */
+ secp256k1_ecmult_gen_compute_table(&secp256k1_ecmult_gen_prec_table[0][0], &secp256k1_ge_const_g, ECMULT_GEN_PREC_BITS);
+ secp256k1_ecmult_compute_two_tables(secp256k1_pre_g, secp256k1_pre_g_128, WINDOW_G, &secp256k1_ge_const_g);
while (count--) {
/* Build context */
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 04227a7c9b..dac86bd77f 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -173,31 +173,6 @@ static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void
# define SECP256K1_GNUC_EXT
#endif
-/* If SECP256K1_{LITTLE,BIG}_ENDIAN is not explicitly provided, infer from various other system macros. */
-#if !defined(SECP256K1_LITTLE_ENDIAN) && !defined(SECP256K1_BIG_ENDIAN)
-/* Inspired by https://github.com/rofl0r/endianness.h/blob/9853923246b065a3b52d2c43835f3819a62c7199/endianness.h#L52L73 */
-# if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
- defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \
- defined(__i486__) || defined(__i586__) || defined(__i686__) || \
- defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \
- defined(__ARMEL__) || defined(__AARCH64EL__) || \
- (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
- (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \
- defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) /* MSVC */
-# define SECP256K1_LITTLE_ENDIAN
-# endif
-# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
- defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \
- defined(__MICROBLAZEEB__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \
- (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
- (defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1)
-# define SECP256K1_BIG_ENDIAN
-# endif
-#endif
-#if defined(SECP256K1_LITTLE_ENDIAN) == defined(SECP256K1_BIG_ENDIAN)
-# error Please make sure that either SECP256K1_LITTLE_ENDIAN or SECP256K1_BIG_ENDIAN is set, see src/util.h.
-#endif
-
/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */
static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) {
unsigned char *p = (unsigned char *)s;
@@ -338,4 +313,20 @@ static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) {
#endif
}
+/* Read a uint32_t in big endian */
+SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) {
+ return (uint32_t)p[0] << 24 |
+ (uint32_t)p[1] << 16 |
+ (uint32_t)p[2] << 8 |
+ (uint32_t)p[3];
+}
+
+/* Write a uint32_t in big endian */
+SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) {
+ p[3] = x;
+ p[2] = x >> 8;
+ p[1] = x >> 16;
+ p[0] = x >> 24;
+}
+
#endif /* SECP256K1_UTIL_H */
diff --git a/src/secp256k1/src/valgrind_ctime_test.c b/src/secp256k1/src/valgrind_ctime_test.c
index ea6d4b3deb..6ff0085d34 100644
--- a/src/secp256k1/src/valgrind_ctime_test.c
+++ b/src/secp256k1/src/valgrind_ctime_test.c
@@ -166,7 +166,7 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
CHECK(ret == 1);
- ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL);
+ ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
diff --git a/src/sync.h b/src/sync.h
index af7595e6fa..c69b58741b 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -223,12 +223,12 @@ public:
friend class reverse_lock;
};
-#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
+#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__)
template<typename MutexArg>
using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
-#define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
+#define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(cs, #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) \
DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index efc30b6822..12cf1176a6 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -23,7 +23,7 @@
using namespace std::literals;
using node::NodeContext;
-static const std::vector<bool> EMPTY_ASMAP;
+static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
static const bool DETERMINISTIC{true};
static int32_t GetCheckRatio(const NodeContext& node_ctx)
@@ -62,7 +62,7 @@ BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(addrman_simple)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
BOOST_CHECK(addrman->size() >= 1);
// Test: reset addrman and test AddrMan::Add multiple addresses works as expected
- addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
std::vector<CAddress> vAddr;
vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
@@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
BOOST_AUTO_TEST_CASE(addrman_ports)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
BOOST_AUTO_TEST_CASE(addrman_select)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(addrman_select)
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
int64_t start_time{GetAdjustedTime()};
addr.nTime = start_time;
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
BOOST_AUTO_TEST_CASE(addrman_getaddr)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
// Test: Sanity check, GetAddr should never return anything if addrman
// is empty.
@@ -357,27 +357,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap; // use /16
-
- BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 40);
+ BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN), 40);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetTriedBucket(nKey2, EMPTY_NETGROUPMAN));
// Test: Two addresses with same IP but different ports can map to
// different buckets because they have different keys.
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info2.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
- int bucket = infoi.GetTriedBucket(nKey1, asmap);
+ int bucket = infoi.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the same /16 prefix should
@@ -389,7 +387,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("250." + ToString(j) + ".1.1"));
- int bucket = infoj.GetTriedBucket(nKey1, asmap);
+ int bucket = infoj.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the different /16 prefix should map to more than
@@ -409,27 +407,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap; // use /16
-
// Test: Make sure the buckets are what we expect
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 786);
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 786);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), 786);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, EMPTY_NETGROUPMAN), 786);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetNewBucket(nKey2, EMPTY_NETGROUPMAN));
// Test: Ports should not affect bucket placement in the addr
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), info2.GetNewBucket(nKey1, EMPTY_NETGROUPMAN));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
- int bucket = infoi.GetNewBucket(nKey1, asmap);
+ int bucket = infoi.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the same group (\16 prefix for IPv4) should
@@ -442,7 +438,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
ResolveService(
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
ResolveIP("251.4.1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the same source groups should map to NO MORE
@@ -454,7 +450,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("250." + ToString(p) + ".1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the different source groups should map to MORE
@@ -475,6 +471,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
// 101.8.0.0/16 AS8
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
{
+ std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
+ NetGroupManager ngm_asmap{asmap};
+
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
@@ -486,27 +485,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
-
- BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 236);
+ BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, ngm_asmap), 236);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info1.GetTriedBucket(nKey2, ngm_asmap));
// Test: Two addresses with same IP but different ports can map to
// different buckets because they have different keys.
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info2.GetTriedBucket(nKey1, ngm_asmap));
std::set<int> buckets;
for (int j = 0; j < 255; j++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("101." + ToString(j) + ".1.1"));
- int bucket = infoj.GetTriedBucket(nKey1, asmap);
+ int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different /16 prefix MAY map to more than
@@ -518,7 +515,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("250." + ToString(j) + ".1.1"));
- int bucket = infoj.GetTriedBucket(nKey1, asmap);
+ int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different /16 prefix MAY NOT map to more than
@@ -528,6 +525,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
{
+ std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
+ NetGroupManager ngm_asmap{asmap};
+
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
@@ -538,27 +538,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
-
// Test: Make sure the buckets are what we expect
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 795);
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 795);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), 795);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, ngm_asmap), 795);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetNewBucket(nKey1, ngm_asmap) != info1.GetNewBucket(nKey2, ngm_asmap));
// Test: Ports should not affect bucket placement in the addr
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), info2.GetNewBucket(nKey1, ngm_asmap));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
- int bucket = infoi.GetNewBucket(nKey1, asmap);
+ int bucket = infoi.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the same /16 prefix
@@ -571,7 +569,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
ResolveService(
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
ResolveIP("251.4.1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the same source /16 prefix should not map to more
@@ -583,7 +581,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("101." + ToString(p) + ".1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different source /16 prefixes usually map to MORE
@@ -595,7 +593,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("250." + ToString(p) + ".1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
@@ -606,11 +604,12 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
BOOST_AUTO_TEST_CASE(addrman_serialization)
{
std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
+ NetGroupManager netgroupman{asmap1};
const auto ratio = GetCheckRatio(m_node);
- auto addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- auto addrman_asmap1_dup = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
+ auto addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@@ -639,8 +638,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
BOOST_CHECK(addr_pos1.position != addr_pos3.position);
// deserializing non-asmaped peers.dat to asmaped addrman
- addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
+ addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
addrman_noasmap->Add({addr}, default_source);
stream << *addrman_noasmap;
stream >> *addrman_asmap1;
@@ -651,8 +650,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
BOOST_CHECK(addr_pos4 == addr_pos2);
// used to map to different buckets, now maps to the same bucket.
- addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
+ addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
addrman_noasmap->Add({addr, addr2}, default_source);
@@ -671,7 +670,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
{
// Confirm that invalid addresses are ignored in unserialization.
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
@@ -703,14 +702,14 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
- addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
stream >> *addrman;
BOOST_CHECK_EQUAL(addrman->size(), 2);
}
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->size() == 0);
@@ -743,7 +742,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
BOOST_AUTO_TEST_CASE(addrman_noevict)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
// Add 35 addresses.
CNetAddr source = ResolveIP("252.2.2.2");
@@ -795,7 +794,7 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->size() == 0);
@@ -865,7 +864,7 @@ static CDataStream AddrmanToStream(const AddrMan& addrman)
BOOST_AUTO_TEST_CASE(load_addrman)
{
- AddrMan addrman{EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman{EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)};
CService addr1, addr2, addr3;
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
@@ -884,7 +883,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
// Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrman);
bool exceptionThrown = false;
- AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.size() == 0);
try {
@@ -901,7 +900,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
// Test that ReadFromStream creates an addrman with the correct number of addrs.
CDataStream ssPeers2 = AddrmanToStream(addrman);
- AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.size() == 0);
ReadFromStream(addrman2, ssPeers2);
BOOST_CHECK(addrman2.size() == 3);
@@ -939,7 +938,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
// Test that the de-serialization of corrupted peers.dat throws an exception.
CDataStream ssPeers1 = MakeCorruptPeersDat();
bool exceptionThrown = false;
- AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.size() == 0);
try {
unsigned char pchMsgTmp[4];
@@ -955,7 +954,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
// Test that ReadFromStream fails if peers.dat is corrupt
CDataStream ssPeers2 = MakeCorruptPeersDat();
- AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.size() == 0);
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
}
@@ -963,7 +962,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
BOOST_AUTO_TEST_CASE(addrman_update_address)
{
// Tests updating nTime via Connected() and nServices via SetServices()
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
diff --git a/src/test/data/key_io_invalid.json b/src/test/data/key_io_invalid.json
index abe07dad24..8f55abfec7 100644
--- a/src/test/data/key_io_invalid.json
+++ b/src/test/data/key_io_invalid.json
@@ -6,207 +6,207 @@
"x"
],
[
- "2v7k5Bb8Lr1MMgTgW6HAf5YHXi6BzpPjHpQ4srD4RSwHYpzXKiXmLAgiLhkXvp3JF5v7nq45EWr"
+ "1GAdfviErV2Ew95FPtZyikz2qGP3gyCB6Hyu94sedAkPpA523m3fQwps9YKUZkKgQckGPKhRsFR"
],
[
- "RAZzCGtMbiUgMiiyrZySrSpdfnQReFXA3r"
+ "37G2kMDLpmWVhimxRdzwNfE8JFvWXnJYnVcXeeGrek2qumdJuK7XArcVVpRtLLjRra3t64BEPF2"
],
[
- "NYamy7tcPQTzoU5iyQojD3sqhiz7zxkvn8"
+ "giymtio7u7oqWtmC9YnvAEKkLF3JQpAdkEFkVJKYrVDfaLbhaDpX1ihfF2vZmya1i61fwLPC3YQ"
],
[
- "geaFG555Ex5nyRf7JjW6Pj2GwZA8KYxtJJLbr1eZhVW75STbYBZeRszy3wg4pkKdF4ez9J4wQiz"
+ "8iVk9nLM3nYwRuwypjy9NK5rsuZH7BbrQRZ1pgcQmvMnjAgRXD"
],
[
- "2Cxmid3c2XQ2zvQ8SA1ha2TKqvqbJS9XFmXRsCneBS3Po7Qqb65z5zNdsoF9AfieXFcpoVPmkmfa"
+ "cPTVQ1hbo4qdoysf6Jx5GthqucNmdfqt6J2pZRFeXv8Ep7Kmjqud"
],
[
- "gaJ7UVge2njVg9tFTetJrtHgruMm7aQDiSAxfHrVEgzK8N2ooagDVmDkdph434xzc4K96Gjyxcs"
+ "cQbR2Ny85XFBzUMx3Ed6HsTLw2pVruSgPvt5AofnBUnhiv86gYeW"
],
[
- "5JN5BEVQPZ3tAiatz1RGXkrJuE3EC6bervMaPb38wTNgEuZCeqp"
+ "2UB3iG3VJbX2TRrMwm6ssWskgvU9VjFBYSqCzwqkrihCwo7mg4mtS4WuGZgxTKuxf5A3EcotYEymz"
],
[
- "3TnFbyUtBRS5rE1KTW81qLVspjJNaB3uu6uuvLjxhZo2DB6PCGh"
+ "cQe12pqwPR6ExtZKfrKf1q4b3CTh1Qi7MwuvMvzs79nWXDvESfBJ"
],
[
- "7UgSZGaMaTc4d2mdEgcGBFiMeS6eMsithGUqvBsKTQdGzD7XQDbMEYo3gojdbXEPbUdFF3CQoK72f"
+ "tc1qeul5g2xfkvdkrhcfmdursv73ad64jnkjl9c40f"
],
[
- "9261wfqQqruNDnBDhbbb4tN9oKA1KpRFHeoYeufyJApVGixyAG4V"
+ "bt1pq65rzej5glw3ra79gav6fqnx4haa0z257qr3mc8cggkefahmgvyseufhc0"
],
[
- "cS824CTUh18scFmYuqt6BgxuRhdR4dEEnCHs3fzBbcyQgbfasHbw"
+ "tb13hty4qmumlwpp6chxjvcyzza4duqgtmxw3xhm3u9ahj4nyhtwz8eq7ynrj4"
],
[
- "tc1q0ywf7wkz6t580n3yemd3ucfw8jxn93tpc6wskt"
+ "bcrt1r2qxpwuge"
],
[
- "bt1pxeeuh96wpm5c6u3kavts2qgwlv6y8um7u7ga6ltlwrhrv7w9vers8lgt3k"
+ "bc10uexgzna2dpfk0vjt35srz6a27ps6m0l89jweznt83n2sqn2fx4hvn9ym5af8wut34sfrqhk3"
],
[
- "tb130lvl2lyugsk2tf3zhwcjjv39dmwt2tt7ytqaexy8edwcuwks6p5scll5kz"
+ "tb1qum6uh0pt4q253qaf520929737v63w5gf"
],
[
- "bcrt1rhsveeudk"
+ "bcrt1q888ryfgxpvl0k7vum8zpyar2u2sexvdhkf38ue37yknmqq0ycrwpl3w48y"
],
[
- "bc10rmfwl8nxdweeyc4sf89t0tn9fv9w6qpyzsnl2r4k48vjqh03qas9asdje0rlr0phru0wqw0p"
+ "bc1qdsuzmn04k2z8vryw8l4dj8m5ygqgnne5n"
],
[
- "tb1qjqnfsuatr54e957xzg9sqk7yqcry9lns"
+ "tb1qlj8es50nc8j8r8xshrjgzmw5azx89efghmw8ju6zcqla0g6xcnrstsjz7k"
],
[
- "bcrt1q8p08mv8echkf3es027u4cdswxlylm3th76ls8v6y4zy4vwsavngpr4e4td"
+ "bcrt1qzwmyj0z924g7fzs5yvnrkc43y76RVyr2lh5t4r"
],
[
- "BC1QNC2H66VLWTWTW52DP0FYUSNU3QQG5VT4V"
+ "bc1qpu6d26mrulzetu4jqhd7rsunv9aqru26f5c4j8"
],
[
- "tb1qgk665m2auw09rc7pqyf7aulcuhmatz9xqtr5mxew7zuysacaascqs9v0vn"
+ "tb1qun6d26ufh77ghny6u5u8cwz9da7qwc6k4wkuceae9tth06eqlw0syupl4w"
],
[
- "bcrt17CAPP7"
+ "bcrt1qj7g2jps453kj9htk9cxyyc2nxe69x4kzzmth7v"
],
[
- "bc1qxmf2d6aerjzam3rur0zufqxqnyqfts5u302s7x"
+ "bc1p702xksx4z3uqf0u2phllxkfe5cgu0adxptqs0uelx0tqt8e885sqryes2l"
],
[
- "tb1qn8x5dnzpexq7nnvrvnhwr9c3wkakpcyu9wwsjzq9pstkwg0t6qhs4l3rv6"
+ "tb1z7gmh0v6pc30z4xum76lmw8w86yswrlmw"
],
[
- "BCRT1Q397G2RNVYRL5LK07CE8NCKHVKP8Z4SC9U0MVH9"
+ "bcrt1sjsrw6nun4h502cr97xmnyyuhkr22q0s6efrgtu"
],
[
- "bc1pgxwyajq0gdn389f69uwn2fw9q0z5c9s063j5dgkdd23ajaud4hpsercr9h"
+ "2UVPFpGYnLHJezFzjUo42our6PMEoozzRdM"
],
[
- "tb1z6mnmp5k542l6yk4ul0mp4rq3yvz44lfm"
+ "2MygHQjE1U33q3LSC53p69YqFjP8PihumJAF"
],
[
- "bcrt17capp7"
+ "KzNbAQ4mexfAxa6RKBzHQqfoTycaeWpv2p"
],
[
- "2D2bqvKseKHdoKjCNvjVULUgmxHu9hjKGwDbPRjTRH59tsHNLeyKwq3vyVBbo9LByY9wiapqjwFY"
+ "2jDPrDfAKihCGPbPD9ztY8TswAia4V8Bc6vx"
],
[
- "2SSjAim4wZpeQRe5zTj1qqS6Li9ttJDaZ3ze"
+ "4VQUNG1hG64QFtaNyQZQWDdwpxB275Pwb3tvyPt2HDxB8Mi2MgH8Tz3AC83YYiz9LydsLNXEZJLHY"
],
[
- "mi9H6MjLwXxy9kxe1x4ToxyLRBsmcZxgVi"
+ "39TKsUQ5QpEL1wowc6GMUqak94ijirPuP69ooV3xsFmiKQX2dau"
],
[
- "VciXoxEitcn88jy197J9n9cpJ1pZahzU3SyWUiHqLgcfjttLEEJz"
+ "2UEJjT3dSdwc8dAo7oedPzznXceXCEsBbDfAvSymqpqDrkZMv7JBEUpLyhkghioYAWC9W4sKysry"
],
[
- "KppmwADGoExPT9Eq5hjRWpWFDbzJyfzHFgsfxBiDHNpVBgWPRNuy"
+ "7VmMEkphxCFSV1y659Th4dkk6x6bJS5eQvbt8rzUYKQyd6ACgwQ4vXHtXKFUwP2kW3XULipnHJdZ7"
],
[
- "TN7EQXMxKffzvHo54yHHu9R4ks9f5gWBW3MMVf5k72zAqrgVK9ys"
+ "tc1qdlapns4zkn03juf2k9xwwpct209suj6mgcd9gh"
],
[
- "92dbrMEYzP5dD5UhQ6maNkCQ4GLG42BM4Gc6XKZzSSMSfosfkkcB"
+ "bt1psa5eptk29c4jc9yumeseat3a0l5e2fpmw635za2p4gpwdnthueysxga9je"
],
[
- "J7VQxPxyzuWEkRstQWpCz2AgysEz1APgnWCEQrFvkN3umAnCrhQF"
+ "tb13w8c43lykfj3lvm9sgp6dsnfjla3d57cm83seykunf0ltxjc9lt2q4efm4d"
],
[
- "tc1qymllj6c96v5qj2504y27ldtner6eh8ldx38t83"
+ "bcrt1rjqr2tdkm"
],
[
- "bt1flep4g"
+ "bc10lyxwnxa70l270e6fcmxr4x7dtgu2yvy7gzkurwxy4zhdvgaqrrn6pfg2flyhqzy5t5se8yu3"
],
[
- "tb13c553hwygcgj48qwmr9f8q0hgdcfklyaye5sxzcpcjnmxv4z506xs90tchn"
+ "TB1QFDFM763VXVSUNZHQLPWC0Q8FG5LJX6ZN"
],
[
- "bcrt1tyddyu"
+ "bcrt1q60chha7wfwlau4kdr4mlvyeyc8mnnh9dhxk05e0hmrxcuhghefj36uwyha"
],
[
- "bc10qssq2mknjqf0glwe2f3587wc4jysvs3f8s6chysae6hcl6fxzdm4wxyyscrl5k9f5qmnf05a"
+ "bc1gmk9yu"
],
[
- "tb1q425lmgvxdgtyl2m6xuu2pc354y4fvgg8"
+ "tb1ly0q7p"
],
[
- "bcrt1q9wp8e5d2u3u4g0pll0cy7smeeuqezdun9xl439n3p2gg4fvgfvk3hu52hj"
+ "bcrt1qdwttaw38uf42wxw40kwk3u8nguyTQH3hx6jmqp"
],
[
- "bc1qrz5acazpue8vl4zsaxn8fxtmeuqmyjkq3"
+ "bc1qtsvlht6730n04f2mpaj5vv8hrledn5n5ug8c79"
],
[
- "tb1qkeuglpgmnex9tv3fr7htzfrh3rwrk23r52rx9halxzmv9fr85lwq0fwhmp"
+ "tb1dclvmr"
],
[
- "bcrt1qd0t2wrhl7s57z99rsyaekpq0dyjcQRSSmz80r4"
+ "bcrt1q3fqvctqu48wsvggrt09vj0yk2gzzcscdp4h98u"
],
[
- "BC1QXLFDUCGX90T3E53PQCNKJ2PK25MSF3VLPMVY6T"
+ "bc1prklpq7tjcawg89cmwwqr3u5apwav36xa4zz56ady7crsllm6mpnqts7p86"
],
[
- "tb1qmycg4zszgnk34vaurx3cu8wpvteg9h40yq6cp52gt26gjel03t3su3x3xu"
+ "tb1zkm58zyhxz3ffkfgsyprflg543slsl4c4"
],
[
- "bcrt1q9hy58r4fnuxqzdqndpmq9pptc9nt2dw3rczf5e"
+ "bcrt1snzr5kaypnfhpnjanrhd20fhqcjxm3hfh7dw9fu"
],
[
- "BC1PA7682NAY6JQSLUWAJYTC0ERWTMW7A4RPWLNTUS32LCXWLHVKKKTQ2UL8CG"
+ "2GgnYKqBGuA2Mm5GnrPsMTZR81xPhNtgMYoFUZngZGiobhCuUpCaTriUHRcgFreEekNdPAR17q8d"
],
[
- "tb1z850dpxnwz2fzae5h2myatj4yvu6rq5xq"
+ "AZEah8d1EK362okRBS66e8SvdtYkrE8tsX"
],
[
- "bcrt1sp525pzjsmpqvcrawjreww36e9keg876skjvpwt"
+ "gep8xr77FyPW6zYP15RiV9W8nL6w2HyHB16cUDakfyDceMA6ZzUdhJjk2LPuLYHnLkBqkRTTi6z"
],
[
- "xcAvW5jurCpzSpLxBKEhCewCgwwuGhqJnC"
+ "2NDNP7GY59tTJPZTpbkprhM9SR99Nn5rUs7"
],
[
- "2Cvv8yp9kXbQt8EKh6Yma95yJ1uwYF9YKXuVhGJyu3dHGVsb2AVpTC62TFACZZ3KDNrALxR2CVNs"
+ "2Csgzy2T287YAjeU5tFtt1nPshBZAUFQi4WtgaWyZGKSBNnKXHy2Tmxo8QK4Mfdds977ShcDWC5o"
],
[
- "niUuL46hCuEVvkAzZKHvD746qbmLmzip9Pv3F6UZV14JxzEXBnTkVxCT4URapChJG6qAEgsZs6G"
+ "Kwjk3Vy6sdXMQDGWJzaWmqFxUNtWZCX1q4F4Kpt8jNNUoWJUUaTY"
],
[
- "2UHHgGfiipzvB8Eumnmvq6SowvrMJimjT3NwwG1839XEiUfwtpSdkUrseNsQuagXv21ce7aZu6yo"
+ "Svj8kk98bAS9V4L2crmxakbhmnPm3cJ1tJ4Je4yVzDreU8eSTFURS1SPYv5oWEQD8Q9VBDvx5uF"
],
[
- "8u9djKu4u6o3bsgeR4BKNnLK3akpo64FYzDAmA9239wKeshgF97"
+ "KNYsv6v9GtkGeD4WdQnBEJCrPKQm91PTxAbCfXr66LEd4JDmhPWC"
],
[
- "TC1QPAARXSLVMXHVRR0474LZXQYZWLGFZYPSFVL9E4"
+ "2UJ2H2xvAeXmFKfQwMyDoSdQTTPFMNCT3SsoUafBWKzoGP3NsUK1buEgQZG38viyD53jgMdpqfT7"
],
[
- "bt1pakek0n2267t9yaksxaczgr2syhv9y3xkx0wnsdwchfa6xkmjtvuqg3kgyr"
+ "6aLMfayKF4TW4ecn5SEc8FExpyJA2peKxYRGZhes6tQ4NTTzuGy"
],
[
- "tb13h83rtwq62udrhwpn87uely7cyxcjrj0azz6a4r3n9s87x5uj98ys6ufp83"
+ "7VP4FmcebU2thJns9MnXde7LWfuqR5vMizrAuUoq2GcJjzTyA4RHFcPVdZL8PLg1SbpSFdJrvLXoY5"
],
[
- "bcrt1rk5vw5qf2"
+ "tc1q5qdvt99uc92jyz663dtdpfpv6nr67ahmgwcpq2"
],
[
- "bc10d3rmtg62h747en5j6fju5g5qyvsransrkty6ghh96pu647wumctejlsngh9pf26cysrys2x2"
+ "bt1peu3ppd7x796sjjenp09r8cs22rhylqm9lhggk72qp8q22vzft0wq2a0x6j"
],
[
- "tb1qajuy2cdwqgmrzc7la85al5cwcq374tsp"
+ "tb1323z3lnz7dl3kd0nsuh6xy4he9almzl67anxgg3xdzkaxc9rwntlqdhdzd7"
],
[
- "bcrt1q3udxvj6x20chqh723mn064mzz65yr56ef00xk8czvu3jnx04ydapzk02s5"
+ "bcrt1r2gc42sky"
],
[
- "bc1qule2szwzyaq4qy0s3aa4mauucyqt6fewe"
+ "bc10fd889x4hd54tqu2ewg9t4hhft2wl7m6x50av4uswzw46xe6as0xmltfg7vrjfkvm459vld7w"
],
[
- "tb1ql0qny5vg9gh5tyzke6dw36px5ulkrp24x53x0pl2t5lpwrtejw3s2seej2"
+ "TB1QZY7V0F2AT3308YGGNGN66ULJTCN3RY6F"
],
[
- "bcrt17CAPP7"
+ "bcrt1qjg3cwht92znyw0l4r5rtctmls337nrc7g0ry9drjxmlecjd3atl3fake7c"
],
[
- "bc1qtvm6davyf725wfedc2d5mrgfewqgcrce8gjrpl"
+ "bc1qmgf8xt8xkecl79k04mma3lz34gqep7hg4"
],
[
- "tb1q5acjgtqrrw3an0dzavxxxzlex8k7aukjzjk9v2u4rmfdqxjphcyq7ge97e"
+ "TB1Q3F9WGNXE9ZMTTMDN5VKVKHYZ8Y0LCV72YV7V5LSXTJXEYHNHEHASLYL0TZ"
]
]
diff --git a/src/test/data/key_io_valid.json b/src/test/data/key_io_valid.json
index 5dee44c04b..c051f8b76b 100644
--- a/src/test/data/key_io_valid.json
+++ b/src/test/data/key_io_valid.json
@@ -1,71 +1,71 @@
[
[
- "1BShJZ8A5q53oJJfMJoEF1gfZCWdZqZwwD",
- "76a914728d4cc27d19707b0197cfcd7c412d43287864b588ac",
+ "1FsSia9rv4NeEwvJ2GvXrX7LyxYspbN2mo",
+ "76a914a31c06bd463e3923bc1aadbde48b16976c08071788ac",
{
"chain": "main",
"isPrivkey": false
}
],
[
- "3L1YkZjdeNSqaZcNKZFXQfyokx3zVYm7r6",
- "a914c8f37c3cc21561296ad81f4bec6b5de10ebc185187",
+ "36j4NfKv6Akva9amjWrLG6MuSQym1GuEmm",
+ "a914373b819a068f32b7a6b38b6b38729647cfde01c287",
{
"chain": "main",
"isPrivkey": false
}
],
[
- "mhJuoGLgnJC8gdBgBzEigsoyG4omQXejPT",
- "76a91413a92d1998e081354d36c13ce0c9dc04b865d40a88ac",
+ "mzK2FFDEhxqHcmrJw1ysqFkVyhUULo45hZ",
+ "76a914ce28b26c57472737f5c3561a1761185bd8589a4388ac",
{
"chain": "test",
"isPrivkey": false
}
],
[
- "2N5VpzKEuYvZJbmg6eUNGnfrrD1ir92FWGu",
- "a91486648cc2faaf05660e72c04c7a837bcc3e986f1787",
+ "2NC2hEhe28ULKAJkW5MjZ3jtTMJdvXmByvK",
+ "a914ce0bba75891ff9ec60148d4bd4a09ee2dc5c933187",
{
"chain": "test",
"isPrivkey": false
}
],
[
- "mtQueCtmAnP3E4aBHXCiFNEQAuPaLMuQNy",
- "76a9148d74ecd86c845baf9c6d4484d2d00e731b79e34788ac",
+ "mww4LvqtTMKvmeQvizPz2EQv26xTneWrbg",
+ "76a914b4110ba93ac54afc14da3bdd19614774a2d55d2988ac",
{
"chain": "signet",
"isPrivkey": false
}
],
[
- "2NEvWRTHjh89gV52fkperFtwzoFWQiQmiCh",
- "a914edc895152c67ccff0ba620bcc373b789ec68266f87",
+ "2N1r7aC69VHeE7yQJPDLi9T1PYq4wnwvjuT",
+ "a9145e5a35ab44b3efaea5129ba22b88ba3e2976614587",
{
"chain": "signet",
"isPrivkey": false
}
],
[
- "mngdx94qJFhSf7A7SAEgQSC9fQJuapujJp",
- "76a9144e9dba545455a80ce94c343d1cac9dec62cbf22288ac",
+ "n4fajahJrAuKbN7uNsKjLjQkz9Qn5ewJXQ",
+ "76a914fdeca3b08e38af53d7c4c60e3ad208ce5066441088ac",
{
"chain": "regtest",
"isPrivkey": false
}
],
[
- "2NBzRN3pV56k3JUvSHifaHyzjGHv7ZS9FZZ",
- "a914cd9da5642451273e5b6d088854cc1fad4a8d442187",
+ "2MxFajLApXpYk4VodBSZSt7rw8y4ryABkfA",
+ "a91436e9f191e0b75036a77f65e2eaa4752443233fbe87",
{
"chain": "regtest",
"isPrivkey": false
}
],
[
- "5KcrFZvJ2p4dM6QVUPu53cKXcCfozA1PJLHm1mNAxkDYhgThLu4",
- "ed6c796e2f62377410766214f55aa81ac9a6590ad7ed57c509c983bf648409ac",
+ "5JuW2AMDYu4xVwRG9DZW18VbzQrGcd5RCgb99sS6ehJsNQXu5b9",
+ "8f8943bf956de595665c38ffff23827e17c10cdc1c27a028caae6c9810626198",
{
"chain": "main",
"isCompressed": false,
@@ -73,8 +73,8 @@
}
],
[
- "L195WBrf2G3nCnun4CLxrb8XKk9LbCqH43THh4n4QrL5SzRzpq9j",
- "74f76c106e38d20514a99a86e4fe3bb28319e7dd2ad21dbc170cbb516a5358fa",
+ "L5nJeqKmpHp4P7F8ZYyjwc5a7P4d8EabuGAzfGJk7yC1BJyzNaEd",
+ "ff778740f88ddcf102aeb81daee289c044c4a4571c4b6f287400f4b8e0b843f8",
{
"chain": "main",
"isCompressed": true,
@@ -82,8 +82,8 @@
}
],
[
- "92z6HnMQR4tWqjfVA3UaUN5EuUMgoVMdCa5rZFYZfmgyD7wxYCw",
- "b8511e1d74549e305517d48a1d394d1be2cfa5d0f3c0d83f9f450316ffa01276",
+ "92ZdE5HoLafywnTBbzPxbvRmp75pSfzvdU3XaZGh1cToipgdHVh",
+ "80c32d81e91bdea04cd7a3819b32275fc3298af4c7ec87eb0099527d041ced5c",
{
"chain": "test",
"isCompressed": false,
@@ -91,8 +91,8 @@
}
],
[
- "cTPnaF52x4w4Tq6afPxRHux3wbYb86thS7S45A7r3oZc1AHTQ6Qm",
- "ad68c48d337181da125de9061933ececcdf7d917631af7d34f7e38082bff9a11",
+ "cV83kKisF3RQSvXbUCm9ox3kaz5JjEUBWcx8tNydfGJcyeUxuH47",
+ "e0fcd4ce4e3d0e3de091f21415bb7cd011fac288c42020a879f28c2a4387df9b",
{
"chain": "test",
"isCompressed": true,
@@ -100,8 +100,8 @@
}
],
[
- "924U35yFcYkxe2JXGmuhSRVaShGyhRDZx1ysPmw1sAHuszGMoxq",
- "3e8dfaf78d4f02b11d0b645648a4f3080d71d0d068979c47f7255c9a29eee01d",
+ "92QuSnywrhsV7WPZChTgSQA23uSmj9MCEEno1eRBDG9sg8M29cX",
+ "6cf636ed8ac1bab033b64f66feaba65f70e684731e3f39105605968d3a963801",
{
"chain": "signet",
"isCompressed": false,
@@ -109,8 +109,8 @@
}
],
[
- "cRy1qCf2LUesGPQagTkYwk2V3PyN2KCPKgxeg6k6KoJPzH7nrVjw",
- "82d4187690d6b59bcffda27dae52f2ecb87313cfc0904e0b674a27d906a65fde",
+ "cND53Dhp8eCZqG2ghe8YhSCGesXZ8fE5PGD1khrqNvEi4RBoXhEK",
+ "12b5a10f3a11e708dc5412833c47ab7c368a21b9efe19293793ec879ce683018",
{
"chain": "signet",
"isCompressed": true,
@@ -118,8 +118,8 @@
}
],
[
- "932NTcHK35Apf2C3K9Zv1ZdeZEmB1x7ZT2Ju3SjoEY6pUgUpT7H",
- "bd7dba24df9e003e145ae9b4862776413a0bb6fa5b4e42753397f2d9536e58a9",
+ "91mn1wYKEB1zyof1VFm8tMtocZx1oBrKKRCu9GCpgZvPmBLEJjp",
+ "18a86e5a6c6977ddba0daca7fba5190f67ba56ccdc1b3f31308972236c2e4776",
{
"chain": "regtest",
"isCompressed": false,
@@ -127,8 +127,8 @@
}
],
[
- "cNa75orYQ2oos52zCnMaS5PG6XbNZKc5LpGxTHacrxwWeX4WAK3E",
- "1d87e3c58b08766fea03598380ec8d59f8c88d5392bf683ab1088bd4caf073ee",
+ "cPisAUdLvqqAr6MYtXnrWvgvyUAwuNyuTvZkDGw6miPhZdaiSDNH",
+ "3fdfec1371cedcdb8c190ca6ff8ad603f817edc0d93c2a687c7b36dd66e70f2a",
{
"chain": "regtest",
"isCompressed": true,
@@ -136,8 +136,8 @@
}
],
[
- "bc1q5cuatynjmk4szh40mmunszfzh7zrc5xm9w8ccy",
- "0014a639d59272ddab015eafdef9380922bf843c50db",
+ "bc1qvyq0cc6rahyvsazfdje0twl7ez82ndmuac2lhv",
+ "00146100fc6343edc8c874496cb2f5bbfec88ea9b77c",
{
"chain": "main",
"isPrivkey": false,
@@ -145,8 +145,8 @@
}
],
[
- "bc1qkw7lz3ahms6e0ajv27mzh7g62tchjpmve4afc29u7w49tddydy2syv0087",
- "0020b3bdf147b7dc3597f64c57b62bf91a52f179076ccd7a9c28bcf3aa55b5a46915",
+ "bc1qyucykdlhp62tezs0hagqury402qwhk589q80tqs5myh3rxq34nwqhkdhv7",
+ "002027304b37f70e94bc8a0fbf500e0c957a80ebda87280ef58214d92f119811acdc",
{
"chain": "main",
"isPrivkey": false,
@@ -154,8 +154,8 @@
}
],
[
- "bc1p5rgvqejqh9dh37t9g94dd9cm8vtqns7dndgj423egwggsggcdzmsspvr7j",
- "5120a0d0c06640b95b78f965416ad6971b3b1609c3cd9b512aaa39439088211868b7",
+ "bc1p83n3au0rjylefxq2nc2xh2y4jzz4pm6zxj4mw5pagdjjr2a9f36s6jjnnu",
+ "51203c671ef1e3913f94980a9e146ba895908550ef4234abb7503d436521aba54c75",
{
"chain": "main",
"isPrivkey": false,
@@ -163,8 +163,8 @@
}
],
[
- "bc1zr4pq63udck",
- "52021d42",
+ "bc1z2rksukkjr8",
+ "520250ed",
{
"chain": "main",
"isPrivkey": false,
@@ -172,8 +172,8 @@
}
],
[
- "tb1q74fxwnvhsue0l8wremgq66xzvn48jlc5zthsvz",
- "0014f552674d978732ff9dc3ced00d68c264ea797f14",
+ "tb1qcrh3yqn4nlleplcez2yndq2ry8h9ncg3qh7n54",
+ "0014c0ef1202759fff90ff19128936814321ee59e111",
{
"chain": "test",
"isPrivkey": false,
@@ -181,8 +181,8 @@
}
],
[
- "tb1qpt7cqgq8ukv92dcraun9c3n0s3aswrt62vtv8nqmkfpa2tjfghesv9ln74",
- "00200afd802007e598553703ef265c466f847b070d7a5316c3cc1bb243d52e4945f3",
+ "tb1quyl9ujpgwr2chdzdnnalen48sup245vdfnh2jxhsuq3yx80rrwlq5hqfe4",
+ "0020e13e5e482870d58bb44d9cfbfccea78702aad18d4ceea91af0e022431de31bbe",
{
"chain": "test",
"isPrivkey": false,
@@ -190,8 +190,8 @@
}
],
[
- "tb1ph9v3e8nxct57hknlkhkz75p5pnxnkn05cw8ewpxu6tek56g29xgqydzfu7",
- "5120b9591c9e66c2e9ebda7fb5ec2f50340ccd3b4df4c38f9704dcd2f36a690a2990",
+ "tb1p35n52jy6xkm4wd905tdy8qtagrn73kqdz73xe4zxpvq9t3fp50aqk3s6gz",
+ "51208d2745489a35b75734afa2da43817d40e7e8d80d17a26cd4460b0055c521a3fa",
{
"chain": "test",
"isPrivkey": false,
@@ -199,8 +199,8 @@
}
],
[
- "tb1ray6e8gxfx49ers6c4c70l3c8lsxtcmlx",
- "5310e93593a0c9354b91c358ae3cffc707fc",
+ "tb1rgv5m6uvdk3kc7qsuz0c79v88ycr5w4wa",
+ "53104329bd718db46d8f021c13f1e2b0e726",
{
"chain": "test",
"isPrivkey": false,
@@ -208,8 +208,8 @@
}
],
[
- "tb1q0sqzfp3zj42u0perxr6jahhu4y03uw4dypk6sc",
- "00147c002486229555c7872330f52edefca91f1e3aad",
+ "tb1q3vya2h5435jkugq2few7dmktlrwq4ejmfaw7kr",
+ "00148b09d55e958d256e200a4e5de6eecbf8dc0ae65b",
{
"chain": "signet",
"isPrivkey": false,
@@ -217,8 +217,8 @@
}
],
[
- "tb1q9jv4qnawnuevqaeadn47gkq05ev78m4qg3zqejykdr9u0cm7yutq6gu5dj",
- "00202c99504fae9f32c0773d6cebe4580fa659e3eea044440cc89668cbc7e37e2716",
+ "tb1qxkhrl2s6ttrclckldruea0e8anhrehffl8xv7t0pdyrzm08v2hyqy408nf",
+ "002035ae3faa1a5ac78fe2df68f99ebf27ecee3cdd29f9cccf2de169062dbcec55c8",
{
"chain": "signet",
"isPrivkey": false,
@@ -226,8 +226,8 @@
}
],
[
- "tb1pxqf7d825wjtcftj7uep8w24jq3tz8vudfaqj20rns8ahqya56gcs92eqtu",
- "51203013e69d54749784ae5ee642772ab2045623b38d4f41253c7381fb7013b4d231",
+ "tb1pae5um27ahn8n73pgexe3kcwlp8dhswpn684h2k2w6t9a7w3eq65qephd5y",
+ "5120ee69cdabddbccf3f4428c9b31b61df09db783833d1eb75594ed2cbdf3a3906a8",
{
"chain": "signet",
"isPrivkey": false,
@@ -235,8 +235,8 @@
}
],
[
- "tb1rsrzkyvu2rt0dcgexajtazlw5nft4j7494ay396q6auw9375wxsrsgag884",
- "532080c562338a1adedc2326ec97d17dd49a57597aa5af4912e81aef1c58fa8e3407",
+ "tb1rx9n9g37az8mu236e5jpxdt0m67y4fuq8rhs0ss3djnm0kscfrwvq0ntlyg",
+ "532031665447dd11f7c54759a48266adfbd78954f0071de0f8422d94f6fb43091b98",
{
"chain": "signet",
"isPrivkey": false,
@@ -244,8 +244,8 @@
}
],
[
- "bcrt1qwf52dt9y2sv0f7fwkcpmtfjf74d4np2saeljt6",
- "00147268a6aca45418f4f92eb603b5a649f55b598550",
+ "bcrt1qdavt4j2sd7dlhqsavtnfxvzppw6k7qy97tmnu9",
+ "00146f58bac9506f9bfb821d62e69330410bb56f0085",
{
"chain": "regtest",
"isPrivkey": false,
@@ -253,8 +253,8 @@
}
],
[
- "bcrt1q0lma84unycxl4n96etffthqlf7y5axyp4fxf64kmhymvw8l6pwfs39futd",
- "00207ff7d3d793260dfaccbacad295dc1f4f894e9881aa4c9d56dbb936c71ffa0b93",
+ "bcrt1qan8gntac7z7me2ejt4hpru42ad2f759fmy0m3ejvs98656znv7eqga4uhv",
+ "0020ecce89afb8f0bdbcab325d6e11f2aaeb549f50a9d91fb8e64c814faa685367b2",
{
"chain": "regtest",
"isPrivkey": false,
@@ -262,8 +262,8 @@
}
],
[
- "bcrt1p3xat2ryucc2v0adrktqnavfzttvezrr27ngltsa2726p2ehvxz4se722v2",
- "512089bab50c9cc614c7f5a3b2c13eb1225ad9910c6af4d1f5c3aaf2b41566ec30ab",
+ "bcrt1pfwxjqvtt4tcxrtdluukfmy2dv7xd2qzdfy6kajv5nwn4yam3wxkq3553uh",
+ "51204b8d20316baaf061adbfe72c9d914d678cd5004d49356ec9949ba752777171ac",
{
"chain": "regtest",
"isPrivkey": false,
@@ -271,8 +271,8 @@
}
],
[
- "bcrt1saflydw6e26xhp29euhy5jke5jjqyywk3wvtc9ulgw9dvxyuqy9hdnxthyw755c7ldavy7u",
- "6028ea7e46bb59568d70a8b9e5c9495b349480423ad1731782f3e8715ac31380216ed9997723bd4a63df",
+ "bcrt1sx6p8njlx7h9mc2agz4yg82dzne23050ncq72cneeecez2pst8mahn8xecsf8g6hzx94420",
+ "6028368279cbe6f5cbbc2ba8154883a9a29e5517d1f3c03cac4f39ce3225060b3efb799cd9c412746ae2",
{
"chain": "regtest",
"isPrivkey": false,
@@ -280,72 +280,72 @@
}
],
[
- "16y3Q1XVRZqMR9T1XL1FkvNtD2E1bXBuYa",
- "76a9144171ec673aeb9fcf42af6094a3c82207e3b9a78188ac",
+ "1FjL87pn8ky6Vbavd1ZHeChRXtoxwRGCRd",
+ "76a914a19331b7b2627e663e25a7b001e4c0dcc5e21bc788ac",
{
"chain": "main",
"isPrivkey": false
}
],
[
- "3CmZZnAiHVQgiAKSakf864oJMxN2BP1eLC",
- "a914798575fc1041b9440c4e63c28e57e597d00b7e4387",
+ "3BZECeAH8gSKkjrTx8PwMrNQBLG18yHpvf",
+ "a9146c382dcdf5b284760c8e3fead91f7422cd76aa8787",
{
"chain": "main",
"isPrivkey": false
}
],
[
- "mtCB3SoBo7EYUv8j54kUubGY4x3aJPY8nk",
- "76a9148b0c5f9ee714e0d1d24642ad63d9d5f398d9b56588ac",
+ "n4YNbYuFdPwFrxSP8sjHFbAhUbLMUiY9jE",
+ "76a914fc8f9851f3c1e4719cd0b8e4816dd4e88c72e52888ac",
{
"chain": "test",
"isPrivkey": false
}
],
[
- "2N5ymzzKpx6EdUR4UdMZ7t9hcuwqtpHwgw5",
- "a9148badb3c3b5c0d39f906f7618e0018b7eae4baf7387",
+ "2NAeQVZayzVFAtgeC3iYJsjpjWDmsDph71A",
+ "a914bedc797342c03fd7a346c4c7857ca03d467013b687",
{
"chain": "test",
"isPrivkey": false
}
],
[
- "myXnpYbub28zgiJupDdZSWZtDbjcyfJVby",
- "76a914c59ac57661b57daadd7c0caf7318c14f54c6c0fa88ac",
+ "mnCBpkNMJEJLehgdEkzSo2eioniyJMxLpZ",
+ "76a914493c455551e48a1423263b62b127b436106a685488ac",
{
"chain": "signet",
"isPrivkey": false
}
],
[
- "2MtLg8jS5jSXm9evMzTtvpLjy26dBmjFEoT",
- "a9140c0007e89cea625d3bf9543baa5a470bb7e5b67287",
+ "2N5sNHomeNJDZv67AcFx9ES7FBZY4jx9KDA",
+ "a9148a776a0f34d56b63e7c595f2b205dbe1c393617a87",
{
"chain": "signet",
"isPrivkey": false
}
],
[
- "mzCyqdf2UNGdpgkD9NBgLcxdwXRg1i9buY",
- "76a914cd04311bdd1ef9c5c24e41930e032aade82a863a88ac",
+ "mfhE6jAUwjUDNZhaX1PAsDTKfneQF2Nshc",
+ "76a91401f15a4cc063dae4f4d56b89bfbc8bcc9ae5387c88ac",
{
"chain": "regtest",
"isPrivkey": false
}
],
[
- "2N3zGiwFku2vQjYnAqXv5Qu2ztfYRhh7tbF",
- "a91475d56d75c88e704d6c72fbe84ac1505abf736b4087",
+ "2MxNm1VHyVU4RuP3u1c1v5aQLk2dQjwy1Qk",
+ "a91438456f7c076356abadcc67b92ad777eb20fb9f8887",
{
"chain": "regtest",
"isPrivkey": false
}
],
[
- "5JUHCgyxNSHg64wwju72eNsG6ajqo4Z2fHHw9iLDLfh69rSiL7w",
- "5644d06d88855dacf3192a31df8f4acd8e4c155c52a86d2c1fa48303f5cff053",
+ "5HsL2nZuEebU5nM3RxNVQD9GcAnvNMahqQskf4fkqHe54zwd14e",
+ "06e8649790a90615a46d22dd762e0c42615336745356c2e16147c0f3d46b40d5",
{
"chain": "main",
"isCompressed": false,
@@ -353,8 +353,8 @@
}
],
[
- "L2kZaexG69VSriMe9T2m1jkS86iPe3xNbjcdfakRC1PHe7ay78Ji",
- "a50ee94aefcabf5a5d7c85be5b3844dee03c5604861dbfc77fe388c91e5a30f8",
+ "KwuVvu6hsuEMHrfFWJQV64tRrWX3QzqHH18JuAHYqYV6dqBvNKxd",
+ "147804bf8a0dfff35939a611c7f5a60ac107f33f33d6059f273d2079ab1d90f2",
{
"chain": "main",
"isCompressed": true,
@@ -362,8 +362,8 @@
}
],
[
- "927JwT1ViCr5TD2ZX8CsMNhg17dXmou5xu4y2KiH54zD7i34UJq",
- "4502a54c0026b0150281d41f40860d1e23870c63cdc32645bbed688f2ee41f64",
+ "921M1RNxghFcsVGqAJksQVbSgx36Yz4u6vebfz1wDujNvgNt93B",
+ "3777b341c45e2a9b9bf6bfb71dc7d129f64f1b9406ed4f93ade8f56065f1b732",
{
"chain": "test",
"isCompressed": false,
@@ -371,8 +371,8 @@
}
],
[
- "cTpGGNPVy2Eagawohbr4aGtRJzpLnjxGsGYh9DUcBM45f3KdKGF6",
- "ba005a0cb39587aab00bd54c848b59e8adaed47403228567ddc739c2a344ff59",
+ "cNEnbfF2fcxmmCLWqMAaq6fxJvVkwMbyU3kCbpQznz4Z1j6TZDGb",
+ "1397b0d4a03e1ab2c54dd9af99ce1ecbfb90c80a58886da95e1181a55703d96b",
{
"chain": "test",
"isCompressed": true,
@@ -380,8 +380,8 @@
}
],
[
- "932PLCLA19yPNqV67qwHBSGjxi82LVzWBF7josL9ab4Q1kxgPGF",
- "bd8677e076eb39770bf7e9f9e8d3f2cf257effab9b4c220fd3439ccfc208c984",
+ "93BcpCMKPmFCuY8bqS4k3HFrhJ1Afxi4uSsEeJFvX86GYW7PC7W",
+ "d27d1b6ef55ca2e4d475b5276f2dbb85f7a6459dceeb89c67b776fd3bb974452",
{
"chain": "signet",
"isCompressed": false,
@@ -389,8 +389,8 @@
}
],
[
- "cViUpEy8URSsLjUvxwL7cEuNgCVqM7oKBzd1ZPbA4khcQsQJuj1j",
- "f2b36ade8393e29dc71e52cb75ba1109ba210203cd7d0a5ae881ad6846516203",
+ "cUtwbyxoL1owPxUafgH2meEpydeywjhnTYv2mJaFHHchz39AaEgy",
+ "da3ed4ef1647e1733ec076919cab6156077ed9532e7c365acc425747e198b3e1",
{
"chain": "signet",
"isCompressed": true,
@@ -398,8 +398,8 @@
}
],
[
- "92jddDjJCVDmJtgvBHQ9i58PMash8kwsYhRdNo22ea2MYPXdCBE",
- "977bf8686f1bcad28f86c4c14afbd33215746bd19203647bf7ff9c6fddc9cc87",
+ "927zPWny2SiNaUmHF5NnGQXQWDwbByfFzXGgu88j91ZoutSosvE",
+ "468e0284f230153db8687d8ec23db079a5b67d72ca04174b3867b13e4ea9945e",
{
"chain": "regtest",
"isCompressed": false,
@@ -407,8 +407,8 @@
}
],
[
- "cVwAuMoUqRo399X7vXzuzQyPEvZJMXM8c82zHzRkFCxPCSGx8A6y",
- "f93acbbce02b8cb9ddca3fad495441e324cc01eb640b0a7b4c9f0e31644c822a",
+ "cRez45VGSp5EXNqm89K3NJJPSKKapJg5Kbw3atxr2337x2gtgYed",
+ "798d87586cffbe8c545ab374454e403b1eb831501ebe89f3c3b02f3137bd7b46",
{
"chain": "regtest",
"isCompressed": true,
@@ -416,8 +416,8 @@
}
],
[
- "bc1qz377zwe5awr68dnggengqx9vrjt05k98q3sw2n",
- "0014147de13b34eb87a3b66846668018ac1c96fa58a7",
+ "bc1qhxt04s5xnpy0kxw4x99n5hpdf5pmtzpqs52es2",
+ "0014b996fac2869848fb19d5314b3a5c2d4d03b58820",
{
"chain": "main",
"isPrivkey": false,
@@ -425,8 +425,8 @@
}
],
[
- "bc1qkmhskpdzg8kdkfywhu09kswwn9qan9vnkrf6mk40jvnr06s6sz5ssf82ya",
- "0020b6ef0b05a241ecdb248ebf1e5b41ce9941d99593b0d3addaaf932637ea1a80a9",
+ "bc1qgc9ljrvdf2e0zg9rmmq86xklqwfys7r6wptjlacdgrcdc7sa6ggqu4rrxf",
+ "0020460bf90d8d4ab2f120a3dec07d1adf039248787a70572ff70d40f0dc7a1dd210",
{
"chain": "main",
"isPrivkey": false,
@@ -434,8 +434,8 @@
}
],
[
- "bc1ps8cndas60cntk8x79sg9f5e5jz7x050z8agyugln2ukkks23rryqpejzkc",
- "512081f136f61a7e26bb1cde2c1054d33490bc67d1e23f504e23f3572d6b415118c8",
+ "bc1pve739yap4uxjvfk0jrey69078u0gasm2nwvv483ec6zkzulgw9xqu4w9fd",
+ "5120667d1293a1af0d2626cf90f24d15fe3f1e8ec36a9b98ca9e39c6856173e8714c",
{
"chain": "main",
"isPrivkey": false,
@@ -443,8 +443,8 @@
}
],
[
- "bc1zn4tsczge9l",
- "52029d57",
+ "bc1zmjtqxkzs89",
+ "5202dc96",
{
"chain": "main",
"isPrivkey": false,
@@ -452,8 +452,8 @@
}
],
[
- "tb1q6xw0wwd9n9d7ge87dryz4vm5vtahzhvz6yett3",
- "0014d19cf739a5995be464fe68c82ab37462fb715d82",
+ "tb1ql4k5ayv7p7w0t0ge7tpntgpkgw53g2payxkszr",
+ "0014fd6d4e919e0f9cf5bd19f2c335a03643a914283d",
{
"chain": "test",
"isPrivkey": false,
@@ -461,8 +461,8 @@
}
],
[
- "tb1qwn9zq9fu5uk35ykpgsc7rz4uawy4yh0r5m5er26768h5ur50su3qj6evun",
- "002074ca20153ca72d1a12c14431e18abceb89525de3a6e991ab5ed1ef4e0e8f8722",
+ "tb1q9jx3x2qqdpempxrcfgyrkjd5fzeacaqj4ua7cs7fe2sfd2wdaueq5wn26y",
+ "00202c8d1328006873b098784a083b49b448b3dc7412af3bec43c9caa096a9cdef32",
{
"chain": "test",
"isPrivkey": false,
@@ -470,8 +470,8 @@
}
],
[
- "tb1pmcdc5d8gr92rtemfsnhpeqanvs0nr82upn5dktxluz9n0qcv34lqxke0wq",
- "5120de1b8a34e8195435e76984ee1c83b3641f319d5c0ce8db2cdfe08b37830c8d7e",
+ "tb1pdswckwd9ym5yf5eyzg8j4jjwnzla8y0tf9cp7aasfkek0u29sz9qfr00yf",
+ "51206c1d8b39a526e844d324120f2aca4e98bfd391eb49701f77b04db367f145808a",
{
"chain": "test",
"isPrivkey": false,
@@ -479,8 +479,8 @@
}
],
[
- "tb1rgxjvtfzp0xczz6dlzqv8d5cmuykk4qkk",
- "531041a4c5a44179b02169bf101876d31be1",
+ "tb1r0ecpfxg2udhtc556gqrpwwhk4sw3f0kc",
+ "53107e7014990ae36ebc529a4006173af6ac",
{
"chain": "test",
"isPrivkey": false,
@@ -488,8 +488,8 @@
}
],
[
- "tb1qa9dlyt6fydestul4y4wh72yshh044w32np8etk",
- "0014e95bf22f49237305f3f5255d7f2890bddf5aba2a",
+ "tb1q6mwf89hnqhlu8txjgjfs4s7p93ugffn3k062ll",
+ "0014d6dc9396f305ffc3acd244930ac3c12c7884a671",
{
"chain": "signet",
"isPrivkey": false,
@@ -497,8 +497,8 @@
}
],
[
- "tb1qu4p26n0033720xm0rjgkds5ehdwf039k2fgv75um5krrvfhrrj7qckl9r2",
- "0020e542ad4def8c7ca79b6f1c9166c299bb5c97c4b65250cf539ba5863626e31cbc",
+ "tb1qafrjalu4d73dql0czau9j6z422434kef235mzljf48ckd5xz3sys09jm97",
+ "0020ea472eff956fa2d07df8177859685552ab1adb295469b17e49a9f166d0c28c09",
{
"chain": "signet",
"isPrivkey": false,
@@ -506,8 +506,8 @@
}
],
[
- "tb1pjyukm4n4flwd0ey3lrl06c9kalr60ggmlkcxq2rhhxmy4lvkmkpqexdzqy",
- "512091396dd6754fdcd7e491f8fefd60b6efc7a7a11bfdb0602877b9b64afd96dd82",
+ "tb1pwst9qszjrhuv2e7as0flcq9gm698v6gdxzz9e87p07s8rssdx3zqklm3vf",
+ "512074165040521df8c567dd83d3fc00a8de8a76690d30845c9fc17fa071c20d3444",
{
"chain": "signet",
"isPrivkey": false,
@@ -515,8 +515,8 @@
}
],
[
- "tb1r4k75s5syvewsvxufdc3xfhf4tw4u30alw39xny3dnxrl6hau7systymfdv",
- "5320adbd485204665d061b896e2264dd355babc8bfbf744a69922d9987fd5fbcf409",
+ "tb1r3ss76jtsuxe8c8c8lxsehnpak55ylrgr345pww076l536ahjr6jsydamx3",
+ "53208c21ed4970e1b27c1f07f9a19bcc3db5284f8d038d681739fed7e91d76f21ea5",
{
"chain": "signet",
"isPrivkey": false,
@@ -524,8 +524,8 @@
}
],
[
- "bcrt1qnk3tdwwj47ppc4pqmxkjdusegedn9ru5gvccwa",
- "00149da2b6b9d2af821c5420d9ad26f219465b328f94",
+ "bcrt1q65nhlm4hf2ptg3t264al57p7wjxj2c3s6kyt83",
+ "0014d5277feeb74a82b4456ad57bfa783e748d256230",
{
"chain": "regtest",
"isPrivkey": false,
@@ -533,8 +533,8 @@
}
],
[
- "bcrt1qz7prfshfkwsxuk72pt6mzr6uumq4qllxe4vmwqt89tat48d362yqlykk6a",
- "0020178234c2e9b3a06e5bca0af5b10f5ce6c1507fe6cd59b701672afaba9db1d288",
+ "bcrt1qawvc90lpytw3z3k9etdx54l0exq5f5sqfzu5e45kjnl6slwayeeqx2dyac",
+ "0020eb9982bfe122dd1146c5cada6a57efc98144d20048b94cd69694ffa87ddd2672",
{
"chain": "regtest",
"isPrivkey": false,
@@ -542,8 +542,8 @@
}
],
[
- "bcrt1pumee3wj80xvyr7wjmj7zsk26x5pn095aegy862yhx6f2j9sgc9hq6cj4cm",
- "5120e6f398ba47799841f9d2dcbc28595a350337969dca087d28973692a91608c16e",
+ "bcrt1p39a4s4vdcw9kqa8w2t0rp7aj8kfxyw7mce5sk5d70x6wnnmpvt7skf2kxy",
+ "5120897b58558dc38b6074ee52de30fbb23d92623bdbc6690b51be79b4e9cf6162fd",
{
"chain": "regtest",
"isPrivkey": false,
@@ -551,8 +551,8 @@
}
],
[
- "bcrt1szqz8hj64d2hhc6nt65v09jxal66pgff2xpcp9kj648qkk8kjzxelsts4dktd799g47uase",
- "602810047bcb556aaf7c6a6bd518f2c8ddfeb414252a307012da5aa9c16b1ed211b3f82e156d96df14a8",
+ "bcrt1s489d9fhmyel0vzfqsrmew4x7r80asuqesm5hgqacy35daflcyufh3j8cgdtflvt99ph05m",
+ "6028a9cad2a6fb267ef6092080f79754de19dfd8701986e97403b82468dea7f8271378c8f843569fb165",
{
"chain": "regtest",
"isPrivkey": false,
@@ -560,48 +560,48 @@
}
],
[
- "12agZTajtRE3STSchwWNWnrm467zzTQ916",
- "76a9141156e00f70061e5faba8b71593a8c7554b47090c88ac",
+ "1G9A9j6W8TLuh6dEeVwWeyibK1Uc5MfVFV",
+ "76a914a614da54daacdb8861f451a0b7e3c27cdf8a099e88ac",
{
"chain": "main",
"isPrivkey": false
}
],
[
- "3NXqB6iZiPYbKruNT3d9xNBTmtb73xMvvf",
- "a914e49decc9e5d97e0547d3642f3a4795b13ae62bca87",
+ "33GA3ZXbw5o5HeUrBEaqkWXFYYZmdxGRRP",
+ "a914113ca1afeb49ff3abf176ffa19c2a2b4df19712a87",
{
"chain": "main",
"isPrivkey": false
}
],
[
- "mjgt4BoCYxjzWvJFoh68x7cj5GeaKDYhyx",
- "76a9142dc11fc7b8072f733f690ffb0591c00f4062295c88ac",
+ "mwgS2HRbjyfYxFnR1nF9VKLvmdgMfFBmGq",
+ "76a914b14ce7070b53cb0e4b5b5f6e253e876990aeca2e88ac",
{
"chain": "test",
"isPrivkey": false
}
],
[
- "2NCT6FdQ5MxorHgnFxLeHyGwTGRdkHcrJDH",
- "a914d2a8ec992b0894a0d9391ca5d9c45c388c41be7e87",
+ "2MwBVrJQ76BdaGD76CTmou8cZzQYLpe4NqU",
+ "a9142b2c149cde619eae3d7fe995243b76a3417541aa87",
{
"chain": "test",
"isPrivkey": false
}
],
[
- "mpomiA7wqDnMcxaNLC23eBuXAb4U6H4ZqW",
- "76a91465e75e340415ed297c58d6a14d3c17ceeaa17bbd88ac",
+ "mfnJ8tEkqKNFE5YaHTXFxyHk2mnDK2fvDh",
+ "76a91402e6cd77e649ad8b281271f158fc964ca3f66cb088ac",
{
"chain": "signet",
"isPrivkey": false
}
],
[
- "2N1pGAA5uatbU2PKvMA9BnJmHcK6yHfMiZa",
- "a9145e008b6cc232164570befc23d216060bf4ea793b87",
+ "2My83D67ir7K8PPzeT6mE2oth3ZwNTVRS9F",
+ "a9144074d84d32ff62da7b1b3c61925b934bfeb34b0587",
{
"chain": "signet",
"isPrivkey": false
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index f03ff5ba3a..69fcd73429 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -4,7 +4,6 @@
// Unit tests for denial-of-service detection/prevention code
-#include <arith_uint256.h>
#include <banman.h>
#include <chainparams.h>
#include <net.h>
@@ -49,7 +48,7 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
// Disable inactivity checks for this test to avoid interference
static_cast<ConnmanTestMsg*>(connman.get())->SetPeerConnectTimeout(99999s);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
@@ -139,7 +138,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
NodeId id{0};
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
*m_node.chainman, *m_node.mempool, false);
@@ -217,7 +216,7 @@ BOOST_AUTO_TEST_CASE(block_relay_only_eviction)
{
NodeId id{0};
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
*m_node.chainman, *m_node.mempool, false);
@@ -280,7 +279,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
{
const CChainParams& chainparams = Params();
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.chainman, *m_node.mempool, false);
@@ -396,7 +395,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
{
const CChainParams& chainparams = Params();
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.chainman, *m_node.mempool, false);
@@ -464,7 +463,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
// ecdsa_signature_parse_der_lax are executed during this test.
// Specifically branches that run only when an ECDSA
// signature's R and S values have leading zeros.
- g_insecure_rand_ctx = FastRandomContext(ArithToUint256(arith_uint256(33)));
+ g_insecure_rand_ctx = FastRandomContext{uint256{33}};
TxOrphanageTest orphanage;
CKey key;
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index ba917dec2a..af7a282781 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -37,11 +37,19 @@ void initialize_addrman()
g_setup = testing_setup.get();
}
+[[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
+ if (!SanityCheckASMap(asmap, 128)) asmap.clear();
+ return NetGroupManager(asmap);
+}
+
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
- AddrMan addr_man{/*asmap=*/std::vector<bool>(), /*deterministic=*/false, GetCheckRatio()};
+ NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
+ AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio());
try {
ReadFromStream(addr_man, data_stream);
} catch (const std::exception&) {
@@ -124,8 +132,8 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
class AddrManDeterministic : public AddrMan
{
public:
- explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
- : AddrMan{std::move(asmap), /*deterministic=*/true, GetCheckRatio()}
+ explicit AddrManDeterministic(const NetGroupManager& netgroupman, FuzzedDataProvider& fuzzed_data_provider)
+ : AddrMan(netgroupman, /*deterministic=*/true, GetCheckRatio())
{
WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
}
@@ -223,19 +231,12 @@ public:
}
};
-[[nodiscard]] inline std::vector<bool> ConsumeAsmap(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
- if (!SanityCheckASMap(asmap, 128)) asmap.clear();
- return asmap;
-}
-
FUZZ_TARGET_INIT(addrman, initialize_addrman)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
- std::vector<bool> asmap = ConsumeAsmap(fuzzed_data_provider);
- auto addr_man_ptr = std::make_unique<AddrManDeterministic>(asmap, fuzzed_data_provider);
+ NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
+ auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
if (fuzzed_data_provider.ConsumeBool()) {
const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
CDataStream ds(serialized_data, SER_DISK, INIT_PROTO_VERSION);
@@ -244,7 +245,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
try {
ds >> *addr_man_ptr;
} catch (const std::ios_base::failure&) {
- addr_man_ptr = std::make_unique<AddrManDeterministic>(asmap, fuzzed_data_provider);
+ addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
}
}
AddrManDeterministic& addr_man = *addr_man_ptr;
@@ -313,9 +314,9 @@ FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
- std::vector<bool> asmap = ConsumeAsmap(fuzzed_data_provider);
- AddrManDeterministic addr_man1{asmap, fuzzed_data_provider};
- AddrManDeterministic addr_man2{asmap, fuzzed_data_provider};
+ NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
+ AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider};
+ AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider};
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp
index 95be963dc8..1720f8e0ab 100644
--- a/src/test/fuzz/asmap.cpp
+++ b/src/test/fuzz/asmap.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <netaddress.h>
+#include <netgroup.h>
#include <test/fuzz/fuzz.h>
#include <util/asmap.h>
@@ -56,5 +57,6 @@ FUZZ_TARGET(asmap)
memcpy(&ipv4, addr_data, addr_size);
net_addr.SetIP(CNetAddr{ipv4});
}
- (void)net_addr.GetMappedAS(asmap);
+ NetGroupManager netgroupman{asmap};
+ (void)netgroupman.GetMappedAS(net_addr);
}
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index a14d28f4ef..4406779015 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -19,12 +19,12 @@
#include <vector>
namespace {
-const BasicTestingSetup* g_setup;
+const TestingSetup* g_setup;
} // namespace
void initialize_connman()
{
- static const auto testing_setup = MakeNoLogFileContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
}
@@ -32,10 +32,11 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
- AddrMan addrman(/*asmap=*/std::vector<bool>(),
- /*deterministic=*/false,
- g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
- CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
+ CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ *g_setup->m_node.addrman,
+ *g_setup->m_node.netgroupman,
+ fuzzed_data_provider.ConsumeBool()};
CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider);
CSubNet random_subnet;
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index ed6f172a2a..0a7d0c55bd 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -15,6 +15,7 @@
#include <merkleblock.h>
#include <net.h>
#include <netbase.h>
+#include <netgroup.h>
#include <node/utxo_snapshot.h>
#include <primitives/block.h>
#include <protocol.h>
@@ -200,7 +201,8 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
BlockMerkleRoot(block, &mutated);
})
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
- AddrMan am(/*asmap=*/std::vector<bool>(),
+ NetGroupManager netgroupman{std::vector<bool>()};
+ AddrMan am(netgroupman,
/*deterministic=*/false,
g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
DeserializeFromFuzzingInput(buffer, am);
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 6766fbf2d9..033c6e18d5 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -193,6 +193,19 @@ int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* op
return 0;
}
+int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
+{
+ constexpr std::array setsockopt_errnos{
+ ENOMEM,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
+ return -1;
+ }
+ return 0;
+}
+
bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
{
constexpr std::array wait_errnos{
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 6c91844633..580105e442 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -68,6 +68,8 @@ public:
int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
+ int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
+
bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
bool IsConnected(std::string& errmsg) const override;
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 61d334ab18..8cb0515a8a 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -204,7 +204,7 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
// create a dummy hash for signature comparison
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
- GetRandBytes(rnd, sizeof(rnd));
+ GetRandBytes(rnd);
uint256 hash;
CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index 949d30dfd5..930582ea24 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(fixed_tests)
Test("and_b(hash256(32ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac),a:and_b(hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),a:older(1)))", "82012088aa2032ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac876b82012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876b51b26c9a6c9a", TESTMODE_VALID | TESTMODE_NONMAL, 15, 3);
Test("thresh(2,multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),a:multi(1,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),ac:pk_k(022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01))", "522103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c721036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0052ae6b5121036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0051ae6c936b21022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01ac6c935287", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG, 13, 7);
Test("and_n(sha256(d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68),t:or_i(v:older(4252898),v:older(144)))", "82012088a820d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68876400676303e2e440b26967029000b269685168", TESTMODE_VALID, 14, 3);
- Test("or_d(d:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b26968736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", TESTMODE_VALID, 14, 3);
+ Test("or_d(nd:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b2696892736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", TESTMODE_VALID, 15, 3);
Test("c:and_v(or_c(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),v:multi(1,02c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db)),pk_k(03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764512102c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db51af682103acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbeac", TESTMODE_VALID | TESTMODE_NEEDSIG, 8, 3);
Test("c:and_v(or_c(multi(2,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00,02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),v:ripemd160(1b0f3c404d12075c68c938f9f60ebea4f74941a0)),pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "5221036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a002102352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d552ae6482012088a6141b0f3c404d12075c68c938f9f60ebea4f74941a088682103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG, 10, 6);
Test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b2587640350c300b2696782012088aa20939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735886804ff64cd1db1", TESTMODE_VALID, 14, 3);
@@ -263,6 +263,15 @@ BOOST_AUTO_TEST_CASE(fixed_tests)
BOOST_CHECK(ms_multi);
BOOST_CHECK_EQUAL(ms_multi->GetOps(), 4); // 3 pubkeys + CMS
BOOST_CHECK_EQUAL(ms_multi->GetStackSize(), 3); // 1 sig + dummy elem + script push
+ // The 'd:' wrapper leaves on the stack what was DUP'ed at the beginning of its execution.
+ // Since it contains an OP_IF just after on the same element, we can make sure that the element
+ // in question must be OP_1 if OP_IF enforces that its argument must only be OP_1 or the empty
+ // vector (since otherwise the execution would immediately fail). This is the MINIMALIF rule.
+ // Unfortunately, this rule is consensus for Taproot but only policy for P2WSH. Therefore we can't
+ // (for now) have 'd:' be 'u'. This tests we can't use a 'd:' wrapper for a thresh, which requires
+ // its subs to all be 'u' (taken from https://github.com/rust-bitcoin/rust-miniscript/discussions/341).
+ const auto ms_minimalif = miniscript::FromString("thresh(3,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),sc:pk_k(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798),sdv:older(32))", CONVERTER);
+ BOOST_CHECK(!ms_minimalif);
// Timelock tests
Test("after(100)", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only heightlock
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 8e6e911ec2..224dc88d0f 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -5,6 +5,7 @@
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
+#include <netgroup.h>
#include <protocol.h>
#include <serialize.h>
#include <streams.h>
@@ -315,22 +316,22 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_AUTO_TEST_CASE(netbase_getgroup)
{
- std::vector<bool> asmap; // use /16
- BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // Local -> !Routable()
- BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // !Valid -> !Routable()
- BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // RFC1918 -> !Routable()
- BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // RFC3927 -> !Routable()
- BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // IPv4
- BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6145
- BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052
- BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964
- BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380
- BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
- BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
+ NetGroupManager netgroupman{std::vector<bool>()}; // use /16
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("127.0.0.1")) == std::vector<unsigned char>({0})); // Local -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("257.0.0.1")) == std::vector<unsigned char>({0})); // !Valid -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("10.0.0.1")) == std::vector<unsigned char>({0})); // RFC1918 -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("169.254.1.1")) == std::vector<unsigned char>({0})); // RFC3927 -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("1.2.3.4")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // IPv4
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("::FFFF:0:102:304")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6145
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("64:FF9B::102:304")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2002:102:304:9999:9999:9999:9999:9999")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999")) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999")) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
// baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
std::vector<unsigned char> internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07};
- BOOST_CHECK(CreateInternal("baz.net").GetGroup(asmap) == internal_group);
+ BOOST_CHECK(netgroupman.GetGroup(CreateInternal("baz.net")) == internal_group);
}
BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index a9d661438c..3cbbec92d6 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <arith_uint256.h>
#include <consensus/merkle.h>
#include <merkleblock.h>
#include <serialize.h>
@@ -107,13 +106,13 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
BOOST_AUTO_TEST_CASE(pmt_malleability)
{
- std::vector<uint256> vTxid = {
- ArithToUint256(1), ArithToUint256(2),
- ArithToUint256(3), ArithToUint256(4),
- ArithToUint256(5), ArithToUint256(6),
- ArithToUint256(7), ArithToUint256(8),
- ArithToUint256(9), ArithToUint256(10),
- ArithToUint256(9), ArithToUint256(10),
+ std::vector<uint256> vTxid{
+ uint256{1}, uint256{2},
+ uint256{3}, uint256{4},
+ uint256{5}, uint256{6},
+ uint256{7}, uint256{8},
+ uint256{9}, uint256{10},
+ uint256{9}, uint256{10},
};
std::vector<bool> vMatch = {false, false, false, false, false, false, false, false, false, true, true, false};
diff --git a/src/test/util/logging.h b/src/test/util/logging.h
index ebe0ecf623..f477088392 100644
--- a/src/test/util/logging.h
+++ b/src/test/util/logging.h
@@ -36,6 +36,6 @@ public:
~DebugLogHelper() { check_found(); }
};
-#define ASSERT_DEBUG_LOG(message) DebugLogHelper PASTE2(debugloghelper, __COUNTER__)(message)
+#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)
#endif // BITCOIN_TEST_UTIL_LOGGING_H
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 20c45058a1..e980fe4967 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -150,6 +150,8 @@ public:
return 0;
}
+ int SetSockOpt(int, int, const void*, socklen_t) const override { return 0; }
+
bool Wait(std::chrono::milliseconds timeout,
Event requested,
Event* occurred = nullptr) const override
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 211153f06c..1830ec05af 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -15,10 +15,10 @@
#include <interfaces/chain.h>
#include <net.h>
#include <net_processing.h>
-#include <node/miner.h>
-#include <noui.h>
#include <node/blockstorage.h>
#include <node/chainstate.h>
+#include <node/miner.h>
+#include <noui.h>
#include <policy/fees.h>
#include <pow.h>
#include <rpc/blockchain.h>
@@ -28,6 +28,7 @@
#include <script/sigcache.h>
#include <shutdown.h>
#include <streams.h>
+#include <test/util/net.h>
#include <txdb.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -179,6 +180,7 @@ ChainTestingSetup::~ChainTestingSetup()
m_node.connman.reset();
m_node.banman.reset();
m_node.addrman.reset();
+ m_node.netgroupman.reset();
m_node.args = nullptr;
WITH_LOCK(::cs_main, UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman));
m_node.mempool.reset();
@@ -222,11 +224,12 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
}
- m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(),
+ m_node.netgroupman = std::make_unique<NetGroupManager>(/*asmap=*/std::vector<bool>());
+ m_node.addrman = std::make_unique<AddrMan>(*m_node.netgroupman,
/*deterministic=*/false,
m_node.args->GetIntArg("-checkaddrman", 0));
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
+ m_node.connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
m_node.banman.get(), *m_node.chainman,
*m_node.mempool, false);
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index a15094e5c8..74450f591d 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -582,7 +582,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
// _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);
- GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE);
+ GetRandBytes(clientNonce);
_conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), std::bind(&TorController::authchallenge_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
if (status_cookie.first) {
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index f73cc5da5f..65c8b4ea60 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -481,8 +481,6 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
// Update transaction for any feeDelta created by PrioritiseTransaction
- // TODO: refactor so that the fee delta is calculated before inserting
- // into mapTx.
CAmount delta{0};
ApplyDelta(entry.GetTx().GetHash(), delta);
if (delta) {
diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp
index f87d0e04b3..bc060a44c9 100644
--- a/src/util/bytevectorhash.cpp
+++ b/src/util/bytevectorhash.cpp
@@ -8,8 +8,8 @@
ByteVectorHash::ByteVectorHash()
{
- GetRandBytes(reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0));
- GetRandBytes(reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1));
+ GetRandBytes({reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0)});
+ GetRandBytes({reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1)});
}
size_t ByteVectorHash::operator()(const std::vector<unsigned char>& input) const
diff --git a/src/util/epochguard.h b/src/util/epochguard.h
index 0fec7d2624..7f6477fb3b 100644
--- a/src/util/epochguard.h
+++ b/src/util/epochguard.h
@@ -7,6 +7,7 @@
#define BITCOIN_UTIL_EPOCHGUARD_H
#include <threadsafety.h>
+#include <util/macros.h>
#include <cassert>
@@ -96,6 +97,6 @@ public:
}
};
-#define WITH_FRESH_EPOCH(epoch) const Epoch::Guard PASTE2(epoch_guard_, __COUNTER__)(epoch)
+#define WITH_FRESH_EPOCH(epoch) const Epoch::Guard UNIQUE_NAME(epoch_guard_)(epoch)
#endif // BITCOIN_UTIL_EPOCHGUARD_H
diff --git a/src/util/macros.h b/src/util/macros.h
index c9740c8e82..bf6ba665dc 100644
--- a/src/util/macros.h
+++ b/src/util/macros.h
@@ -8,6 +8,8 @@
#define PASTE(x, y) x ## y
#define PASTE2(x, y) PASTE(x, y)
+#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
+
/**
* Converts the parameter X to a string after macro replacement on X has been performed.
* Don't merge these into one macro!
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index 2029d70a37..b5c1e28294 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -105,6 +105,11 @@ int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len)
return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len);
}
+int Sock::SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const
+{
+ return setsockopt(m_socket, level, opt_name, static_cast<const char*>(opt_val), opt_len);
+}
+
bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
{
#ifdef USE_POLL
diff --git a/src/util/sock.h b/src/util/sock.h
index 7510482857..dd2913a66c 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -115,6 +115,16 @@ public:
void* opt_val,
socklen_t* opt_len) const;
+ /**
+ * setsockopt(2) wrapper. Equivalent to
+ * `setsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this
+ * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
+ */
+ [[nodiscard]] virtual int SetSockOpt(int level,
+ int opt_name,
+ const void* opt_val,
+ socklen_t opt_len) const;
+
using Event = uint8_t;
/**
diff --git a/src/util/time.cpp b/src/util/time.cpp
index f7712f0dc8..e428430bac 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -23,16 +23,6 @@ void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread
static std::atomic<int64_t> nMockTime(0); //!< For testing
-int64_t GetTime()
-{
- int64_t mocktime = nMockTime.load(std::memory_order_relaxed);
- if (mocktime) return mocktime;
-
- time_t now = time(nullptr);
- assert(now > 0);
- return now;
-}
-
bool ChronoSanityCheck()
{
// std::chrono::system_clock.time_since_epoch and time_t(0) are not guaranteed
@@ -80,11 +70,12 @@ template <typename T>
T GetTime()
{
const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)};
-
- return std::chrono::duration_cast<T>(
+ const auto ret{
mocktime.count() ?
mocktime :
- std::chrono::microseconds{GetTimeMicros()});
+ std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch())};
+ assert(ret > 0s);
+ return ret;
}
template std::chrono::seconds GetTime();
template std::chrono::milliseconds GetTime();
@@ -129,6 +120,8 @@ int64_t GetTimeSeconds()
return int64_t{GetSystemTime<std::chrono::seconds>().count()};
}
+int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); }
+
std::string FormatISO8601DateTime(int64_t nTime) {
struct tm ts;
time_t time_val = nTime;
diff --git a/src/validation.cpp b/src/validation.cpp
index f4b316f67a..58686632f9 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -69,7 +69,6 @@ using node::CBlockIndexHeightOnlyComparator;
using node::CBlockIndexWorkComparator;
using node::CCoinsStats;
using node::CoinStatsHashType;
-using node::fHavePruned;
using node::fImporting;
using node::fPruneMode;
using node::fReindex;
@@ -120,7 +119,6 @@ const std::vector<std::string> CHECKLEVEL_DOC {
*/
RecursiveMutex cs_main;
-CBlockIndex *pindexBestHeader = nullptr;
Mutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
uint256 g_best_block;
@@ -280,8 +278,9 @@ static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_
return false;
if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
return false;
- if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1)
+ if (active_chainstate.m_chain.Height() < active_chainstate.m_chainman.m_best_header->nHeight - 1) {
return false;
+ }
return true;
}
@@ -1602,8 +1601,8 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
m_chainman.m_best_invalid = pindexNew;
}
- if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) {
- pindexBestHeader = m_chain.Tip();
+ if (m_chainman.m_best_header != nullptr && m_chainman.m_best_header->GetAncestor(pindexNew->nHeight) == pindexNew) {
+ m_chainman.m_best_header = m_chain.Tip();
}
LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__,
@@ -2029,8 +2028,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid);
if (it != m_blockman.m_block_index.end()) {
if (it->second.GetAncestor(pindex->nHeight) == pindex &&
- pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
- pindexBestHeader->nChainWork >= nMinimumChainWork) {
+ m_chainman.m_best_header->GetAncestor(pindex->nHeight) == pindex &&
+ m_chainman.m_best_header->nChainWork >= nMinimumChainWork) {
// This block is a member of the assumed verified chain and an ancestor of the best header.
// Script verification is skipped when connecting blocks under the
// assumevalid block. Assuming the assumevalid block is valid this
@@ -2045,7 +2044,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
// artificially set the default assumed verified block further back.
// The test against nMinimumChainWork prevents the skipping when denied access to any chain at
// least as good as the expected chain.
- fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
+ fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
}
}
}
@@ -2358,9 +2357,9 @@ bool CChainState::FlushStateToDisk(
}
if (!setFilesToPrune.empty()) {
fFlushForPrune = true;
- if (!fHavePruned) {
+ if (!m_blockman.m_have_pruned) {
m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true);
- fHavePruned = true;
+ m_blockman.m_have_pruned = true;
}
}
}
@@ -2904,7 +2903,7 @@ static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) {
CBlockIndex* pindexHeader = nullptr;
{
LOCK(cs_main);
- pindexHeader = pindexBestHeader;
+ pindexHeader = chainstate.m_chainman.m_best_header;
if (pindexHeader != pindexHeaderOld) {
fNotify = true;
@@ -3621,7 +3620,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
}
}
}
- CBlockIndex* pindex{m_blockman.AddToBlockIndex(block)};
+ CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, m_best_header)};
if (ppindex)
*ppindex = pindex;
@@ -4122,13 +4121,11 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
{
AssertLockHeld(::cs_main);
chainman.Unload();
- pindexBestHeader = nullptr;
if (mempool) mempool->clear();
g_versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
warningcache[b].clear();
}
- fHavePruned = false;
}
bool ChainstateManager::LoadBlockIndex()
@@ -4203,6 +4200,8 @@ bool ChainstateManager::LoadBlockIndex()
if (pindex->nStatus & BLOCK_FAILED_MASK && (!m_best_invalid || pindex->nChainWork > m_best_invalid->nChainWork)) {
m_best_invalid = pindex;
}
+ if (pindex->IsValid(BLOCK_VALID_TREE) && (m_best_header == nullptr || CBlockIndexWorkComparator()(m_best_header, pindex)))
+ m_best_header = pindex;
}
needs_init = m_blockman.m_block_index.empty();
@@ -4237,7 +4236,7 @@ bool CChainState::LoadGenesisBlock()
if (blockPos.IsNull()) {
return error("%s: writing genesis block to disk failed", __func__);
}
- CBlockIndex *pindex = m_blockman.AddToBlockIndex(block);
+ CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, m_chainman.m_best_header);
ReceivedBlockTransactions(block, pindex, blockPos);
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
@@ -4448,7 +4447,7 @@ void CChainState::CheckBlockIndex()
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
// Unless these indexes are assumed valid and pending block download on a
// background chainstate.
- if (!fHavePruned && !pindex->IsAssumedValid()) {
+ if (!m_blockman.m_have_pruned && !pindex->IsAssumedValid()) {
// If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
assert(pindexFirstMissing == pindexFirstNeverProcessed);
@@ -4522,7 +4521,7 @@ void CChainState::CheckBlockIndex()
if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked.
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
// We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
- assert(fHavePruned); // We must have pruned.
+ assert(m_blockman.m_have_pruned); // We must have pruned.
// This block may have entered m_blocks_unlinked if:
// - it has a descendant that at some point had more work than the
// tip, and
@@ -5169,6 +5168,7 @@ void ChainstateManager::Unload()
m_failed_blocks.clear();
m_blockman.Unload();
+ m_best_header = nullptr;
m_best_invalid = nullptr;
}
diff --git a/src/validation.h b/src/validation.h
index 53ea2d4aea..2e7ab42f88 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -131,9 +131,6 @@ extern uint256 hashAssumeValid;
/** Minimum work we will assume exists on some valid chain. */
extern arith_uint256 nMinimumChainWork;
-/** Best header we've seen so far (used for getheaders queries' starting points). */
-extern CBlockIndex *pindexBestHeader;
-
/** Documentation for argument 'checklevel'. */
extern const std::vector<std::string> CHECKLEVEL_DOC;
@@ -883,6 +880,9 @@ public:
*/
std::set<CBlockIndex*> m_failed_blocks;
+ /** Best header we've seen so far (used for getheaders queries' starting points). */
+ CBlockIndex* m_best_header = nullptr;
+
//! The total number of bytes available for us to use across all in-memory
//! coins caches. This will be split somehow across chainstates.
int64_t m_total_coinstip_cache{0};
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 4baf16fdcb..1291663847 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -257,7 +257,7 @@ static RPCHelpMan setwalletflag()
{
{RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
{RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
- {RPCResult::Type::STR, "warnings", "Any warnings associated with the change"},
+ {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
}
},
RPCExamples{
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index 166e27bab9..327c28412a 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(passphrase) {
std::string hash(GetRandHash().ToString());
std::vector<unsigned char> vchSalt(8);
- GetRandBytes(vchSalt.data(), vchSalt.size());
+ GetRandBytes(vchSalt);
uint32_t rounds = InsecureRand32();
if (rounds > 30000)
rounds = 30000;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 2a0653c719..0d7075810d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -299,6 +299,13 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
return nullptr;
}
+ // Do not allow a passphrase when private keys are disabled
+ if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
+ status = DatabaseStatus::FAILED_CREATE;
+ return nullptr;
+ }
+
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
if (!database) {
@@ -307,13 +314,6 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
return nullptr;
}
- // Do not allow a passphrase when private keys are disabled
- if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
- status = DatabaseStatus::FAILED_CREATE;
- return nullptr;
- }
-
// Make the wallet
context.chain->initMessage(_("Loading wallet…").translated);
const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings);
@@ -682,12 +682,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
CKeyingMaterial _vMasterKey;
_vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
- GetStrongRandBytes(_vMasterKey.data(), WALLET_CRYPTO_KEY_SIZE);
+ GetStrongRandBytes(_vMasterKey);
CMasterKey kMasterKey;
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
- GetStrongRandBytes(kMasterKey.vchSalt.data(), WALLET_CRYPTO_SALT_SIZE);
+ GetStrongRandBytes(kMasterKey.vchSalt);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
diff --git a/test/README.md b/test/README.md
index 7ff2d6d9f2..e5a184d23c 100644
--- a/test/README.md
+++ b/test/README.md
@@ -305,9 +305,9 @@ Use the `-v` option for verbose output.
| Lint test | Dependency |
|-----------|:----------:|
-| [`lint-python.sh`](lint/lint-python.sh) | [flake8](https://gitlab.com/pycqa/flake8)
-| [`lint-python.sh`](lint/lint-python.sh) | [mypy](https://github.com/python/mypy)
-| [`lint-python.sh`](lint/lint-python.sh) | [pyzmq](https://github.com/zeromq/pyzmq)
+| [`lint-python.py`](lint/lint-python.py) | [flake8](https://gitlab.com/pycqa/flake8)
+| [`lint-python.py`](lint/lint-python.py) | [mypy](https://github.com/python/mypy)
+| [`lint-python.py`](lint/lint-python.py) | [pyzmq](https://github.com/zeromq/pyzmq)
| [`lint-python-dead-code.py`](lint/lint-python-dead-code.py) | [vulture](https://github.com/jendrikseipp/vulture)
| [`lint-shell.sh`](lint/lint-shell.sh) | [ShellCheck](https://github.com/koalaman/shellcheck)
| [`lint-spelling.py`](lint/lint-spelling.py) | [codespell](https://github.com/codespell-project/codespell)
diff --git a/test/config.ini.in b/test/config.ini.in
index d7105c419b..5888ef443b 100644
--- a/test/config.ini.in
+++ b/test/config.ini.in
@@ -19,6 +19,7 @@ RPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py
@USE_SQLITE_TRUE@USE_SQLITE=true
@USE_BDB_TRUE@USE_BDB=true
@BUILD_BITCOIN_CLI_TRUE@ENABLE_CLI=true
+@BUILD_BITCOIN_UTIL_TRUE@ENABLE_BITCOIN_UTIL=true
@BUILD_BITCOIN_WALLET_TRUE@ENABLE_WALLET_TOOL=true
@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true
@ENABLE_FUZZ_TRUE@ENABLE_FUZZ=true
diff --git a/test/functional/README.md b/test/functional/README.md
index 926810cf03..914dbfd977 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -24,7 +24,7 @@ don't have test cases for.
Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version),
to prevent accidentally introducing modern syntax from an unsupported Python version.
The CI linter job also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
-- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that
+- See [the python lint script](/test/lint/lint-python.py) that checks for violations that
could lead to bugs and issues in the test code.
- Use [type hints](https://docs.python.org/3/library/typing.html) in your code to improve code readability
and to detect possible bugs earlier.
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 233ffd60da..422612a78e 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -3,25 +3,13 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test fee estimation code."""
+from copy import deepcopy
from decimal import Decimal
import os
import random
from test_framework.messages import (
COIN,
- COutPoint,
- CTransaction,
- CTxIn,
- CTxOut,
-)
-from test_framework.script import (
- CScript,
- OP_1,
- OP_DROP,
- OP_TRUE,
-)
-from test_framework.script_util import (
- script_to_p2sh_script,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -31,22 +19,14 @@ from test_framework.util import (
assert_raises_rpc_error,
satoshi_round,
)
-
-# Construct 2 trivial P2SH's and the ScriptSigs that spend them
-# So we can create many transactions without needing to spend
-# time signing.
-SCRIPT = CScript([OP_1, OP_DROP])
-P2SH = script_to_p2sh_script(SCRIPT)
-REDEEM_SCRIPT = CScript([OP_TRUE, SCRIPT])
+from test_framework.wallet import MiniWallet
def small_txpuzzle_randfee(
- from_node, conflist, unconflist, amount, min_fee, fee_increment
+ wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment
):
- """Create and send a transaction with a random fee.
+ """Create and send a transaction with a random fee using MiniWallet.
- The transaction pays to a trivial P2SH script, and assumes that its inputs
- are of the same form.
The function takes a list of confirmed outputs and unconfirmed outputs
and attempts to use the confirmed list first for its inputs.
It adds the newly created outputs to the unconfirmed list.
@@ -58,23 +38,29 @@ def small_txpuzzle_randfee(
rand_fee = float(fee_increment) * (1.1892 ** random.randint(0, 28))
# Total fee ranges from min_fee to min_fee + 127*fee_increment
fee = min_fee - fee_increment + satoshi_round(rand_fee)
- tx = CTransaction()
+ utxos_to_spend = []
total_in = Decimal("0.00000000")
while total_in <= (amount + fee) and len(conflist) > 0:
t = conflist.pop(0)
- total_in += t["amount"]
- tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), REDEEM_SCRIPT))
+ total_in += t["value"]
+ utxos_to_spend.append(t)
while total_in <= (amount + fee) and len(unconflist) > 0:
t = unconflist.pop(0)
- total_in += t["amount"]
- tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), REDEEM_SCRIPT))
+ total_in += t["value"]
+ utxos_to_spend.append(t)
if total_in <= amount + fee:
raise RuntimeError(f"Insufficient funds: need {amount + fee}, have {total_in}")
- tx.vout.append(CTxOut(int((total_in - amount - fee) * COIN), P2SH))
- tx.vout.append(CTxOut(int(amount * COIN), P2SH))
+ tx = wallet.create_self_transfer_multi(
+ from_node=from_node,
+ utxos_to_spend=utxos_to_spend,
+ fee_per_output=0)
+ tx.vout[0].nValue = int((total_in - amount - fee) * COIN)
+ tx.vout.append(deepcopy(tx.vout[0]))
+ tx.vout[1].nValue = int(amount * COIN)
+
txid = from_node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
- unconflist.append({"txid": txid, "vout": 0, "amount": total_in - amount - fee})
- unconflist.append({"txid": txid, "vout": 1, "amount": amount})
+ unconflist.append({"txid": txid, "vout": 0, "value": total_in - amount - fee})
+ unconflist.append({"txid": txid, "vout": 1, "value": amount})
return (tx.serialize().hex(), fee)
@@ -129,17 +115,13 @@ def check_estimates(node, fees_seen):
check_smart_estimates(node, fees_seen)
-def send_tx(node, utxo, feerate):
+def send_tx(wallet, node, utxo, feerate):
"""Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb)."""
- tx = CTransaction()
- tx.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), REDEEM_SCRIPT)]
- tx.vout = [CTxOut(int(utxo["amount"] * COIN), P2SH)]
-
- # vbytes == bytes as we are using legacy transactions
- fee = tx.get_vsize() * feerate
- tx.vout[0].nValue -= fee
-
- return node.sendrawtransaction(tx.serialize().hex())
+ return wallet.send_self_transfer(
+ from_node=node,
+ utxo_to_spend=utxo,
+ fee_rate=Decimal(feerate * 1000) / COIN,
+ )['txid']
class EstimateFeeTest(BitcoinTestFramework):
@@ -152,9 +134,6 @@ class EstimateFeeTest(BitcoinTestFramework):
["-whitelist=noban@127.0.0.1", "-blockmaxweight=32000"],
]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def setup_network(self):
"""
We'll setup the network to have 3 nodes that all mine with different parameters.
@@ -168,9 +147,6 @@ class EstimateFeeTest(BitcoinTestFramework):
# (68k weight is room enough for 120 or so transactions)
# Node2 is a stingy miner, that
# produces too small blocks (room for only 55 or so transactions)
- self.start_nodes()
- self.import_deterministic_coinbase_privkeys()
- self.stop_nodes()
def transact_and_mine(self, numblocks, mining_node):
min_fee = Decimal("0.00001")
@@ -183,6 +159,7 @@ class EstimateFeeTest(BitcoinTestFramework):
for _ in range(random.randrange(100 - 50, 100 + 50)):
from_index = random.randint(1, 2)
(txhex, fee) = small_txpuzzle_randfee(
+ self.wallet,
self.nodes[from_index],
self.confutxo,
self.memutxo,
@@ -205,24 +182,10 @@ class EstimateFeeTest(BitcoinTestFramework):
def initial_split(self, node):
"""Split two coinbase UTxOs into many small coins"""
- utxo_count = 2048
- self.confutxo = []
- splitted_amount = Decimal("0.04")
- fee = Decimal("0.1")
- change = Decimal("100") - splitted_amount * utxo_count - fee
- tx = CTransaction()
- tx.vin = [
- CTxIn(COutPoint(int(cb["txid"], 16), cb["vout"]))
- for cb in node.listunspent()[:2]
- ]
- tx.vout = [CTxOut(int(splitted_amount * COIN), P2SH) for _ in range(utxo_count)]
- tx.vout.append(CTxOut(int(change * COIN), P2SH))
- txhex = node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
- txid = node.sendrawtransaction(txhex)
- self.confutxo = [
- {"txid": txid, "vout": i, "amount": splitted_amount}
- for i in range(utxo_count)
- ]
+ self.confutxo = self.wallet.send_self_transfer_multi(
+ from_node=node,
+ utxos_to_spend=[self.wallet.get_utxo() for _ in range(2)],
+ num_outputs=2048)['new_utxos']
while len(node.getrawmempool()) > 0:
self.generate(node, 1, sync_fun=self.no_op)
@@ -284,12 +247,12 @@ class EstimateFeeTest(BitcoinTestFramework):
# Broadcast 45 low fee transactions that will need to be RBF'd
for _ in range(45):
u = utxos.pop(0)
- txid = send_tx(node, u, low_feerate)
+ txid = send_tx(self.wallet, node, u, low_feerate)
utxos_to_respend.append(u)
txids_to_replace.append(txid)
# Broadcast 5 low fee transaction which don't need to
for _ in range(5):
- send_tx(node, utxos.pop(0), low_feerate)
+ send_tx(self.wallet, node, utxos.pop(0), low_feerate)
# Mine the transactions on another node
self.sync_mempools(wait=0.1, nodes=[node, miner])
for txid in txids_to_replace:
@@ -298,7 +261,7 @@ class EstimateFeeTest(BitcoinTestFramework):
# RBF the low-fee transactions
while len(utxos_to_respend) > 0:
u = utxos_to_respend.pop(0)
- send_tx(node, u, high_feerate)
+ send_tx(self.wallet, node, u, high_feerate)
# Mine the last replacement txs
self.sync_mempools(wait=0.1, nodes=[node, miner])
@@ -316,6 +279,8 @@ class EstimateFeeTest(BitcoinTestFramework):
# Split two coinbases into many small utxos
self.start_node(0)
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.rescan_utxos()
self.initial_split(self.nodes[0])
self.log.info("Finished splitting")
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index 4f8676ec53..95dc40cb52 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -326,6 +326,10 @@ class RESTTest (BitcoinTestFramework):
# Check that there are our submitted transactions in the TX memory pool
json_obj = self.test_rest_request("/mempool/contents")
+ raw_mempool_verbose = self.nodes[0].getrawmempool(verbose=True)
+
+ assert_equal(json_obj, raw_mempool_verbose)
+
for i, tx in enumerate(txs):
assert tx in json_obj
assert_equal(json_obj[tx]['spentby'], txs[i + 1:i + 2])
@@ -361,6 +365,10 @@ class RESTTest (BitcoinTestFramework):
json_obj = self.test_rest_request("/chaininfo")
assert_equal(json_obj['bestblockhash'], bb_hash)
+ # Compare with normal RPC getblockchaininfo response
+ blockchain_info = self.nodes[0].getblockchaininfo()
+ assert_equal(blockchain_info, json_obj)
+
# Test compatibility of deprecated and newer endpoints
self.log.info("Test compatibility of deprecated and newer endpoints")
assert_equal(self.test_rest_request(f"/headers/{bb_hash}", query_params={"count": 1}), self.test_rest_request(f"/headers/1/{bb_hash}"))
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index f377fbaaa6..89ddfd3bcf 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -43,7 +43,6 @@ from test_framework.messages import (
ser_uint256,
ser_vector,
sha256,
- tx_from_hex,
)
from test_framework.p2p import (
P2PInterface,
@@ -89,6 +88,8 @@ from test_framework.util import (
softfork_active,
assert_raises_rpc_error,
)
+from test_framework.wallet import MiniWallet
+
MAX_SIGOP_COST = 80000
@@ -221,9 +222,6 @@ class SegWitTest(BitcoinTestFramework):
]
self.supports_cli = False
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
# Helper functions
def build_next_block(self):
@@ -259,6 +257,7 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Starting tests before segwit activation")
self.segwit_active = False
+ self.wallet = MiniWallet(self.nodes[0])
self.test_non_witness_transaction()
self.test_v0_outputs_arent_spendable()
@@ -307,7 +306,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.send_and_ping(msg_no_witness_block(block)) # make sure the block was processed
txid = block.vtx[0].sha256
- self.generate(self.nodes[0], 99) # let the block mature
+ self.generate(self.wallet, 99) # let the block mature
# Create a transaction that spends the coinbase
tx = CTransaction()
@@ -1999,21 +1998,13 @@ class SegWitTest(BitcoinTestFramework):
def serialize(self):
return serialize_with_bogus_witness(self.tx)
- self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(address_type='bech32'), 5)
- self.generate(self.nodes[0], 1)
- unspent = next(u for u in self.nodes[0].listunspent() if u['spendable'] and u['address'].startswith('bcrt'))
-
- raw = self.nodes[0].createrawtransaction([{"txid": unspent['txid'], "vout": unspent['vout']}], {self.nodes[0].getnewaddress(): 1})
- tx = tx_from_hex(raw)
+ tx = self.wallet.create_self_transfer(from_node=self.nodes[0])['tx']
assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, hexstring=serialize_with_bogus_witness(tx).hex(), iswitness=True)
- with self.nodes[0].assert_debug_log(['Superfluous witness record']):
+ with self.nodes[0].assert_debug_log(['Unknown transaction optional data']):
self.test_node.send_and_ping(msg_bogus_tx(tx))
- raw = self.nodes[0].signrawtransactionwithwallet(raw)
- assert raw['complete']
- raw = raw['hex']
- tx = tx_from_hex(raw)
+ tx.wit.vtxinwit = [] # drop witness
assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, hexstring=serialize_with_bogus_witness(tx).hex(), iswitness=True)
- with self.nodes[0].assert_debug_log(['Unknown transaction optional data']):
+ with self.nodes[0].assert_debug_log(['Superfluous witness record']):
self.test_node.send_and_ping(msg_bogus_tx(tx))
@subtest
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 2fb9ec0942..a39ee003ef 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -244,8 +244,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"src",
"bitcoin-cli" + config["environment"]["EXEEXT"],
)
+ fname_bitcoinutil = os.path.join(
+ config["environment"]["BUILDDIR"],
+ "src",
+ "bitcoin-util" + config["environment"]["EXEEXT"],
+ )
self.options.bitcoind = os.getenv("BITCOIND", default=fname_bitcoind)
self.options.bitcoincli = os.getenv("BITCOINCLI", default=fname_bitcoincli)
+ self.options.bitcoinutil = os.getenv("BITCOINUTIL", default=fname_bitcoinutil)
os.environ['PATH'] = os.pathsep.join([
os.path.join(config['environment']['BUILDDIR'], 'src'),
@@ -880,6 +886,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
if not self.is_wallet_tool_compiled():
raise SkipTest("bitcoin-wallet has not been compiled")
+ def skip_if_no_bitcoin_util(self):
+ """Skip the running test if bitcoin-util has not been compiled."""
+ if not self.is_bitcoin_util_compiled():
+ raise SkipTest("bitcoin-util has not been compiled")
+
def skip_if_no_cli(self):
"""Skip the running test if bitcoin-cli has not been compiled."""
if not self.is_cli_compiled():
@@ -927,6 +938,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""Checks whether bitcoin-wallet was compiled."""
return self.config["components"].getboolean("ENABLE_WALLET_TOOL")
+ def is_bitcoin_util_compiled(self):
+ """Checks whether bitcoin-util was compiled."""
+ return self.config["components"].getboolean("ENABLE_BITCOIN_UTIL")
+
def is_zmq_compiled(self):
"""Checks whether the zmq module was compiled."""
return self.config["components"].getboolean("ENABLE_ZMQ")
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1f0f806d91..a3c938ae26 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -145,6 +145,8 @@ BASE_SCRIPTS = [
'wallet_txn_doublespend.py --mineblock',
'tool_wallet.py --legacy-wallet',
'tool_wallet.py --descriptors',
+ 'tool_signet_miner.py --legacy-wallet',
+ 'tool_signet_miner.py --descriptors',
'wallet_txn_clone.py',
'wallet_txn_clone.py --segwit',
'rpc_getchaintips.py',
diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py
new file mode 100755
index 0000000000..e6fc9072ab
--- /dev/null
+++ b/test/functional/tool_signet_miner.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test signet miner tool"""
+
+import os.path
+import subprocess
+import sys
+import time
+
+from test_framework.key import ECKey
+from test_framework.script_util import key_to_p2wpkh_script
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+from test_framework.wallet_util import bytes_to_wif
+
+
+CHALLENGE_PRIVATE_KEY = (42).to_bytes(32, 'big')
+
+
+class SignetMinerTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.chain = "signet"
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ # generate and specify signet challenge (simple p2wpkh script)
+ privkey = ECKey()
+ privkey.set(CHALLENGE_PRIVATE_KEY, True)
+ pubkey = privkey.get_pubkey().get_bytes()
+ challenge = key_to_p2wpkh_script(pubkey)
+ self.extra_args = [[f'-signetchallenge={challenge.hex()}']]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_cli()
+ self.skip_if_no_wallet()
+ self.skip_if_no_bitcoin_util()
+
+ def run_test(self):
+ node = self.nodes[0]
+ # import private key needed for signing block
+ node.importprivkey(bytes_to_wif(CHALLENGE_PRIVATE_KEY))
+
+ # generate block with signet miner tool
+ base_dir = self.config["environment"]["SRCDIR"]
+ signet_miner_path = os.path.join(base_dir, "contrib", "signet", "miner")
+ subprocess.run([
+ sys.executable,
+ signet_miner_path,
+ f'--cli={node.cli.binary} -datadir={node.cli.datadir}',
+ 'generate',
+ f'--address={node.getnewaddress()}',
+ f'--grind-cmd={self.options.bitcoinutil} grind',
+ '--nbits=1d00ffff',
+ f'--set-block-time={int(time.time())}',
+ ], check=True, stderr=subprocess.STDOUT)
+ assert_equal(node.getblockcount(), 1)
+
+
+if __name__ == "__main__":
+ SignetMinerTest().main()
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index dc823c2c60..f663666f57 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -118,6 +118,17 @@ class AvoidReuseTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Wallet flag is already set to false", self.nodes[0].setwalletflag, 'avoid_reuse', False)
assert_raises_rpc_error(-8, "Wallet flag is already set to true", self.nodes[1].setwalletflag, 'avoid_reuse', True)
+ # Create a wallet with avoid reuse, and test that disabling it afterwards persists
+ self.nodes[1].createwallet(wallet_name="avoid_reuse_persist", avoid_reuse=True)
+ w = self.nodes[1].get_wallet_rpc("avoid_reuse_persist")
+ assert_equal(w.getwalletinfo()["avoid_reuse"], True)
+ w.setwalletflag("avoid_reuse", False)
+ assert_equal(w.getwalletinfo()["avoid_reuse"], False)
+ w.unloadwallet()
+ self.nodes[1].loadwallet("avoid_reuse_persist")
+ assert_equal(w.getwalletinfo()["avoid_reuse"], False)
+ w.unloadwallet()
+
def test_immutable(self):
'''Test immutable wallet flags'''
self.log.info("Test immutable wallet flags")
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index e8234de032..dcf2e98638 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -26,6 +26,11 @@ class CreateWalletTest(BitcoinTestFramework):
node = self.nodes[0]
self.generate(node, 1) # Leave IBD for sethdseed
+ self.log.info("Run createwallet with invalid parameters.")
+ # Run createwallet with invalid parameters. This must not prevent a new wallet with the same name from being created with the correct parameters.
+ assert_raises_rpc_error(-4, "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.",
+ self.nodes[0].createwallet, wallet_name='w0', descriptors=True, disable_private_keys=True, passphrase="passphrase")
+
self.nodes[0].createwallet(wallet_name='w0')
w0 = node.get_wallet_rpc('w0')
address1 = w0.getnewaddress()
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index d3731b135a..41bb86f962 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -192,9 +192,9 @@ class WalletTaprootTest(BitcoinTestFramework):
"""Test generation and spending of P2TR address outputs."""
def set_test_params(self):
- self.num_nodes = 3
+ self.num_nodes = 2
self.setup_clean_chain = True
- self.extra_args = [['-keypool=100'], ['-keypool=100'], ["-vbparams=taproot:1:1"]]
+ self.extra_args = [['-keypool=100'], ['-keypool=100']]
self.supports_cli = False
def skip_test_if_missing_module(self):
@@ -243,15 +243,11 @@ class WalletTaprootTest(BitcoinTestFramework):
assert_equal(len(rederive), 1)
assert_equal(rederive[0], addr_g)
- # tr descriptors can be imported regardless of Taproot status
+ # tr descriptors can be imported
result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert(result[0]["success"])
result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
assert(result[0]["success"])
- result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
- assert result[0]["success"]
- result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
- assert result[0]["success"]
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through sendtoaddress" % comment)
@@ -328,12 +324,8 @@ class WalletTaprootTest(BitcoinTestFramework):
self.log.info("Creating wallets...")
self.nodes[0].createwallet(wallet_name="privs_tr_enabled", descriptors=True, blank=True)
self.privs_tr_enabled = self.nodes[0].get_wallet_rpc("privs_tr_enabled")
- self.nodes[2].createwallet(wallet_name="privs_tr_disabled", descriptors=True, blank=True)
- self.privs_tr_disabled=self.nodes[2].get_wallet_rpc("privs_tr_disabled")
self.nodes[0].createwallet(wallet_name="pubs_tr_enabled", descriptors=True, blank=True, disable_private_keys=True)
self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
- self.nodes[2].createwallet(wallet_name="pubs_tr_disabled", descriptors=True, blank=True, disable_private_keys=True)
- self.pubs_tr_disabled=self.nodes[2].get_wallet_rpc("pubs_tr_disabled")
self.nodes[0].createwallet(wallet_name="boring")
self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
self.nodes[0].createwallet(wallet_name="rpc_online", descriptors=True, blank=True)
diff --git a/test/lint/lint-git-commit-check.py b/test/lint/lint-git-commit-check.py
new file mode 100755
index 0000000000..a1d03370e8
--- /dev/null
+++ b/test/lint/lint-git-commit-check.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2020-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.
+#
+# Linter to check that commit messages have a new line before the body
+# or no body at all
+
+import argparse
+import os
+import sys
+
+from subprocess import check_output
+
+
+def parse_args():
+ """Parse command line arguments."""
+ parser = argparse.ArgumentParser(
+ description="""
+ Linter to check that commit messages have a new line before
+ the body or no body at all.
+ """,
+ epilog=f"""
+ You can manually set the commit-range with the COMMIT_RANGE
+ environment variable (e.g. "COMMIT_RANGE='47ba2c3...ee50c9e'
+ {sys.argv[0]}"). Defaults to current merge base when neither
+ prev-commits nor the environment variable is set.
+ """)
+
+ parser.add_argument("--prev-commits", "-p", required=False, help="The previous n commits to check")
+
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+ exit_code = 0
+
+ if not os.getenv("COMMIT_RANGE"):
+ if args.prev_commits:
+ commit_range = "HEAD~" + args.prev_commits + "...HEAD"
+ else:
+ # This assumes that the target branch of the pull request will be master.
+ merge_base = check_output(["git", "merge-base", "HEAD", "master"], universal_newlines=True, encoding="utf8").rstrip("\n")
+ commit_range = merge_base + "..HEAD"
+ else:
+ commit_range = os.getenv("COMMIT_RANGE")
+
+ commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], universal_newlines=True, encoding="utf8").splitlines()
+
+ for hash in commit_hashes:
+ commit_info = check_output(["git", "log", "--format=%B", "-n", "1", hash], universal_newlines=True, encoding="utf8").splitlines()
+ if len(commit_info) >= 2:
+ if commit_info[1]:
+ print(f"The subject line of commit hash {hash} is followed by a non-empty line. Subject lines should always be followed by a blank line.")
+ exit_code = 1
+
+ sys.exit(exit_code)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh
deleted file mode 100755
index f77373ed00..0000000000
--- a/test/lint/lint-git-commit-check.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2020-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.
-#
-# Linter to check that commit messages have a new line before the body
-# or no body at all
-
-export LC_ALL=C
-
-EXIT_CODE=0
-
-while getopts "?" opt; do
- case $opt in
- ?)
- echo "Usage: $0 [N]"
- echo " COMMIT_RANGE='<commit range>' $0"
- echo " $0 -?"
- echo "Checks unmerged commits, the previous N commits, or a commit range."
- echo "COMMIT_RANGE='47ba2c3...ee50c9e' $0"
- exit ${EXIT_CODE}
- ;;
- esac
-done
-
-if [ -z "${COMMIT_RANGE}" ]; then
- if [ -n "$1" ]; then
- COMMIT_RANGE="HEAD~$1...HEAD"
- else
- # This assumes that the target branch of the pull request will be master.
- MERGE_BASE=$(git merge-base HEAD master)
- COMMIT_RANGE="$MERGE_BASE..HEAD"
- fi
-fi
-
-while IFS= read -r commit_hash || [[ -n "$commit_hash" ]]; do
- n_line=0
- while IFS= read -r line || [[ -n "$line" ]]; do
- n_line=$((n_line+1))
- length=${#line}
- if [ $n_line -eq 2 ] && [ "$length" -ne 0 ]; then
- echo "The subject line of commit hash ${commit_hash} is followed by a non-empty line. Subject lines should always be followed by a blank line."
- EXIT_CODE=1
- fi
- done < <(git log --format=%B -n 1 "$commit_hash")
-done < <(git log "${COMMIT_RANGE}" --format=%H)
-
-exit ${EXIT_CODE}
diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py
new file mode 100755
index 0000000000..b29c7f8b4d
--- /dev/null
+++ b/test/lint/lint-includes.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2018-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.
+#
+# Check for duplicate includes.
+# Guard against accidental introduction of new Boost dependencies.
+# Check includes: Check for duplicate includes. Enforce bracket syntax includes.
+
+import os
+import re
+import sys
+
+from subprocess import check_output, CalledProcessError
+
+
+EXCLUDED_DIRS = ["src/leveldb/",
+ "src/crc32c/",
+ "src/secp256k1/",
+ "src/minisketch/",
+ "src/univalue/"]
+
+EXPECTED_BOOST_INCLUDES = ["boost/algorithm/string.hpp",
+ "boost/algorithm/string/classification.hpp",
+ "boost/algorithm/string/replace.hpp",
+ "boost/algorithm/string/split.hpp",
+ "boost/date_time/posix_time/posix_time.hpp",
+ "boost/multi_index/hashed_index.hpp",
+ "boost/multi_index/ordered_index.hpp",
+ "boost/multi_index/sequenced_index.hpp",
+ "boost/multi_index_container.hpp",
+ "boost/process.hpp",
+ "boost/signals2/connection.hpp",
+ "boost/signals2/optional_last_value.hpp",
+ "boost/signals2/signal.hpp",
+ "boost/test/included/unit_test.hpp",
+ "boost/test/unit_test.hpp"]
+
+
+def get_toplevel():
+ return check_output(["git", "rev-parse", "--show-toplevel"], universal_newlines=True, encoding="utf8").rstrip("\n")
+
+
+def list_files_by_suffix(suffixes):
+ exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS]
+
+ files_list = check_output(["git", "ls-files", "src"] + exclude_args, universal_newlines=True, encoding="utf8").splitlines()
+
+ return [file for file in files_list if file.endswith(suffixes)]
+
+
+def find_duplicate_includes(include_list):
+ tempset = set()
+ duplicates = set()
+
+ for inclusion in include_list:
+ if inclusion in tempset:
+ duplicates.add(inclusion)
+ else:
+ tempset.add(inclusion)
+
+ return duplicates
+
+
+def find_included_cpps():
+ included_cpps = list()
+
+ try:
+ included_cpps = check_output(["git", "grep", "-E", r"^#include [<\"][^>\"]+\.cpp[>\"]", "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8").splitlines()
+ except CalledProcessError as e:
+ if e.returncode > 1:
+ raise e
+
+ return included_cpps
+
+
+def find_extra_boosts():
+ included_boosts = list()
+ filtered_included_boost_set = set()
+ exclusion_set = set()
+
+ try:
+ included_boosts = check_output(["git", "grep", "-E", r"^#include <boost/", "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8").splitlines()
+ except CalledProcessError as e:
+ if e.returncode > 1:
+ raise e
+
+ for boost in included_boosts:
+ filtered_included_boost_set.add(re.findall(r'(?<=\<).+?(?=\>)', boost)[0])
+
+ for expected_boost in EXPECTED_BOOST_INCLUDES:
+ for boost in filtered_included_boost_set:
+ if expected_boost in boost:
+ exclusion_set.add(boost)
+
+ extra_boosts = set(filtered_included_boost_set.difference(exclusion_set))
+
+ return extra_boosts
+
+
+def find_quote_syntax_inclusions():
+ exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS]
+ quote_syntax_inclusions = list()
+
+ try:
+ quote_syntax_inclusions = check_output(["git", "grep", r"^#include \"", "--", "*.cpp", "*.h"] + exclude_args, universal_newlines=True, encoding="utf8").splitlines()
+ except CalledProcessError as e:
+ if e.returncode > 1:
+ raise e
+
+ return quote_syntax_inclusions
+
+
+def main():
+ exit_code = 0
+
+ os.chdir(get_toplevel())
+
+ # Check for duplicate includes
+ for filename in list_files_by_suffix((".cpp", ".h")):
+ with open(filename, "r", encoding="utf8") as file:
+ include_list = [line.rstrip("\n") for line in file if re.match(r"^#include", line)]
+
+ duplicates = find_duplicate_includes(include_list)
+
+ if duplicates:
+ print(f"Duplicate include(s) in {filename}:")
+ for duplicate in duplicates:
+ print(duplicate)
+ print("")
+ exit_code = 1
+
+ # Check if code includes .cpp-files
+ included_cpps = find_included_cpps()
+
+ if included_cpps:
+ print("The following files #include .cpp files:")
+ for included_cpp in included_cpps:
+ print(included_cpp)
+ print("")
+ exit_code = 1
+
+ # Guard against accidental introduction of new Boost dependencies
+ extra_boosts = find_extra_boosts()
+
+ if extra_boosts:
+ for boost in extra_boosts:
+ print(f"A new Boost dependency in the form of \"{boost}\" appears to have been introduced:")
+ print(check_output(["git", "grep", boost, "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8"))
+ exit_code = 1
+
+ # Check if Boost dependencies are no longer used
+ for expected_boost in EXPECTED_BOOST_INCLUDES:
+ try:
+ check_output(["git", "grep", "-q", r"^#include <%s>" % expected_boost, "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8")
+ except CalledProcessError as e:
+ if e.returncode > 1:
+ raise e
+ else:
+ print(f"Good job! The Boost dependency \"{expected_boost}\" is no longer used. "
+ "Please remove it from EXPECTED_BOOST_INCLUDES in test/lint/lint-includes.py "
+ "to make sure this dependency is not accidentally reintroduced.\n")
+ exit_code = 1
+
+ # Enforce bracket syntax includes
+ quote_syntax_inclusions = find_quote_syntax_inclusions()
+
+ if quote_syntax_inclusions:
+ print("Please use bracket syntax includes (\"#include <foo.h>\") instead of quote syntax includes:")
+ for quote_syntax_inclusion in quote_syntax_inclusions:
+ print(quote_syntax_inclusion)
+ exit_code = 1
+
+ sys.exit(exit_code)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
deleted file mode 100755
index 9e72831ee9..0000000000
--- a/test/lint/lint-includes.sh
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-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.
-#
-# Check for duplicate includes.
-# Guard against accidental introduction of new Boost dependencies.
-# Check includes: Check for duplicate includes. Enforce bracket syntax includes.
-
-export LC_ALL=C
-IGNORE_REGEXP="/(leveldb|secp256k1|minisketch|univalue|crc32c)/"
-
-# cd to root folder of git repo for git ls-files to work properly
-cd "$(dirname "$0")/../.." || exit 1
-
-filter_suffix() {
- git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "${IGNORE_REGEXP}"
-}
-
-EXIT_CODE=0
-
-for HEADER_FILE in $(filter_suffix h); do
- DUPLICATE_INCLUDES_IN_HEADER_FILE=$(grep -E "^#include " < "${HEADER_FILE}" | sort | uniq -d)
- if [[ ${DUPLICATE_INCLUDES_IN_HEADER_FILE} != "" ]]; then
- echo "Duplicate include(s) in ${HEADER_FILE}:"
- echo "${DUPLICATE_INCLUDES_IN_HEADER_FILE}"
- echo
- EXIT_CODE=1
- fi
-done
-
-for CPP_FILE in $(filter_suffix cpp); do
- DUPLICATE_INCLUDES_IN_CPP_FILE=$(grep -E "^#include " < "${CPP_FILE}" | sort | uniq -d)
- if [[ ${DUPLICATE_INCLUDES_IN_CPP_FILE} != "" ]]; then
- echo "Duplicate include(s) in ${CPP_FILE}:"
- echo "${DUPLICATE_INCLUDES_IN_CPP_FILE}"
- echo
- EXIT_CODE=1
- fi
-done
-
-INCLUDED_CPP_FILES=$(git grep -E "^#include [<\"][^>\"]+\.cpp[>\"]" -- "*.cpp" "*.h")
-if [[ ${INCLUDED_CPP_FILES} != "" ]]; then
- echo "The following files #include .cpp files:"
- echo "${INCLUDED_CPP_FILES}"
- echo
- EXIT_CODE=1
-fi
-
-EXPECTED_BOOST_INCLUDES=(
- boost/algorithm/string.hpp
- boost/algorithm/string/classification.hpp
- boost/algorithm/string/replace.hpp
- boost/algorithm/string/split.hpp
- boost/date_time/posix_time/posix_time.hpp
- boost/multi_index/hashed_index.hpp
- boost/multi_index/ordered_index.hpp
- boost/multi_index/sequenced_index.hpp
- boost/multi_index_container.hpp
- boost/process.hpp
- boost/signals2/connection.hpp
- boost/signals2/optional_last_value.hpp
- boost/signals2/signal.hpp
- boost/test/included/unit_test.hpp
- boost/test/unit_test.hpp
-)
-
-for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do
- IS_EXPECTED_INCLUDE=0
- for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do
- if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then
- IS_EXPECTED_INCLUDE=1
- break
- fi
- done
- if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then
- EXIT_CODE=1
- echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:"
- git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h"
- echo
- fi
-done
-
-for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do
- if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then
- echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used."
- echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0"
- echo "to make sure this dependency is not accidentally reintroduced."
- echo
- EXIT_CODE=1
- fi
-done
-
-QUOTE_SYNTAX_INCLUDES=$(git grep '^#include "' -- "*.cpp" "*.h" | grep -Ev "${IGNORE_REGEXP}")
-if [[ ${QUOTE_SYNTAX_INCLUDES} != "" ]]; then
- echo "Please use bracket syntax includes (\"#include <foo.h>\") instead of quote syntax includes:"
- echo "${QUOTE_SYNTAX_INCLUDES}"
- echo
- EXIT_CODE=1
-fi
-
-exit ${EXIT_CODE}
diff --git a/test/lint/lint-logs.py b/test/lint/lint-logs.py
new file mode 100755
index 0000000000..e6c4c068fb
--- /dev/null
+++ b/test/lint/lint-logs.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2018-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.
+#
+# Check that all logs are terminated with '\n'
+#
+# Some logs are continued over multiple lines. They should be explicitly
+# commented with /* Continued */
+
+import re
+import sys
+
+from subprocess import check_output
+
+
+def main():
+ logs_list = check_output(["git", "grep", "--extended-regexp", r"LogPrintf?\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines()
+
+ unterminated_logs = [line for line in logs_list if not re.search(r'(\\n"|/\* Continued \*/)', line)]
+
+ if unterminated_logs != []:
+ print("All calls to LogPrintf() and LogPrint() should be terminated with \\n")
+ print("")
+
+ for line in unterminated_logs:
+ print(line)
+
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh
deleted file mode 100755
index 6d5165f649..0000000000
--- a/test/lint/lint-logs.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-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.
-#
-# Check that all logs are terminated with '\n'
-#
-# Some logs are continued over multiple lines. They should be explicitly
-# commented with /* Continued */
-#
-# There are some instances of LogPrintf() in comments. Those can be
-# ignored
-
-export LC_ALL=C
-UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \
- grep -v '\\n"' | \
- grep -v '\.\.\.' | \
- grep -v "/\* Continued \*/" | \
- grep -v "LogPrint()" | \
- grep -v "LogPrintf()")
-if [[ ${UNTERMINATED_LOGS} != "" ]]; then
- # shellcheck disable=SC2028
- echo "All calls to LogPrintf() and LogPrint() should be terminated with \\n"
- echo
- echo "${UNTERMINATED_LOGS}"
- exit 1
-fi
diff --git a/test/lint/lint-python-mutable-default-parameters.py b/test/lint/lint-python-mutable-default-parameters.py
new file mode 100755
index 0000000000..7991e3630b
--- /dev/null
+++ b/test/lint/lint-python-mutable-default-parameters.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2019 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+"""
+Detect when a mutable list or dict is used as a default parameter value in a Python function.
+"""
+
+import subprocess
+import sys
+
+
+def main():
+ command = [
+ "git",
+ "grep",
+ "-E",
+ r"^\s*def [a-zA-Z0-9_]+\(.*=\s*(\[|\{)",
+ "--",
+ "*.py",
+ ]
+ output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
+ if len(output.stdout) > 0:
+ error_msg = (
+ "A mutable list or dict seems to be used as default parameter value:\n\n"
+ f"{output.stdout}\n"
+ f"{example()}"
+ )
+ print(error_msg)
+ sys.exit(1)
+ else:
+ sys.exit(0)
+
+
+def example():
+ return """This is how mutable list and dict default parameter values behave:
+
+>>> def f(i, j=[], k={}):
+... j.append(i)
+... k[i] = True
+... return j, k
+...
+>>> f(1)
+([1], {1: True})
+>>> f(1)
+([1, 1], {1: True})
+>>> f(2)
+([1, 1, 2], {1: True, 2: True})
+
+The intended behaviour was likely:
+
+>>> def f(i, j=None, k=None):
+... if j is None:
+... j = []
+... if k is None:
+... k = {}
+... j.append(i)
+... k[i] = True
+... return j, k
+...
+>>> f(1)
+([1], {1: True})
+>>> f(1)
+([1], {1: True})
+>>> f(2)
+([2], {2: True})"""
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-python-mutable-default-parameters.sh b/test/lint/lint-python-mutable-default-parameters.sh
deleted file mode 100755
index 1f9f035d30..0000000000
--- a/test/lint/lint-python-mutable-default-parameters.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2019 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Detect when a mutable list or dict is used as a default parameter value in a Python function.
-
-export LC_ALL=C
-EXIT_CODE=0
-OUTPUT=$(git grep -E '^\s*def [a-zA-Z0-9_]+\(.*=\s*(\[|\{)' -- "*.py")
-if [[ ${OUTPUT} != "" ]]; then
- echo "A mutable list or dict seems to be used as default parameter value:"
- echo
- echo "${OUTPUT}"
- echo
- cat << EXAMPLE
-This is how mutable list and dict default parameter values behave:
-
->>> def f(i, j=[], k={}):
-... j.append(i)
-... k[i] = True
-... return j, k
-...
->>> f(1)
-([1], {1: True})
->>> f(1)
-([1, 1], {1: True})
->>> f(2)
-([1, 1, 2], {1: True, 2: True})
-
-The intended behaviour was likely:
-
->>> def f(i, j=None, k=None):
-... if j is None:
-... j = []
-... if k is None:
-... k = {}
-... j.append(i)
-... k[i] = True
-... return j, k
-...
->>> f(1)
-([1], {1: True})
->>> f(1)
-([1], {1: True})
->>> f(2)
-([2], {2: True})
-EXAMPLE
- EXIT_CODE=1
-fi
-exit ${EXIT_CODE}
diff --git a/test/lint/lint-python.py b/test/lint/lint-python.py
new file mode 100755
index 0000000000..4d16facfea
--- /dev/null
+++ b/test/lint/lint-python.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 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.
+
+"""
+Check for specified flake8 and mypy warnings in python files.
+"""
+
+import os
+import pkg_resources
+import subprocess
+import sys
+
+DEPS = ['flake8', 'mypy', 'pyzmq']
+MYPY_CACHE_DIR = f"{os.getenv('BASE_ROOT_DIR', '')}/test/.mypy_cache"
+FILES_ARGS = ['git', 'ls-files', 'test/functional/*.py', 'contrib/devtools/*.py']
+
+ENABLED = (
+ 'E101,' # indentation contains mixed spaces and tabs
+ 'E112,' # expected an indented block
+ 'E113,' # unexpected indentation
+ 'E115,' # expected an indented block (comment)
+ 'E116,' # unexpected indentation (comment)
+ 'E125,' # continuation line with same indent as next logical line
+ 'E129,' # visually indented line with same indent as next logical line
+ 'E131,' # continuation line unaligned for hanging indent
+ 'E133,' # closing bracket is missing indentation
+ 'E223,' # tab before operator
+ 'E224,' # tab after operator
+ 'E242,' # tab after ','
+ 'E266,' # too many leading '#' for block comment
+ 'E271,' # multiple spaces after keyword
+ 'E272,' # multiple spaces before keyword
+ 'E273,' # tab after keyword
+ 'E274,' # tab before keyword
+ 'E275,' # missing whitespace after keyword
+ 'E304,' # blank lines found after function decorator
+ 'E306,' # expected 1 blank line before a nested definition
+ 'E401,' # multiple imports on one line
+ 'E402,' # module level import not at top of file
+ 'E502,' # the backslash is redundant between brackets
+ 'E701,' # multiple statements on one line (colon)
+ 'E702,' # multiple statements on one line (semicolon)
+ 'E703,' # statement ends with a semicolon
+ 'E711,' # comparison to None should be 'if cond is None:'
+ 'E714,' # test for object identity should be "is not"
+ 'E721,' # do not compare types, use "isinstance()"
+ 'E742,' # do not define classes named "l", "O", or "I"
+ 'E743,' # do not define functions named "l", "O", or "I"
+ 'E901,' # SyntaxError: invalid syntax
+ 'E902,' # TokenError: EOF in multi-line string
+ 'F401,' # module imported but unused
+ 'F402,' # import module from line N shadowed by loop variable
+ 'F403,' # 'from foo_module import *' used; unable to detect undefined names
+ 'F404,' # future import(s) name after other statements
+ 'F405,' # foo_function may be undefined, or defined from star imports: bar_module
+ 'F406,' # "from module import *" only allowed at module level
+ 'F407,' # an undefined __future__ feature name was imported
+ 'F601,' # dictionary key name repeated with different values
+ 'F602,' # dictionary key variable name repeated with different values
+ 'F621,' # too many expressions in an assignment with star-unpacking
+ 'F622,' # two or more starred expressions in an assignment (a, *b, *c = d)
+ 'F631,' # assertion test is a tuple, which are always True
+ 'F632,' # use ==/!= to compare str, bytes, and int literals
+ 'F701,' # a break statement outside of a while or for loop
+ 'F702,' # a continue statement outside of a while or for loop
+ 'F703,' # a continue statement in a finally block in a loop
+ 'F704,' # a yield or yield from statement outside of a function
+ 'F705,' # a return statement with arguments inside a generator
+ 'F706,' # a return statement outside of a function/method
+ 'F707,' # an except: block as not the last exception handler
+ 'F811,' # redefinition of unused name from line N
+ 'F812,' # list comprehension redefines 'foo' from line N
+ 'F821,' # undefined name 'Foo'
+ 'F822,' # undefined name name in __all__
+ 'F823,' # local variable name … referenced before assignment
+ 'F831,' # duplicate argument name in function definition
+ 'F841,' # local variable 'foo' is assigned to but never used
+ 'W191,' # indentation contains tabs
+ 'W291,' # trailing whitespace
+ 'W292,' # no newline at end of file
+ 'W293,' # blank line contains whitespace
+ 'W601,' # .has_key() is deprecated, use "in"
+ 'W602,' # deprecated form of raising exception
+ 'W603,' # "<>" is deprecated, use "!="
+ 'W604,' # backticks are deprecated, use "repr()"
+ 'W605,' # invalid escape sequence "x"
+ 'W606,' # 'async' and 'await' are reserved keywords starting with Python 3.7
+)
+
+
+def check_dependencies():
+ working_set = {pkg.key for pkg in pkg_resources.working_set}
+
+ for dep in DEPS:
+ if dep not in working_set:
+ print(f"Skipping Python linting since {dep} is not installed.")
+ exit(0)
+
+
+def main():
+ check_dependencies()
+
+ if len(sys.argv) > 1:
+ flake8_files = sys.argv[1:]
+ else:
+ files_args = ['git', 'ls-files', '*.py']
+ flake8_files = subprocess.check_output(files_args).decode("utf-8").splitlines()
+
+ flake8_args = ['flake8', '--ignore=B,C,E,F,I,N,W', f'--select={ENABLED}'] + flake8_files
+ flake8_env = os.environ.copy()
+ flake8_env["PYTHONWARNINGS"] = "ignore"
+
+ try:
+ subprocess.check_call(flake8_args, env=flake8_env)
+ except subprocess.CalledProcessError:
+ exit(1)
+
+ mypy_files = subprocess.check_output(FILES_ARGS).decode("utf-8").splitlines()
+ mypy_args = ['mypy', '--show-error-codes'] + mypy_files
+
+ try:
+ subprocess.check_call(mypy_args)
+ except subprocess.CalledProcessError:
+ exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
deleted file mode 100755
index 7d7857d325..0000000000
--- a/test/lint/lint-python.sh
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2017-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.
-#
-# Check for specified flake8 warnings in python files.
-
-export LC_ALL=C
-export MYPY_CACHE_DIR="${BASE_ROOT_DIR}/test/.mypy_cache"
-
-enabled=(
- E101 # indentation contains mixed spaces and tabs
- E112 # expected an indented block
- E113 # unexpected indentation
- E115 # expected an indented block (comment)
- E116 # unexpected indentation (comment)
- E125 # continuation line with same indent as next logical line
- E129 # visually indented line with same indent as next logical line
- E131 # continuation line unaligned for hanging indent
- E133 # closing bracket is missing indentation
- E223 # tab before operator
- E224 # tab after operator
- E242 # tab after ','
- E266 # too many leading '#' for block comment
- E271 # multiple spaces after keyword
- E272 # multiple spaces before keyword
- E273 # tab after keyword
- E274 # tab before keyword
- E275 # missing whitespace after keyword
- E304 # blank lines found after function decorator
- E306 # expected 1 blank line before a nested definition
- E401 # multiple imports on one line
- E402 # module level import not at top of file
- E502 # the backslash is redundant between brackets
- E701 # multiple statements on one line (colon)
- E702 # multiple statements on one line (semicolon)
- E703 # statement ends with a semicolon
- E711 # comparison to None should be 'if cond is None:'
- E714 # test for object identity should be "is not"
- E721 # do not compare types, use "isinstance()"
- E742 # do not define classes named "l", "O", or "I"
- E743 # do not define functions named "l", "O", or "I"
- E901 # SyntaxError: invalid syntax
- E902 # TokenError: EOF in multi-line string
- F401 # module imported but unused
- F402 # import module from line N shadowed by loop variable
- F403 # 'from foo_module import *' used; unable to detect undefined names
- F404 # future import(s) name after other statements
- F405 # foo_function may be undefined, or defined from star imports: bar_module
- F406 # "from module import *" only allowed at module level
- F407 # an undefined __future__ feature name was imported
- F601 # dictionary key name repeated with different values
- F602 # dictionary key variable name repeated with different values
- F621 # too many expressions in an assignment with star-unpacking
- F622 # two or more starred expressions in an assignment (a, *b, *c = d)
- F631 # assertion test is a tuple, which are always True
- F632 # use ==/!= to compare str, bytes, and int literals
- F701 # a break statement outside of a while or for loop
- F702 # a continue statement outside of a while or for loop
- F703 # a continue statement in a finally block in a loop
- F704 # a yield or yield from statement outside of a function
- F705 # a return statement with arguments inside a generator
- F706 # a return statement outside of a function/method
- F707 # an except: block as not the last exception handler
- F811 # redefinition of unused name from line N
- F812 # list comprehension redefines 'foo' from line N
- F821 # undefined name 'Foo'
- F822 # undefined name name in __all__
- F823 # local variable name … referenced before assignment
- F831 # duplicate argument name in function definition
- F841 # local variable 'foo' is assigned to but never used
- W191 # indentation contains tabs
- W291 # trailing whitespace
- W292 # no newline at end of file
- W293 # blank line contains whitespace
- W601 # .has_key() is deprecated, use "in"
- W602 # deprecated form of raising exception
- W603 # "<>" is deprecated, use "!="
- W604 # backticks are deprecated, use "repr()"
- W605 # invalid escape sequence "x"
- W606 # 'async' and 'await' are reserved keywords starting with Python 3.7
-)
-
-if ! command -v flake8 > /dev/null; then
- echo "Skipping Python linting since flake8 is not installed."
- exit 0
-elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then
- echo "Skipping Python linting since flake8 is running under Python 2. Install the Python 3 version of flake8."
- exit 0
-fi
-
-EXIT_CODE=0
-
-# shellcheck disable=SC2046
-if ! PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") $(
- if [[ $# == 0 ]]; then
- git ls-files "*.py"
- else
- echo "$@"
- fi
-); then
- EXIT_CODE=1
-fi
-
-mapfile -t FILES < <(git ls-files "test/functional/*.py" "contrib/devtools/*.py")
-if ! mypy --show-error-codes "${FILES[@]}"; then
- EXIT_CODE=1
-fi
-
-exit $EXIT_CODE
diff --git a/test/lint/lint-submodule.py b/test/lint/lint-submodule.py
new file mode 100755
index 0000000000..89d4c80f55
--- /dev/null
+++ b/test/lint/lint-submodule.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 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.
+
+"""
+This script checks for git modules
+"""
+
+import subprocess
+import sys
+
+def main():
+ submodules_list = subprocess.check_output(['git', 'submodule', 'status', '--recursive'],
+ universal_newlines = True, encoding = 'utf8').rstrip('\n')
+ if submodules_list:
+ print("These submodules were found, delete them:\n", submodules_list)
+ sys.exit(1)
+ sys.exit(0)
+
+if __name__ == '__main__':
+ main()
diff --git a/test/lint/lint-submodule.sh b/test/lint/lint-submodule.sh
deleted file mode 100755
index d9aa021df7..0000000000
--- a/test/lint/lint-submodule.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2020 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# This script checks for git modules
-export LC_ALL=C
-EXIT_CODE=0
-
-CMD=$(git submodule status --recursive)
-if test -n "$CMD";
-then
- echo These submodules were found, delete them:
- echo "$CMD"
- EXIT_CODE=1
-fi
-
-exit $EXIT_CODE
-
diff --git a/test/lint/lint-whitespace.py b/test/lint/lint-whitespace.py
new file mode 100755
index 0000000000..d98fc8d9a2
--- /dev/null
+++ b/test/lint/lint-whitespace.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2017-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.
+#
+# Check for new lines in diff that introduce trailing whitespace or
+# tab characters instead of spaces.
+
+# We can't run this check unless we know the commit range for the PR.
+
+import argparse
+import os
+import re
+import sys
+
+from subprocess import check_output
+
+EXCLUDED_DIRS = ["depends/patches/",
+ "contrib/guix/patches/",
+ "src/leveldb/",
+ "src/crc32c/",
+ "src/secp256k1/",
+ "src/minisketch/",
+ "src/univalue/",
+ "doc/release-notes/",
+ "src/qt/locale"]
+
+def parse_args():
+ """Parse command line arguments."""
+ parser = argparse.ArgumentParser(
+ description="""
+ Check for new lines in diff that introduce trailing whitespace
+ or tab characters instead of spaces in unstaged changes, the
+ previous n commits, or a commit-range.
+ """,
+ epilog=f"""
+ You can manually set the commit-range with the COMMIT_RANGE
+ environment variable (e.g. "COMMIT_RANGE='47ba2c3...ee50c9e'
+ {sys.argv[0]}"). Defaults to current merge base when neither
+ prev-commits nor the environment variable is set.
+ """)
+
+ parser.add_argument("--prev-commits", "-p", required=False, help="The previous n commits to check")
+
+ return parser.parse_args()
+
+
+def report_diff(selection):
+ filename = ""
+ seen = False
+ seenln = False
+
+ print("The following changes were suspected:")
+
+ for line in selection:
+ if re.match(r"^diff", line):
+ filename = line
+ seen = False
+ elif re.match(r"^@@", line):
+ linenumber = line
+ seenln = False
+ else:
+ if not seen:
+ # The first time a file is seen with trailing whitespace or a tab character, we print the
+ # filename (preceded by a newline).
+ print("")
+ print(filename)
+ seen = True
+ if not seenln:
+ print(linenumber)
+ seenln = True
+ print(line)
+
+
+def get_diff(commit_range, check_only_code):
+ exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS]
+
+ if check_only_code:
+ what_files = ["*.cpp", "*.h", "*.md", "*.py", "*.sh"]
+ else:
+ what_files = ["."]
+
+ diff = check_output(["git", "diff", "-U0", commit_range, "--"] + what_files + exclude_args, universal_newlines=True, encoding="utf8")
+
+ return diff
+
+
+def main():
+ args = parse_args()
+
+ if not os.getenv("COMMIT_RANGE"):
+ if args.prev_commits:
+ commit_range = "HEAD~" + args.prev_commits + "...HEAD"
+ else:
+ # This assumes that the target branch of the pull request will be master.
+ merge_base = check_output(["git", "merge-base", "HEAD", "master"], universal_newlines=True, encoding="utf8").rstrip("\n")
+ commit_range = merge_base + "..HEAD"
+ else:
+ commit_range = os.getenv("COMMIT_RANGE")
+
+ whitespace_selection = []
+ tab_selection = []
+
+ # Check if trailing whitespace was found in the diff.
+ for line in get_diff(commit_range, check_only_code=False).splitlines():
+ if re.match(r"^(diff --git|\@@|^\+.*\s+$)", line):
+ whitespace_selection.append(line)
+
+ whitespace_additions = [i for i in whitespace_selection if i.startswith("+")]
+
+ # Check if tab characters were found in the diff.
+ for line in get_diff(commit_range, check_only_code=True).splitlines():
+ if re.match(r"^(diff --git|\@@|^\+.*\t)", line):
+ tab_selection.append(line)
+
+ tab_additions = [i for i in tab_selection if i.startswith("+")]
+
+ ret = 0
+
+ if len(whitespace_additions) > 0:
+ print("This diff appears to have added new lines with trailing whitespace.")
+ report_diff(whitespace_selection)
+ ret = 1
+
+ if len(tab_additions) > 0:
+ print("This diff appears to have added new lines with tab characters instead of spaces.")
+ report_diff(tab_selection)
+ ret = 1
+
+ sys.exit(ret)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
deleted file mode 100755
index 9d55c71eb5..0000000000
--- a/test/lint/lint-whitespace.sh
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2017-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.
-#
-# Check for new lines in diff that introduce trailing whitespace.
-
-# We can't run this check unless we know the commit range for the PR.
-
-export LC_ALL=C
-while getopts "?" opt; do
- case $opt in
- ?)
- echo "Usage: $0 [N]"
- echo " COMMIT_RANGE='<commit range>' $0"
- echo " $0 -?"
- echo "Checks unstaged changes, the previous N commits, or a commit range."
- echo "COMMIT_RANGE='47ba2c3...ee50c9e' $0"
- exit 0
- ;;
- esac
-done
-
-if [ -z "${COMMIT_RANGE}" ]; then
- if [ -n "$1" ]; then
- COMMIT_RANGE="HEAD~$1...HEAD"
- else
- # This assumes that the target branch of the pull request will be master.
- MERGE_BASE=$(git merge-base HEAD master)
- COMMIT_RANGE="$MERGE_BASE..HEAD"
- fi
-fi
-
-showdiff() {
- if ! git diff -U0 "${COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)contrib/guix/patches/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/minisketch/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then
- echo "Failed to get a diff"
- exit 1
- fi
-}
-
-showcodediff() {
- if ! git diff -U0 "${COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/minisketch/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then
- echo "Failed to get a diff"
- exit 1
- fi
-}
-
-RET=0
-
-# Check if trailing whitespace was found in the diff.
-if showdiff | grep -E -q '^\+.*\s+$'; then
- echo "This diff appears to have added new lines with trailing whitespace."
- echo "The following changes were suspected:"
- FILENAME=""
- SEEN=0
- SEENLN=0
- while read -r line; do
- if [[ "$line" =~ ^diff ]]; then
- FILENAME="$line"
- SEEN=0
- elif [[ "$line" =~ ^@@ ]]; then
- LINENUMBER="$line"
- SEENLN=0
- else
- if [ "$SEEN" -eq 0 ]; then
- # The first time a file is seen with trailing whitespace, we print the
- # filename (preceded by a newline).
- echo
- echo "$FILENAME"
- SEEN=1
- fi
- if [ "$SEENLN" -eq 0 ]; then
- echo "$LINENUMBER"
- SEENLN=1
- fi
- echo "$line"
- fi
- done < <(showdiff | grep -E '^(diff --git |@@|\+.*\s+$)')
- RET=1
-fi
-
-# Check if tab characters were found in the diff.
-if showcodediff | perl -nle '$MATCH++ if m{^\+.*\t}; END{exit 1 unless $MATCH>0}' > /dev/null; then
- echo "This diff appears to have added new lines with tab characters instead of spaces."
- echo "The following changes were suspected:"
- FILENAME=""
- SEEN=0
- SEENLN=0
- while read -r line; do
- if [[ "$line" =~ ^diff ]]; then
- FILENAME="$line"
- SEEN=0
- elif [[ "$line" =~ ^@@ ]]; then
- LINENUMBER="$line"
- SEENLN=0
- else
- if [ "$SEEN" -eq 0 ]; then
- # The first time a file is seen with a tab character, we print the
- # filename (preceded by a newline).
- echo
- echo "$FILENAME"
- SEEN=1
- fi
- if [ "$SEENLN" -eq 0 ]; then
- echo "$LINENUMBER"
- SEENLN=1
- fi
- echo "$line"
- fi
- done < <(showcodediff | perl -nle 'print if m{^(diff --git |@@|\+.*\t)}')
- RET=1
-fi
-
-exit $RET