aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--build_msvc/libsecp256k1/libsecp256k1.vcxproj2
-rwxr-xr-xci/test/00_setup_env_mac.sh5
-rwxr-xr-xci/test/01_base_install.sh3
-rwxr-xr-xci/test/06_script_b.sh2
-rw-r--r--configure.ac1
-rwxr-xr-xcontrib/devtools/security-check.py8
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/devtools/test-security-check.py14
-rwxr-xr-xcontrib/devtools/test-symbol-check.py2
-rw-r--r--contrib/guix/manifest.scm2
-rw-r--r--depends/hosts/darwin.mk50
-rw-r--r--depends/packages/native_clang.mk6
-rw-r--r--doc/release-notes-27632.md5
-rw-r--r--doc/release-notes-empty-template.md2
-rw-r--r--share/qt/Info.plist.in2
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/bench/bip324_ecdh.cpp51
-rw-r--r--src/bench/ellswift.cpp31
-rw-r--r--src/bench/wallet_create_tx.cpp4
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/init.cpp23
-rw-r--r--src/init/common.cpp15
-rw-r--r--src/init/common.h6
-rw-r--r--src/kernel/mempool_entry.h10
-rw-r--r--src/key.cpp37
-rw-r--r--src/key.h27
-rw-r--r--src/logging.cpp4
-rw-r--r--src/logging.h2
-rw-r--r--src/net.cpp11
-rw-r--r--src/net.h1
-rw-r--r--src/net_processing.cpp196
-rw-r--r--src/node/blockstorage.cpp4
-rw-r--r--src/node/chainstate.cpp2
-rw-r--r--src/node/chainstate.h3
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/fees.cpp33
-rw-r--r--src/policy/fees.h22
-rw-r--r--src/pubkey.cpp15
-rw-r--r--src/pubkey.h32
-rw-r--r--src/random.cpp6
-rw-r--r--src/random.h3
-rw-r--r--src/rpc/client.cpp4
-rw-r--r--src/rpc/mempool.cpp4
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/secp256k1/.cirrus.yml22
-rw-r--r--src/secp256k1/.gitignore2
-rw-r--r--src/secp256k1/CHANGELOG.md22
-rw-r--r--src/secp256k1/CMakeLists.txt172
-rw-r--r--src/secp256k1/CMakePresets.json19
-rw-r--r--src/secp256k1/Makefile.am53
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m426
-rwxr-xr-xsrc/secp256k1/ci/cirrus.sh4
-rw-r--r--src/secp256k1/ci/linux-debian.Dockerfile11
-rw-r--r--src/secp256k1/cmake/CheckArm32Assembly.cmake6
-rw-r--r--src/secp256k1/cmake/CheckStringOptionValue.cmake8
-rw-r--r--src/secp256k1/cmake/CheckX86_64Assembly.cmake (renamed from src/secp256k1/cmake/Check64bitAssembly.cmake)6
-rw-r--r--src/secp256k1/cmake/FindValgrind.cmake2
-rw-r--r--src/secp256k1/cmake/TryAddCompileOption.cmake23
-rw-r--r--src/secp256k1/cmake/TryAppendCFlags.cmake24
-rw-r--r--src/secp256k1/cmake/source_arm32.s9
-rw-r--r--src/secp256k1/configure.ac48
-rw-r--r--src/secp256k1/doc/ellswift.md483
-rw-r--r--src/secp256k1/doc/release-process.md45
-rw-r--r--src/secp256k1/examples/CMakeLists.txt19
-rw-r--r--src/secp256k1/examples/examples_util.h8
-rw-r--r--src/secp256k1/include/secp256k1.h12
-rw-r--r--src/secp256k1/include/secp256k1_ellswift.h198
-rw-r--r--src/secp256k1/include/secp256k1_extrakeys.h10
-rw-r--r--src/secp256k1/include/secp256k1_schnorrsig.h16
-rw-r--r--src/secp256k1/src/CMakeLists.txt242
-rw-r--r--src/secp256k1/src/bench.c74
-rw-r--r--src/secp256k1/src/bench.h2
-rw-r--r--src/secp256k1/src/bench_ecmult.c6
-rw-r--r--src/secp256k1/src/bench_internal.c8
-rw-r--r--src/secp256k1/src/ctime_tests.c35
-rw-r--r--src/secp256k1/src/ecdsa_impl.h3
-rw-r--r--src/secp256k1/src/eckey_impl.h12
-rw-r--r--src/secp256k1/src/ecmult_const.h8
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h68
-rw-r--r--src/secp256k1/src/ecmult_gen_compute_table_impl.h2
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h7
-rw-r--r--src/secp256k1/src/ecmult_impl.h13
-rw-r--r--src/secp256k1/src/field.h311
-rw-r--r--src/secp256k1/src/field_10x26.h33
-rw-r--r--src/secp256k1/src/field_10x26_impl.h276
-rw-r--r--src/secp256k1/src/field_5x52.h33
-rw-r--r--src/secp256k1/src/field_5x52_asm_impl.h6
-rw-r--r--src/secp256k1/src/field_5x52_impl.h273
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h1
-rw-r--r--src/secp256k1/src/field_impl.h300
-rw-r--r--src/secp256k1/src/group.h12
-rw-r--r--src/secp256k1/src/group_impl.h150
-rw-r--r--src/secp256k1/src/int128_native_impl.h1
-rw-r--r--src/secp256k1/src/int128_struct_impl.h1
-rw-r--r--src/secp256k1/src/modinv32_impl.h33
-rw-r--r--src/secp256k1/src/modinv64_impl.h31
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/ellswift/Makefile.am.include4
-rw-r--r--src/secp256k1/src/modules/ellswift/bench_impl.h106
-rw-r--r--src/secp256k1/src/modules/ellswift/main_impl.h589
-rw-r--r--src/secp256k1/src/modules/ellswift/tests_impl.h434
-rw-r--r--src/secp256k1/src/modules/extrakeys/main_impl.h3
-rw-r--r--src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h2
-rw-r--r--src/secp256k1/src/modules/recovery/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/schnorrsig/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_impl.h212
-rw-r--r--src/secp256k1/src/precompute_ecmult.c1
-rw-r--r--src/secp256k1/src/precompute_ecmult_gen.c1
-rw-r--r--src/secp256k1/src/precomputed_ecmult.c1
-rw-r--r--src/secp256k1/src/precomputed_ecmult.h1
-rw-r--r--src/secp256k1/src/precomputed_ecmult_gen.c1
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h25
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h39
-rw-r--r--src/secp256k1/src/scalar_low_impl.h1
-rw-r--r--src/secp256k1/src/secp256k1.c8
-rw-r--r--src/secp256k1/src/testrand.h2
-rw-r--r--src/secp256k1/src/testrand_impl.h1
-rw-r--r--src/secp256k1/src/tests.c322
-rw-r--r--src/secp256k1/src/tests_exhaustive.c18
-rw-r--r--src/secp256k1/src/util.h58
-rwxr-xr-xsrc/secp256k1/tools/tests_wycheproof_generate.py43
-rw-r--r--src/span.h1
-rw-r--r--src/support/allocators/secure.h4
-rw-r--r--src/support/allocators/zeroafterfree.h4
-rw-r--r--src/test/fuzz/key.cpp80
-rw-r--r--src/test/fuzz/policy_estimator.cpp2
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/transaction.cpp13
-rw-r--r--src/test/key_tests.cpp20
-rw-r--r--src/test/logging_tests.cpp12
-rw-r--r--src/test/settings_tests.cpp2
-rw-r--r--src/test/util/setup_common.cpp2
-rw-r--r--src/txmempool.cpp8
-rw-r--r--src/txorphanage.cpp12
-rw-r--r--src/txorphanage.h2
-rw-r--r--src/univalue/include/univalue.h2
-rw-r--r--src/univalue/lib/univalue.cpp6
-rw-r--r--src/univalue/test/object.cpp4
-rw-r--r--src/validation.cpp33
-rw-r--r--src/validation.h3
-rw-r--r--src/wallet/coinselection.cpp4
-rw-r--r--src/wallet/coinselection.h2
-rw-r--r--src/wallet/rpc/addresses.cpp4
-rw-r--r--src/wallet/spend.cpp2
-rw-r--r--src/wallet/test/coinselector_tests.cpp2
-rw-r--r--src/wallet/test/db_tests.cpp7
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp7
-rw-r--r--src/wallet/test/fuzz/fees.cpp2
-rw-r--r--src/wallet/wallet.cpp7
-rwxr-xr-xtest/functional/feature_assumevalid.py11
-rwxr-xr-xtest/functional/feature_block.py6
-rwxr-xr-xtest/functional/feature_config_args.py2
-rwxr-xr-xtest/functional/feature_fee_estimation.py101
-rwxr-xr-xtest/functional/feature_logging.py30
-rwxr-xr-xtest/functional/feature_nulldummy.py12
-rwxr-xr-xtest/functional/feature_taproot.py14
-rwxr-xr-xtest/functional/interface_usdt_mempool.py80
-rwxr-xr-xtest/functional/interface_usdt_net.py15
-rwxr-xr-xtest/functional/interface_usdt_utxocache.py49
-rwxr-xr-xtest/functional/interface_usdt_validation.py34
-rwxr-xr-xtest/functional/mempool_accept.py6
-rwxr-xr-xtest/functional/mempool_dust.py9
-rwxr-xr-xtest/functional/p2p_segwit.py12
-rwxr-xr-xtest/functional/rpc_createmultisig.py11
-rwxr-xr-xtest/functional/rpc_psbt.py22
-rwxr-xr-xtest/functional/rpc_signrawtransactionwithkey.py21
-rw-r--r--test/functional/test_framework/wallet.py7
-rwxr-xr-xtest/functional/test_framework/wallet_util.py23
-rwxr-xr-xtest/functional/wallet_blank.py14
-rwxr-xr-xtest/functional/wallet_createwallet.py12
-rwxr-xr-xtest/functional/wallet_fundrawtransaction.py9
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py9
-rwxr-xr-xtest/functional/wallet_listsinceblock.py9
-rwxr-xr-xtest/functional/wallet_migration.py37
-rwxr-xr-xtest/functional/wallet_send.py8
-rwxr-xr-xtest/fuzz/test_runner.py22
-rwxr-xr-xtest/lint/lint-assertions.py10
-rw-r--r--test/sanitizer_suppressions/ubsan1
179 files changed, 4906 insertions, 1668 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index fd2a46433d..40db8321b2 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -314,7 +314,7 @@ task:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
task:
- name: 'macOS 10.15 [gui, no tests] [jammy]'
+ name: 'macOS 11.0 [gui, no tests] [jammy]'
<< : *CONTAINER_DEPENDS_TEMPLATE
container:
docker_arguments:
diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
index 585c28e503..777515aa3a 100644
--- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj
+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
@@ -14,7 +14,7 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;ENABLE_MODULE_ELLSWIFT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UndefinePreprocessorDefinitions>USE_ASM_X86_64;%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4146;4244;4267;4334</DisableSpecificWarnings>
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index 6ae427fd42..65c6119fcd 100755
--- a/ci/test/00_setup_env_mac.sh
+++ b/ci/test/00_setup_env_mac.sh
@@ -15,4 +15,7 @@ export XCODE_BUILD_ID=12B45b
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports"
+
+# False-positive warning is fixed with clang 17, remove this when that version
+# can be used.
+export BITCOIN_CONFIG="--with-gui --enable-reduce-exports LDFLAGS=-Wno-error=unused-command-line-argument"
diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh
index 230288bc6c..76cde42161 100755
--- a/ci/test/01_base_install.sh
+++ b/ci/test/01_base_install.sh
@@ -42,7 +42,7 @@ if [ -n "$PIP_PACKAGES" ]; then
fi
if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
- git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-16.0.5 "${BASE_SCRATCH_DIR}"/msan/llvm-project
+ git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-16.0.6 "${BASE_SCRATCH_DIR}"/msan/llvm-project
cmake -G Ninja -B "${BASE_SCRATCH_DIR}"/msan/clang_build/ -DLLVM_ENABLE_PROJECTS="clang" \
-DCMAKE_BUILD_TYPE=Release \
@@ -55,6 +55,7 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
update-alternatives --install /usr/bin/clang++ clang++ "${BASE_SCRATCH_DIR}"/msan/clang_build/bin/clang++ 100
update-alternatives --install /usr/bin/clang clang "${BASE_SCRATCH_DIR}"/msan/clang_build/bin/clang 100
+ update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer "${BASE_SCRATCH_DIR}"/msan/clang_build/bin/llvm-symbolizer 100
cmake -G Ninja -B "${BASE_SCRATCH_DIR}"/msan/cxx_build/ -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \
-DCMAKE_BUILD_TYPE=Release \
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index 1e086a9f13..0b10ebd44b 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -170,5 +170,5 @@ if [ "${RUN_TIDY}" = "true" ]; then
fi
if [ "$RUN_FUZZ_TESTS" = "true" ]; then
- bash -c "LD_LIBRARY_PATH=${DEPENDS_DIR}/${HOST}/lib test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} $MAKEJOBS -l DEBUG ${DIR_FUZZ_IN}"
+ bash -c "LD_LIBRARY_PATH=${DEPENDS_DIR}/${HOST}/lib test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} $MAKEJOBS -l DEBUG ${DIR_FUZZ_IN} --empty_min_time=60"
fi
diff --git a/configure.ac b/configure.ac
index f9fac057d0..f4368053a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1008,6 +1008,7 @@ if test "$TARGET_OS" = "darwin"; then
AX_CHECK_LINK_FLAG([-Wl,-dead_strip], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-dead_strip"], [], [$LDFLAG_WERROR])
AX_CHECK_LINK_FLAG([-Wl,-dead_strip_dylibs], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-dead_strip_dylibs"], [], [$LDFLAG_WERROR])
AX_CHECK_LINK_FLAG([-Wl,-bind_at_load], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-bind_at_load"], [], [$LDFLAG_WERROR])
+ AX_CHECK_LINK_FLAG([-Wl,-fixup_chains], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-fixup_chains"], [], [$LDFLAG_WERROR])
fi
AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h])
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 452a1d42d6..85f75f978a 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -158,13 +158,6 @@ def check_MACHO_NOUNDEFS(binary) -> bool:
'''
return binary.header.has(lief.MachO.HEADER_FLAGS.NOUNDEFS)
-def check_MACHO_LAZY_BINDINGS(binary) -> bool:
- '''
- Check for no lazy bindings.
- We don't use or check for MH_BINDATLOAD. See #18295.
- '''
- return binary.dyld_info.lazy_bind == (0,0)
-
def check_MACHO_Canary(binary) -> bool:
'''
Check for use of stack canary
@@ -214,7 +207,6 @@ BASE_PE = [
BASE_MACHO = [
('NOUNDEFS', check_MACHO_NOUNDEFS),
- ('LAZY_BINDINGS', check_MACHO_LAZY_BINDINGS),
('Canary', check_MACHO_Canary),
]
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 4fb997b023..d85912398d 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -232,7 +232,7 @@ def check_MACHO_libraries(binary) -> bool:
return ok
def check_MACHO_min_os(binary) -> bool:
- if binary.build_version.minos == [10,15,0]:
+ if binary.build_version.minos == [11,0,0]:
return True
return False
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index d666291cba..90268740c6 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -120,13 +120,13 @@ class TestSecurityChecks(unittest.TestCase):
if arch == lief.ARCHITECTURES.X86:
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-Wl,-allow_stack_execute','-fno-stack-protector']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS Canary PIE NX CONTROL_FLOW'))
+ (1, executable+': failed NOUNDEFS Canary PIE NX CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-Wl,-allow_stack_execute','-fstack-protector-all']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS PIE NX CONTROL_FLOW'))
+ (1, executable+': failed NOUNDEFS PIE NX CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-fstack-protector-all']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS PIE CONTROL_FLOW'))
+ (1, executable+': failed NOUNDEFS PIE CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-fstack-protector-all']),
- (1, executable+': failed LAZY_BINDINGS PIE CONTROL_FLOW'))
+ (1, executable+': failed PIE CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-bind_at_load','-fstack-protector-all']),
(1, executable+': failed PIE CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-bind_at_load','-fstack-protector-all', '-fcf-protection=full']),
@@ -136,11 +136,9 @@ class TestSecurityChecks(unittest.TestCase):
else:
# arm64 darwin doesn't support non-PIE binaries, control flow or executable stacks
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS Canary'))
+ (1, executable+': failed NOUNDEFS Canary'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS'))
- self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all']),
- (1, executable+': failed LAZY_BINDINGS'))
+ (1, executable+': failed NOUNDEFS'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-bind_at_load','-fstack-protector-all']),
(0, ''))
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index e304880140..fe8a99739f 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -121,7 +121,7 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,10.15', '-Wl,11.4']),
+ self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']),
(1, f'{executable}: failed SDK'))
def test_PE(self):
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index f1c2854d09..1808eeffbe 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -608,5 +608,5 @@ inspecting signatures in Mach-O binaries.")
((string-contains target "-linux-")
(list (make-bitcoin-cross-toolchain target)))
((string-contains target "darwin")
- (list clang-toolchain-10 binutils cmake-minimal xorriso python-signapple))
+ (list clang-toolchain-11 binutils cmake-minimal xorriso python-signapple))
(else '())))))
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 08d81cbc99..fa6d6d4b8b 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -1,4 +1,4 @@
-OSX_MIN_VERSION=10.15
+OSX_MIN_VERSION=11.0
OSX_SDK_VERSION=11.0
XCODE_VERSION=12.2
XCODE_BUILD_ID=12B45b
@@ -19,7 +19,6 @@ clang_prog=$(build_prefix)/bin/clang
clangxx_prog=$(clang_prog)++
llvm_config_prog=$(build_prefix)/bin/llvm-config
-clang_resource_dir=$(build_prefix)/lib/clang/$(native_clang_version)
else
# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's
# system
@@ -37,7 +36,6 @@ clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang")
clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++")
llvm_config_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-config")
-clang_resource_dir=$(shell clang -print-resource-dir)
llvm_lib_dir=$(shell $(llvm_config_prog) --libdir)
endif
@@ -63,53 +61,33 @@ $(foreach TOOL,$(cctools_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/$$(
# Explicitly point to our binaries (e.g. cctools) so that they are
# ensured to be found and preferred over other possibilities.
#
-# -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1
+# -isysroot$(OSX_SDK) -nostdlibinc
#
-# Forces clang to use the libc++ headers from our SDK and completely
-# forget about the libc++ headers from the standard directories
+# Disable default include paths built into the compiler as well as
+# those normally included for libc and libc++. The only path that
+# remains implicitly is the clang resource dir.
#
-# -Xclang -*system<path_a> \
-# -Xclang -*system<path_b> \
-# -Xclang -*system<path_c> ...
+# -iwithsysroot / -iframeworkwithsysroot
#
-# Adds path_a, path_b, and path_c to the bottom of clang's list of
-# include search paths. This is used to explicitly specify the list of
-# system include search paths and its ordering, rather than rely on
-# clang's autodetection routine. This routine has been shown to:
-# 1. Fail to pickup libc++ headers in $SYSROOT/usr/include/c++/v1
-# when clang was built manually (see: https://github.com/bitcoin/bitcoin/pull/17919#issuecomment-656785034)
-# 2. Fail to pickup C headers in $SYSROOT/usr/include when
-# C_INCLUDE_DIRS was specified at configure time (see: https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9)
-#
-# Talking directly to cc1 with -Xclang here grants us access to specify
-# more granular categories for these system include search paths, and we
-# can use the correct categories that these search paths would have been
-# placed in if the autodetection routine had worked correctly. (see:
-# https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9#the-treatment)
-#
-# Furthermore, it places these search paths after any "non-Xclang"
-# specified search paths. This prevents any additional clang options or
-# environment variables from coming after or in between these system
-# include search paths, as that would be wrong in general but would also
-# break #include_next's.
+# Adds the desired paths from the SDK
#
+
darwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
-u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
-u LIBRARY_PATH \
$(clang_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
-B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
- -isysroot$(OSX_SDK) \
- -Xclang -internal-externc-isystem -Xclang $(clang_resource_dir)/include \
- -Xclang -internal-externc-isystem -Xclang $(OSX_SDK)/usr/include
+ -isysroot$(OSX_SDK) -nostdlibinc \
+ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks
+
darwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
-u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
-u LIBRARY_PATH \
$(clangxx_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
-B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
- -isysroot$(OSX_SDK) \
- -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1 \
- -Xclang -internal-externc-isystem -Xclang $(clang_resource_dir)/include \
- -Xclang -internal-externc-isystem -Xclang $(OSX_SDK)/usr/include
+ -isysroot$(OSX_SDK) -nostdlibinc \
+ -iwithsysroot/usr/include/c++/v1 \
+ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks
darwin_CFLAGS=-pipe -std=$(C_STANDARD)
darwin_CXXFLAGS=-pipe -std=$(CXX_STANDARD)
diff --git a/depends/packages/native_clang.mk b/depends/packages/native_clang.mk
index b11037b83e..109796c0e6 100644
--- a/depends/packages/native_clang.mk
+++ b/depends/packages/native_clang.mk
@@ -1,12 +1,12 @@
package=native_clang
-$(package)_version=10.0.1
+$(package)_version=11.1.0
$(package)_download_path=https://github.com/llvm/llvm-project/releases/download/llvmorg-$($(package)_version)
ifneq (,$(findstring aarch64,$(BUILD)))
$(package)_file_name=clang+llvm-$($(package)_version)-aarch64-linux-gnu.tar.xz
-$(package)_sha256_hash=90dc69a4758ca15cd0ffa45d07fbf5bf4309d47d2c7745a9f0735ecffde9c31f
+$(package)_sha256_hash=18df38247af3fba0e0e2991fb00d7e3cf3560b4d3509233a14af699ef0039e1c
else
$(package)_file_name=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-16.04.tar.xz
-$(package)_sha256_hash=48b83ef827ac2c213d5b64f5ad7ed082c8bcb712b46644e0dc5045c6f462c231
+$(package)_sha256_hash=c691a558967fb7709fb81e0ed80d1f775f4502810236aa968b4406526b43bee1
endif
define $(package)_stage_cmds
diff --git a/doc/release-notes-27632.md b/doc/release-notes-27632.md
new file mode 100644
index 0000000000..d588247c85
--- /dev/null
+++ b/doc/release-notes-27632.md
@@ -0,0 +1,5 @@
+Updated settings
+----------------
+
+- Passing an invalid `-debug`, `-debugexclude`, or `-loglevel` logging configuration
+ option now raises an error, rather than logging an easily missed warning. (#27632)
diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md
index 4cd2314308..887104548b 100644
--- a/doc/release-notes-empty-template.md
+++ b/doc/release-notes-empty-template.md
@@ -36,7 +36,7 @@ Compatibility
==============
Bitcoin Core is supported and extensively tested on operating systems
-using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+using the Linux kernel, macOS 11.0+, and Windows 7 and newer. Bitcoin
Core should also work on most other Unix-like systems but is not as
frequently tested on them. It is not recommended to use Bitcoin Core on
unsupported systems.
diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in
index 053359e0a8..b4e6f6a150 100644
--- a/share/qt/Info.plist.in
+++ b/share/qt/Info.plist.in
@@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>LSMinimumSystemVersion</key>
- <string>10.15.0</string>
+ <string>11</string>
<key>LSArchitecturePriority</key>
<array>
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index c8e510b482..10c8389c80 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -18,6 +18,7 @@ bench_bench_bitcoin_SOURCES = \
bench/bench.cpp \
bench/bench.h \
bench/bench_bitcoin.cpp \
+ bench/bip324_ecdh.cpp \
bench/block_assemble.cpp \
bench/ccoins_caching.cpp \
bench/chacha20.cpp \
@@ -29,6 +30,7 @@ bench_bench_bitcoin_SOURCES = \
bench/data.h \
bench/descriptors.cpp \
bench/duplicate_inputs.cpp \
+ bench/ellswift.cpp \
bench/examples.cpp \
bench/gcs_filter.cpp \
bench/hashpadding.cpp \
diff --git a/src/bench/bip324_ecdh.cpp b/src/bench/bip324_ecdh.cpp
new file mode 100644
index 0000000000..659da0f08e
--- /dev/null
+++ b/src/bench/bip324_ecdh.cpp
@@ -0,0 +1,51 @@
+// 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 <key.h>
+#include <pubkey.h>
+#include <random.h>
+#include <span.h>
+
+#include <array>
+#include <cstddef>
+
+static void BIP324_ECDH(benchmark::Bench& bench)
+{
+ ECC_Start();
+ FastRandomContext rng;
+
+ std::array<std::byte, 32> key_data;
+ std::array<std::byte, EllSwiftPubKey::size()> our_ellswift_data;
+ std::array<std::byte, EllSwiftPubKey::size()> their_ellswift_data;
+
+ rng.fillrand(key_data);
+ rng.fillrand(our_ellswift_data);
+ rng.fillrand(their_ellswift_data);
+
+ bench.batch(1).unit("ecdh").run([&] {
+ CKey key;
+ key.Set(UCharCast(key_data.data()), UCharCast(key_data.data()) + 32, true);
+ EllSwiftPubKey our_ellswift(our_ellswift_data);
+ EllSwiftPubKey their_ellswift(their_ellswift_data);
+
+ auto ret = key.ComputeBIP324ECDHSecret(their_ellswift, our_ellswift, true);
+
+ // To make sure that the computation is not the same on every iteration (ellswift decoding
+ // is variable-time), distribute bytes from the shared secret over the 3 inputs. The most
+ // important one is their_ellswift, because that one is actually decoded, so it's given most
+ // bytes. The data is copied into the middle, so that both halves are affected:
+ // - Copy 8 bytes from the resulting shared secret into middle of the private key.
+ std::copy(ret.begin(), ret.begin() + 8, key_data.begin() + 12);
+ // - Copy 8 bytes from the resulting shared secret into the middle of our ellswift key.
+ std::copy(ret.begin() + 8, ret.begin() + 16, our_ellswift_data.begin() + 28);
+ // - Copy 16 bytes from the resulting shared secret into the middle of their ellswift key.
+ std::copy(ret.begin() + 16, ret.end(), their_ellswift_data.begin() + 24);
+ });
+
+ ECC_Stop();
+}
+
+BENCHMARK(BIP324_ECDH, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/ellswift.cpp b/src/bench/ellswift.cpp
new file mode 100644
index 0000000000..75729e170c
--- /dev/null
+++ b/src/bench/ellswift.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2022-2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+
+#include <key.h>
+#include <random.h>
+
+static void EllSwiftCreate(benchmark::Bench& bench)
+{
+ ECC_Start();
+
+ CKey key;
+ key.MakeNewKey(true);
+
+ uint256 entropy = GetRandHash();
+
+ bench.batch(1).unit("pubkey").run([&] {
+ auto ret = key.EllSwiftCreate(AsBytes(Span{entropy}));
+ /* Use the first 32 bytes of the ellswift encoded public key as next private key. */
+ key.Set(UCharCast(ret.data()), UCharCast(ret.data()) + 32, true);
+ assert(key.IsValid());
+ /* Use the last 32 bytes of the ellswift encoded public key as next entropy. */
+ std::copy(ret.begin() + 32, ret.begin() + 64, AsBytePtr(entropy.data()));
+ });
+
+ ECC_Stop();
+}
+
+BENCHMARK(EllSwiftCreate, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp
index 13b0019fd2..5e5bc76fd2 100644
--- a/src/bench/wallet_create_tx.cpp
+++ b/src/bench/wallet_create_tx.cpp
@@ -83,6 +83,8 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
+ // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
+ SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
{
LOCK(wallet.cs_wallet);
@@ -136,6 +138,8 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType>& output_type)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
+ // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
+ SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
{
LOCK(wallet.cs_wallet);
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 9187f242eb..5761e8b321 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -115,7 +115,7 @@ bool WriteSettings(const fs::path& path,
{
SettingsValue out(SettingsValue::VOBJ);
for (const auto& value : values) {
- out.__pushKV(value.first, value.second);
+ out.pushKVEnd(value.first, value.second);
}
std::ofstream file;
file.open(path);
diff --git a/src/init.cpp b/src/init.cpp
index 38e1dbb4a2..e86180017a 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -77,12 +77,14 @@
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/moneystr.h>
+#include <util/result.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/syscall_sandbox.h>
#include <util/syserror.h>
#include <util/thread.h>
#include <util/threadnames.h>
+#include <util/time.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -586,6 +588,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and replacement policy. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
+ argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
@@ -949,8 +952,10 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags
- init::SetLoggingCategories(args);
- init::SetLoggingLevel(args);
+ auto result = init::SetLoggingCategories(args);
+ if (!result) return InitError(util::ErrorString(result));
+ result = init::SetLoggingLevel(args);
+ if (!result) return InitError(util::ErrorString(result));
nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0) {
@@ -1253,7 +1258,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
assert(!node.fee_estimator);
// Don't initialize fee estimation with old data if we don't relay transactions,
// as they would never get updated.
- if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args));
+ if (!ignores_incoming_txs) {
+ bool read_stale_estimates = args.GetBoolArg("-acceptstalefeeestimates", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
+ if (read_stale_estimates && (chainparams.GetChainType() != ChainType::REGTEST)) {
+ return InitError(strprintf(_("acceptstalefeeestimates is not supported on %s chain."), chainparams.GetChainTypeString()));
+ }
+ node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args), read_stale_estimates);
+
+ // Flush estimates to disk periodically
+ CBlockPolicyEstimator* fee_estimator = node.fee_estimator.get();
+ node.scheduler->scheduleEvery([fee_estimator] { fee_estimator->FlushFeeEstimates(); }, FEE_FLUSH_INTERVAL);
+ }
// Check port numbers
for (const std::string port_option : {
@@ -1530,7 +1545,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}
- if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
+ if (status == node::ChainstateLoadStatus::FAILURE_FATAL || status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
return InitError(error);
}
diff --git a/src/init/common.cpp b/src/init/common.cpp
index 9a52a09cea..f3f7c696c5 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -13,6 +13,7 @@
#include <tinyformat.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
+#include <util/result.h>
#include <util/string.h>
#include <util/time.h>
#include <util/translation.h>
@@ -58,27 +59,28 @@ void SetLoggingOptions(const ArgsManager& args)
fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
}
-void SetLoggingLevel(const ArgsManager& args)
+util::Result<void> SetLoggingLevel(const ArgsManager& args)
{
if (args.IsArgSet("-loglevel")) {
for (const std::string& level_str : args.GetArgs("-loglevel")) {
if (level_str.find_first_of(':', 3) == std::string::npos) {
// user passed a global log level, i.e. -loglevel=<level>
if (!LogInstance().SetLogLevel(level_str)) {
- InitWarning(strprintf(_("Unsupported global logging level -loglevel=%s. Valid values: %s."), level_str, LogInstance().LogLevelsString()));
+ return util::Error{strprintf(_("Unsupported global logging level %s=%s. Valid values: %s."), "-loglevel", level_str, LogInstance().LogLevelsString())};
}
} else {
// user passed a category-specific log level, i.e. -loglevel=<category>:<level>
const auto& toks = SplitString(level_str, ':');
if (!(toks.size() == 2 && LogInstance().SetCategoryLogLevel(toks[0], toks[1]))) {
- InitWarning(strprintf(_("Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s."), level_str, LogInstance().LogCategoriesString(), LogInstance().LogLevelsString()));
+ return util::Error{strprintf(_("Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s."), "-loglevel", level_str, LogInstance().LogCategoriesString(), LogInstance().LogLevelsString())};
}
}
}
}
+ return {};
}
-void SetLoggingCategories(const ArgsManager& args)
+util::Result<void> SetLoggingCategories(const ArgsManager& args)
{
if (args.IsArgSet("-debug")) {
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
@@ -88,7 +90,7 @@ void SetLoggingCategories(const ArgsManager& args)
[](std::string cat){return cat == "0" || cat == "none";})) {
for (const auto& cat : categories) {
if (!LogInstance().EnableCategory(cat)) {
- InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
+ return util::Error{strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)};
}
}
}
@@ -97,9 +99,10 @@ void SetLoggingCategories(const ArgsManager& args)
// Now remove the logging categories which were explicitly excluded
for (const std::string& cat : args.GetArgs("-debugexclude")) {
if (!LogInstance().DisableCategory(cat)) {
- InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
+ return util::Error{strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)};
}
}
+ return {};
}
bool StartLogging(const ArgsManager& args)
diff --git a/src/init/common.h b/src/init/common.h
index 44c3a502ee..b61a77c6d4 100644
--- a/src/init/common.h
+++ b/src/init/common.h
@@ -8,13 +8,15 @@
#ifndef BITCOIN_INIT_COMMON_H
#define BITCOIN_INIT_COMMON_H
+#include <util/result.h>
+
class ArgsManager;
namespace init {
void AddLoggingArgs(ArgsManager& args);
void SetLoggingOptions(const ArgsManager& args);
-void SetLoggingCategories(const ArgsManager& args);
-void SetLoggingLevel(const ArgsManager& args);
+[[nodiscard]] util::Result<void> SetLoggingCategories(const ArgsManager& args);
+[[nodiscard]] util::Result<void> SetLoggingLevel(const ArgsManager& args);
bool StartLogging(const ArgsManager& args);
void LogPackageVersion();
} // namespace init
diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h
index 969ddcd1ce..886e1e1b3a 100644
--- a/src/kernel/mempool_entry.h
+++ b/src/kernel/mempool_entry.h
@@ -57,7 +57,7 @@ struct CompareIteratorByHash {
* ("descendant" transactions).
*
* When a new entry is added to the mempool, we update the descendant state
- * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
+ * (m_count_with_descendants, nSizeWithDescendants, and nModFeesWithDescendants) for
* all ancestors of the newly added transaction.
*
*/
@@ -87,13 +87,13 @@ private:
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
// descendants as well.
- uint64_t nCountWithDescendants{1}; //!< number of descendant transactions
+ int64_t m_count_with_descendants{1}; //!< number of descendant transactions
// Using int64_t instead of int32_t to avoid signed integer overflow issues.
int64_t nSizeWithDescendants; //!< ... and size
CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
// Analogous statistics for ancestor transactions
- uint64_t nCountWithAncestors{1};
+ int64_t m_count_with_ancestors{1};
// Using int64_t instead of int32_t to avoid signed integer overflow issues.
int64_t nSizeWithAncestors;
CAmount nModFeesWithAncestors;
@@ -153,13 +153,13 @@ public:
lockPoints = lp;
}
- uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
+ uint64_t GetCountWithDescendants() const { return m_count_with_descendants; }
int64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
- uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
+ uint64_t GetCountWithAncestors() const { return m_count_with_ancestors; }
int64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
diff --git a/src/key.cpp b/src/key.cpp
index 3a3f0b2bc2..efaea5b1b3 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -11,6 +11,7 @@
#include <random.h>
#include <secp256k1.h>
+#include <secp256k1_ellswift.h>
#include <secp256k1_extrakeys.h>
#include <secp256k1_recovery.h>
#include <secp256k1_schnorrsig.h>
@@ -331,6 +332,42 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
return ret;
}
+EllSwiftPubKey CKey::EllSwiftCreate(Span<const std::byte> ent32) const
+{
+ assert(fValid);
+ assert(ent32.size() == 32);
+ std::array<std::byte, EllSwiftPubKey::size()> encoded_pubkey;
+
+ auto success = secp256k1_ellswift_create(secp256k1_context_sign,
+ UCharCast(encoded_pubkey.data()),
+ keydata.data(),
+ UCharCast(ent32.data()));
+
+ // Should always succeed for valid keys (asserted above).
+ assert(success);
+ return {encoded_pubkey};
+}
+
+ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, const EllSwiftPubKey& our_ellswift, bool initiating) const
+{
+ assert(fValid);
+
+ ECDHSecret output;
+ // BIP324 uses the initiator as party A, and the responder as party B. Remap the inputs
+ // accordingly:
+ bool success = secp256k1_ellswift_xdh(secp256k1_context_sign,
+ UCharCast(output.data()),
+ UCharCast(initiating ? our_ellswift.data() : their_ellswift.data()),
+ UCharCast(initiating ? their_ellswift.data() : our_ellswift.data()),
+ keydata.data(),
+ initiating ? 0 : 1,
+ secp256k1_ellswift_xdh_hash_function_bip324,
+ nullptr);
+ // Should always succeed for valid keys (assert above).
+ assert(success);
+ return output;
+}
+
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
out.nDepth = nDepth + 1;
diff --git a/src/key.h b/src/key.h
index 4e092fffea..8382b0a670 100644
--- a/src/key.h
+++ b/src/key.h
@@ -22,6 +22,12 @@
*/
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
+/** Size of ECDH shared secrets. */
+constexpr static size_t ECDH_SECRET_SIZE = CSHA256::OUTPUT_SIZE;
+
+// Used to represent ECDH shared secret (ECDH_SECRET_SIZE bytes)
+using ECDHSecret = std::array<std::byte, ECDH_SECRET_SIZE>;
+
/** An encapsulated private key. */
class CKey
{
@@ -156,6 +162,27 @@ public:
//! Load private key and check that public key matches.
bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck);
+
+ /** Create an ellswift-encoded public key for this key, with specified entropy.
+ *
+ * entropy must be a 32-byte span with additional entropy to use in the encoding. Every
+ * public key has ~2^256 different encodings, and this function will deterministically pick
+ * one of them, based on entropy. Note that even without truly random entropy, the
+ * resulting encoding will be indistinguishable from uniform to any adversary who does not
+ * know the private key (because the private key itself is always used as entropy as well).
+ */
+ EllSwiftPubKey EllSwiftCreate(Span<const std::byte> entropy) const;
+
+ /** Compute a BIP324-style ECDH shared secret.
+ *
+ * - their_ellswift: EllSwiftPubKey that was received from the other side.
+ * - our_ellswift: EllSwiftPubKey that was sent to the other side (must have been generated
+ * from *this using EllSwiftCreate()).
+ * - initiating: whether we are the initiating party (true) or responding party (false).
+ */
+ ECDHSecret ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift,
+ const EllSwiftPubKey& our_ellswift,
+ bool initiating) const;
};
struct CExtKey {
diff --git a/src/logging.cpp b/src/logging.cpp
index 7725fefeb7..a5cfb0d28e 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -179,7 +179,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::LOCK, "lock"},
#endif
{BCLog::UTIL, "util"},
- {BCLog::BLOCKSTORE, "blockstorage"},
+ {BCLog::BLOCKSTORAGE, "blockstorage"},
{BCLog::TXRECONCILIATION, "txreconciliation"},
{BCLog::SCAN, "scan"},
{BCLog::ALL, "1"},
@@ -280,7 +280,7 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
#endif
case BCLog::LogFlags::UTIL:
return "util";
- case BCLog::LogFlags::BLOCKSTORE:
+ case BCLog::LogFlags::BLOCKSTORAGE:
return "blockstorage";
case BCLog::LogFlags::TXRECONCILIATION:
return "txreconciliation";
diff --git a/src/logging.h b/src/logging.h
index e7c554e79f..fc03c8eac3 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -65,7 +65,7 @@ namespace BCLog {
LOCK = (1 << 24),
#endif
UTIL = (1 << 25),
- BLOCKSTORE = (1 << 26),
+ BLOCKSTORAGE = (1 << 26),
TXRECONCILIATION = (1 << 27),
SCAN = (1 << 28),
ALL = ~(uint32_t)0,
diff --git a/src/net.cpp b/src/net.cpp
index 282c8fb741..a96ffcfbe9 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1637,6 +1637,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
+ const bool use_seednodes{gArgs.IsArgSet("-seednode")};
if (!add_fixed_seeds) {
LogPrintf("Fixed seeds are disabled\n");
@@ -1666,12 +1667,12 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n");
}
- // Checking !dnsseed is cheaper before locking 2 mutexes.
- if (!add_fixed_seeds_now && !dnsseed) {
- LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex);
- if (m_addr_fetches.empty() && m_added_nodes.empty()) {
+ // Perform cheap checks before locking a mutex.
+ else if (!dnsseed && !use_seednodes) {
+ LOCK(m_added_nodes_mutex);
+ if (m_added_nodes.empty()) {
add_fixed_seeds_now = true;
- LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n");
+ LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n");
}
}
diff --git a/src/net.h b/src/net.h
index 83fe0427d4..811007ebee 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1219,7 +1219,6 @@ private:
std::vector<CNode*> m_nodes_copy;
};
- friend struct CConnmanTest;
friend struct ConnmanTestMsg;
};
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 6597019797..8da2c701d3 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -568,7 +568,7 @@ private:
*
* @return Returns true if the peer was punished (probably disconnected)
*/
- bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "")
+ bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state)
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
/** Maybe disconnect a peer and discourage future connections from its address.
@@ -918,6 +918,10 @@ private:
/** Process a new block. Perform any post-processing housekeeping */
void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked);
+ /** Process compact block txns */
+ void ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)
+ EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex, !m_most_recent_block_mutex);
+
/**
* When a peer sends us a valid block, instruct it to announce blocks to us
* using CMPCTBLOCK if possible by adding its nodeid to the end of
@@ -1731,7 +1735,7 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
return false;
}
-bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
+bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state)
{
PeerRef peer{GetPeerRef(nodeid)};
switch (state.GetResult()) {
@@ -1739,7 +1743,7 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
break;
// The node is providing invalid data:
case TxValidationResult::TX_CONSENSUS:
- if (peer) Misbehaving(*peer, 100, message);
+ if (peer) Misbehaving(*peer, 100, "");
return true;
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
@@ -1754,9 +1758,6 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
case TxValidationResult::TX_NO_MEMPOOL:
break;
}
- if (message != "") {
- LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
- }
return false;
}
@@ -3204,6 +3205,93 @@ void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlo
}
}
+void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)
+{
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ bool fBlockRead{false};
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
+ {
+ LOCK(cs_main);
+
+ auto range_flight = mapBlocksInFlight.equal_range(block_transactions.blockhash);
+ size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
+ bool requested_block_from_this_peer{false};
+
+ // Multimap ensures ordering of outstanding requests. It's either empty or first in line.
+ bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());
+
+ while (range_flight.first != range_flight.second) {
+ auto [node_id, block_it] = range_flight.first->second;
+ if (node_id == pfrom.GetId() && block_it->partialBlock) {
+ requested_block_from_this_peer = true;
+ break;
+ }
+ range_flight.first++;
+ }
+
+ if (!requested_block_from_this_peer) {
+ LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
+ return;
+ }
+
+ PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock;
+ ReadStatus status = partialBlock.FillBlock(*pblock, block_transactions.txn);
+ if (status == READ_STATUS_INVALID) {
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
+ Misbehaving(peer, 100, "invalid compact block/non-matching block transactions");
+ return;
+ } else if (status == READ_STATUS_FAILED) {
+ if (first_in_flight) {
+ // Might have collided, fall back to getdata now :(
+ std::vector<CInv> invs;
+ invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(peer), block_transactions.blockhash));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ } else {
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId());
+ LogPrint(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId());
+ return;
+ }
+ } else {
+ // Block is either okay, or possibly we received
+ // READ_STATUS_CHECKBLOCK_FAILED.
+ // Note that CheckBlock can only fail for one of a few reasons:
+ // 1. bad-proof-of-work (impossible here, because we've already
+ // accepted the header)
+ // 2. merkleroot doesn't match the transactions given (already
+ // caught in FillBlock with READ_STATUS_FAILED, so
+ // impossible here)
+ // 3. the block is otherwise invalid (eg invalid coinbase,
+ // block is too big, too many legacy sigops, etc).
+ // So if CheckBlock failed, #3 is the only possibility.
+ // Under BIP 152, we don't discourage the peer unless proof of work is
+ // invalid (we don't require all the stateless checks to have
+ // been run). This is handled below, so just treat this as
+ // though the block was successfully read, and rely on the
+ // handling in ProcessNewBlock to ensure the block index is
+ // updated, etc.
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // it is now an empty pointer
+ fBlockRead = true;
+ // mapBlockSource is used for potentially punishing peers and
+ // updating which peers send us compact blocks, so the race
+ // between here and cs_main in ProcessNewBlock is fine.
+ // BIP 152 permits peers to relay compact blocks after validating
+ // the header only; we should not punish peers if the block turns
+ // out to be invalid.
+ mapBlockSource.emplace(block_transactions.blockhash, std::make_pair(pfrom.GetId(), false));
+ }
+ } // Don't hold cs_main when we call into ProcessNewBlock
+ if (fBlockRead) {
+ // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
+ // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
+ // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
+ // disk-space attacks), but this should be safe due to the
+ // protections in the compact block handler -- see related comment
+ // in compact block optimistic reconstruction handling.
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
+ }
+ return;
+}
+
void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
const std::chrono::microseconds time_received,
const std::atomic<bool>& interruptMsgProc)
@@ -4276,12 +4364,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
blockhash.ToString(), pfrom.GetId());
}
- // When we succeed in decoding a block's txids from a cmpctblock
- // message we typically jump to the BLOCKTXN handling code, with a
- // dummy (empty) BLOCKTXN message, to re-use the logic there in
- // completing processing of the putative block (without cs_main).
bool fProcessBLOCKTXN = false;
- CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
// If we end up treating this as a plain headers message, call that as well
// without cs_main.
@@ -4382,10 +4465,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
req.indexes.push_back(i);
}
if (req.indexes.empty()) {
- // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)
- BlockTransactions txn;
- txn.blockhash = blockhash;
- blockTxnMsg << txn;
fProcessBLOCKTXN = true;
} else if (first_in_flight) {
// We will try to round-trip any compact blocks we get on failure,
@@ -4440,7 +4519,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} // cs_main
if (fProcessBLOCKTXN) {
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, interruptMsgProc);
+ BlockTransactions txn;
+ txn.blockhash = blockhash;
+ return ProcessCompactBlockTxns(pfrom, *peer, txn);
}
if (fRevertToHeaderProcessing) {
@@ -4492,88 +4573,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
BlockTransactions resp;
vRecv >> resp;
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
- bool fBlockRead = false;
- {
- LOCK(cs_main);
-
- auto range_flight = mapBlocksInFlight.equal_range(resp.blockhash);
- size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
- bool requested_block_from_this_peer{false};
-
- // Multimap ensures ordering of outstanding requests. It's either empty or first in line.
- bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());
-
- while (range_flight.first != range_flight.second) {
- auto [node_id, block_it] = range_flight.first->second;
- if (node_id == pfrom.GetId() && block_it->partialBlock) {
- requested_block_from_this_peer = true;
- break;
- }
- range_flight.first++;
- }
-
- if (!requested_block_from_this_peer) {
- LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
- return;
- }
-
- PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock;
- ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
- if (status == READ_STATUS_INVALID) {
- RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
- Misbehaving(*peer, 100, "invalid compact block/non-matching block transactions");
- return;
- } else if (status == READ_STATUS_FAILED) {
- if (first_in_flight) {
- // Might have collided, fall back to getdata now :(
- std::vector<CInv> invs;
- invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(*peer), resp.blockhash));
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
- } else {
- RemoveBlockRequest(resp.blockhash, pfrom.GetId());
- LogPrint(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId());
- return;
- }
- } else {
- // Block is either okay, or possibly we received
- // READ_STATUS_CHECKBLOCK_FAILED.
- // Note that CheckBlock can only fail for one of a few reasons:
- // 1. bad-proof-of-work (impossible here, because we've already
- // accepted the header)
- // 2. merkleroot doesn't match the transactions given (already
- // caught in FillBlock with READ_STATUS_FAILED, so
- // impossible here)
- // 3. the block is otherwise invalid (eg invalid coinbase,
- // block is too big, too many legacy sigops, etc).
- // So if CheckBlock failed, #3 is the only possibility.
- // Under BIP 152, we don't discourage the peer unless proof of work is
- // invalid (we don't require all the stateless checks to have
- // been run). This is handled below, so just treat this as
- // though the block was successfully read, and rely on the
- // handling in ProcessNewBlock to ensure the block index is
- // updated, etc.
- RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // it is now an empty pointer
- fBlockRead = true;
- // mapBlockSource is used for potentially punishing peers and
- // updating which peers send us compact blocks, so the race
- // between here and cs_main in ProcessNewBlock is fine.
- // BIP 152 permits peers to relay compact blocks after validating
- // the header only; we should not punish peers if the block turns
- // out to be invalid.
- mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom.GetId(), false));
- }
- } // Don't hold cs_main when we call into ProcessNewBlock
- if (fBlockRead) {
- // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
- // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
- // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
- // disk-space attacks), but this should be safe due to the
- // protections in the compact block handler -- see related comment
- // in compact block optimistic reconstruction handling.
- ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
- }
- return;
+ return ProcessCompactBlockTxns(pfrom, *peer, resp);
}
if (msg_type == NetMsgType::HEADERS)
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 1368ae6f6d..87cd291c7e 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -573,7 +573,7 @@ void BlockManager::UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const
const bool removed_blockfile{fs::remove(BlockFileSeq().FileName(pos), ec)};
const bool removed_undofile{fs::remove(UndoFileSeq().FileName(pos), ec)};
if (removed_blockfile || removed_undofile) {
- LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
+ LogPrint(BCLog::BLOCKSTORAGE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
}
}
}
@@ -642,7 +642,7 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
if ((int)nFile != m_last_blockfile) {
if (!fKnown) {
- LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString());
+ LogPrint(BCLog::BLOCKSTORAGE, "Leaving block file %i: %s\n", m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString());
}
FlushBlockFile(!fKnown, finalize_undo);
m_last_blockfile = nFile;
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index 8f997b0594..3900d2e620 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -207,7 +207,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
} else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) {
LogPrintf("[snapshot] cleaning up unneeded background chainstate, then reinitializing\n");
if (!chainman.ValidatedSnapshotCleanup()) {
- AbortNode("Background chainstate cleanup failed unexpectedly.");
+ return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Background chainstate cleanup failed unexpectedly.")};
}
// Because ValidatedSnapshotCleanup() has torn down chainstates with
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index 77240cafe9..2e35035c28 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -42,7 +42,8 @@ struct ChainstateLoadOptions {
//! and exit cleanly in the interrupted case.
enum class ChainstateLoadStatus {
SUCCESS,
- FAILURE,
+ FAILURE, //!< Generic failure which reindexing may fix
+ FAILURE_FATAL, //!< Fatal error which should not prompt to reindex
FAILURE_INCOMPATIBLE_DB,
FAILURE_INSUFFICIENT_DBCACHE,
INTERRUPTED,
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 6f859e2d0d..41f4a4d06b 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -62,7 +62,7 @@ public:
/**
* Return the fee in satoshis for a vsize of 1000 vbytes
*/
- CAmount GetFeePerK() const { return GetFee(1000); }
+ CAmount GetFeePerK() const { return nSatoshisPerK; }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index ae226f7011..c8f2df781b 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -24,6 +24,7 @@
#include <algorithm>
#include <cassert>
+#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
@@ -527,7 +528,7 @@ bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
}
}
-CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath)
+CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates)
: m_estimation_filepath{estimation_filepath}
{
static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
@@ -545,9 +546,22 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath
shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
- // If the fee estimation file is present, read recorded estimations
AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")};
- if (est_file.IsNull() || !Read(est_file)) {
+
+ // Whenever the fee estimation file is not present return early
+ if (est_file.IsNull()) {
+ LogPrintf("%s is not found. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
+ return;
+ }
+
+ std::chrono::hours file_age = GetFeeEstimatorFileAge();
+ // fee estimate file must not be too old to avoid wrong fee estimates.
+ if (file_age > MAX_FILE_AGE && !read_stale_estimates) {
+ LogPrintf("Fee estimation file %s too old (age=%lld > %lld hours) and will not be used to avoid serving stale estimates.\n", fs::PathToString(m_estimation_filepath), Ticks<std::chrono::hours>(file_age), Ticks<std::chrono::hours>(MAX_FILE_AGE));
+ return;
+ }
+
+ if (!Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
}
@@ -903,10 +917,16 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
void CBlockPolicyEstimator::Flush() {
FlushUnconfirmed();
+ FlushFeeEstimates();
+}
+void CBlockPolicyEstimator::FlushFeeEstimates()
+{
AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "wb")};
if (est_file.IsNull() || !Write(est_file)) {
LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
+ } else {
+ LogPrintf("Flushed fee estimates to %s.\n", fs::PathToString(m_estimation_filepath.filename()));
}
}
@@ -1011,6 +1031,13 @@ void CBlockPolicyEstimator::FlushUnconfirmed()
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
}
+std::chrono::hours CBlockPolicyEstimator::GetFeeEstimatorFileAge()
+{
+ auto file_time = std::filesystem::last_write_time(m_estimation_filepath);
+ auto now = std::filesystem::file_time_type::clock::now();
+ return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
+}
+
static std::set<double> MakeFeeSet(const CFeeRate& min_incremental_fee,
double max_filter_fee_rate,
double fee_filter_spacing)
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 775a72a764..52761f03ca 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -14,12 +14,25 @@
#include <util/fs.h>
#include <array>
+#include <chrono>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
+
+// How often to flush fee estimates to fee_estimates.dat.
+static constexpr std::chrono::hours FEE_FLUSH_INTERVAL{1};
+
+/** fee_estimates.dat that are more than 60 hours (2.5 days) will not be read,
+ * as the estimates in the file are stale.
+ */
+static constexpr std::chrono::hours MAX_FILE_AGE{60};
+
+// Whether we allow importing a fee_estimates file older than MAX_FILE_AGE.
+static constexpr bool DEFAULT_ACCEPT_STALE_FEE_ESTIMATES{false};
+
class AutoFile;
class CTxMemPoolEntry;
class TxConfirmStats;
@@ -183,7 +196,7 @@ private:
const fs::path m_estimation_filepath;
public:
/** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
- CBlockPolicyEstimator(const fs::path& estimation_filepath);
+ CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates);
~CBlockPolicyEstimator();
/** Process all the transactions that have been included in a block */
@@ -239,6 +252,13 @@ public:
void Flush()
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
+ /** Record current fee estimations. */
+ void FlushFeeEstimates()
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
+
+ /** Calculates the age of the file, since last modified */
+ std::chrono::hours GetFeeEstimatorFileAge();
+
private:
mutable Mutex m_cs_fee_estimator;
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index ae5dccfb5a..4866feed67 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -7,6 +7,7 @@
#include <hash.h>
#include <secp256k1.h>
+#include <secp256k1_ellswift.h>
#include <secp256k1_extrakeys.h>
#include <secp256k1_recovery.h>
#include <secp256k1_schnorrsig.h>
@@ -335,6 +336,20 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
return true;
}
+CPubKey EllSwiftPubKey::Decode() const
+{
+ secp256k1_pubkey pubkey;
+ secp256k1_ellswift_decode(secp256k1_context_static, &pubkey, UCharCast(m_pubkey.data()));
+
+ size_t sz = CPubKey::COMPRESSED_SIZE;
+ std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes;
+
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED);
+ assert(sz == vch_bytes.size());
+
+ return CPubKey{vch_bytes.begin(), vch_bytes.end()};
+}
+
void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
diff --git a/src/pubkey.h b/src/pubkey.h
index b3edafea7f..d8d5e3d85b 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -291,6 +291,38 @@ public:
SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
};
+/** An ElligatorSwift-encoded public key. */
+struct EllSwiftPubKey
+{
+private:
+ static constexpr size_t SIZE = 64;
+ std::array<std::byte, SIZE> m_pubkey;
+
+public:
+ /** Construct a new ellswift public key from a given serialization. */
+ EllSwiftPubKey(const std::array<std::byte, SIZE>& ellswift) :
+ m_pubkey(ellswift) {}
+
+ /** Decode to normal compressed CPubKey (for debugging purposes). */
+ CPubKey Decode() const;
+
+ // Read-only access for serialization.
+ const std::byte* data() const { return m_pubkey.data(); }
+ static constexpr size_t size() { return SIZE; }
+ auto begin() const { return m_pubkey.cbegin(); }
+ auto end() const { return m_pubkey.cend(); }
+
+ bool friend operator==(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
+ {
+ return a.m_pubkey == b.m_pubkey;
+ }
+
+ bool friend operator!=(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
+ {
+ return a.m_pubkey != b.m_pubkey;
+ }
+};
+
struct CExtPubKey {
unsigned char version[4];
unsigned char nDepth;
diff --git a/src/random.cpp b/src/random.cpp
index 54500e6cc6..39ceae4206 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -599,6 +599,12 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
return ret;
}
+void FastRandomContext::fillrand(Span<std::byte> output)
+{
+ if (requires_seed) RandomSeed();
+ rng.Keystream(UCharCast(output.data()), output.size());
+}
+
FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0)
{
rng.SetKey32(seed.begin());
diff --git a/src/random.h b/src/random.h
index 49c0dff5bf..50f56ed911 100644
--- a/src/random.h
+++ b/src/random.h
@@ -213,6 +213,9 @@ public:
/** Generate random bytes. */
std::vector<unsigned char> randbytes(size_t len);
+ /** Fill a byte Span with random bytes. */
+ void fillrand(Span<std::byte> output);
+
/** Generate a random 32-bit integer. */
uint32_t rand32() noexcept { return randbits(32); }
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index edc0fb05d7..5f58eef1db 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -371,10 +371,10 @@ UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<s
}
if (!positional_args.empty()) {
- // Use __pushKV instead of pushKV to avoid overwriting an explicit
+ // Use pushKVEnd instead of pushKV to avoid overwriting an explicit
// "args" value with an implicit one. Let the RPC server handle the
// request as given.
- params.__pushKV("args", positional_args);
+ params.pushKVEnd("args", positional_args);
}
return params;
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 89c403b6f5..11d2874961 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -351,8 +351,8 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempoo
entryToJSON(pool, info, e);
// Mempool has unique entries so there is no advantage in using
// UniValue::pushKV, which checks if the key already exists in O(N).
- // UniValue::__pushKV is used instead which currently is O(1).
- o.__pushKV(hash.ToString(), info);
+ // UniValue::pushKVEnd is used instead which currently is O(1).
+ o.pushKVEnd(hash.ToString(), info);
}
return o;
} else {
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index d39efcb245..daf751111f 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -437,7 +437,7 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
if (options.exists(fr->first)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + fr->first + " specified multiple times");
}
- options.__pushKV(fr->first, *fr->second);
+ options.pushKVEnd(fr->first, *fr->second);
argsIn.erase(fr);
}
continue;
diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml
index 0b904a4e38..5a00b65a33 100644
--- a/src/secp256k1/.cirrus.yml
+++ b/src/secp256k1/.cirrus.yml
@@ -21,6 +21,7 @@ env:
ECDH: no
RECOVERY: no
SCHNORRSIG: no
+ ELLSWIFT: no
### test options
SECP256K1_TEST_ITERS:
BENCH: yes
@@ -74,12 +75,12 @@ task:
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128}
- - env: {WIDEMUL: int128_struct}
- - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int128_struct, ELLSWIFT: yes}
+ - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- - env: {WIDEMUL: int128, ASM: x86_64}
+ - env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes}
- env: { RECOVERY: yes, SCHNORRSIG: yes}
- env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
@@ -154,6 +155,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
<< : *MERGE_BASE
test_script:
@@ -173,10 +175,11 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
matrix:
- env: {}
- - env: {EXPERIMENTAL: yes, ASM: arm}
+ - env: {EXPERIMENTAL: yes, ASM: arm32}
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -193,6 +196,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
<< : *MERGE_BASE
test_script:
@@ -210,6 +214,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
<< : *MERGE_BASE
test_script:
@@ -247,6 +252,7 @@ task:
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
# This will detect some MinGW-w64 tools but then make will need only
@@ -286,6 +292,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
matrix:
- name: "Valgrind (memcheck)"
@@ -361,6 +368,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -397,13 +405,13 @@ task:
- PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
configure_script:
- '%x64_NATIVE_TOOLS%'
- - cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
+ - cmake -E env CFLAGS="/WX" cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
build_script:
- '%x64_NATIVE_TOOLS%'
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
check_script:
- '%x64_NATIVE_TOOLS%'
- - ctest --test-dir build -j 5
+ - ctest -C RelWithDebInfo --test-dir build -j 5
- build\src\RelWithDebInfo\bench_ecmult.exe
- build\src\RelWithDebInfo\bench_internal.exe
- build\src\RelWithDebInfo\bench.exe
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index bc7e499de7..574902b8b5 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -59,5 +59,7 @@ build-aux/compile
build-aux/test-driver
libsecp256k1.pc
+### CMake
+/CMakeUserPresets.json
# Default CMake build directory.
/build
diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md
index 6d23662a93..8e31edc6ee 100644
--- a/src/secp256k1/CHANGELOG.md
+++ b/src/secp256k1/CHANGELOG.md
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.3.2] - 2023-05-13
+We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
+
+#### Security
+ - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1.
+
+#### Fixed
+ - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far.
+
+#### Changed
+ - Various improvements and changes to CMake builds. CMake builds remain experimental.
+ - Made API versioning consistent with GNU Autotools builds.
+ - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library.
+ - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts.
+ - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake).
+
+#### ABI Compatibility
+The ABI is compatible with versions 0.3.0 and 0.3.1.
+
## [0.3.1] - 2023-04-10
We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`.
@@ -68,7 +87,8 @@ This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
Therefore, this version number does not uniquely identify a set of source files.
-[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...HEAD
+[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD
+[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt
index a70165e356..3107eb3bf1 100644
--- a/src/secp256k1/CMakeLists.txt
+++ b/src/secp256k1/CMakeLists.txt
@@ -1,16 +1,33 @@
cmake_minimum_required(VERSION 3.13)
-if(CMAKE_VERSION VERSION_GREATER 3.14)
+if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
# MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction.
cmake_policy(SET CMP0091 NEW)
# MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.
cmake_policy(SET CMP0092 NEW)
endif()
-# 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.
-project(libsecp256k1 VERSION 0.3.2 LANGUAGES C)
+project(libsecp256k1
+ # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
+ # the API. All changes in experimental modules are treated as
+ # backwards-compatible and therefore at most increase the minor version.
+ VERSION 0.3.3
+ DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
+ HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
+ LANGUAGES C
+)
+
+if(CMAKE_VERSION VERSION_LESS 3.21)
+ get_directory_property(parent_directory PARENT_DIRECTORY)
+ if(parent_directory)
+ set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ else()
+ set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ endif()
+ unset(parent_directory)
+endif()
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
@@ -18,7 +35,7 @@ project(libsecp256k1 VERSION 0.3.2 LANGUAGES C)
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2)
-set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
+set(${PROJECT_NAME}_LIB_VERSION_REVISION 3)
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
set(CMAKE_C_STANDARD 90)
@@ -26,36 +43,42 @@ set(CMAKE_C_EXTENSIONS OFF)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
-# We do not use CMake's BUILD_SHARED_LIBS option.
-option(SECP256K1_BUILD_SHARED "Build shared library." ON)
-option(SECP256K1_BUILD_STATIC "Build static library." ON)
-if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC)
- message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.")
+option(BUILD_SHARED_LIBS "Build shared libraries." ON)
+option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
+if(SECP256K1_DISABLE_SHARED)
+ set(BUILD_SHARED_LIBS OFF)
endif()
+option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
+
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
if(SECP256K1_ENABLE_MODULE_ECDH)
- add_definitions(-DENABLE_MODULE_ECDH=1)
+ add_compile_definitions(ENABLE_MODULE_ECDH=1)
endif()
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
if(SECP256K1_ENABLE_MODULE_RECOVERY)
- add_definitions(-DENABLE_MODULE_RECOVERY=1)
+ add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
endif()
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
- add_definitions(-DENABLE_MODULE_SCHNORRSIG=1)
+ add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
endif()
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- add_definitions(-DENABLE_MODULE_EXTRAKEYS=1)
+ add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
+endif()
+
+option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
+if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
+ add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
endif()
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
- add_definitions(-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1)
+ add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
endif()
set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]")
@@ -65,7 +88,7 @@ check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO")
set(SECP256K1_ECMULT_WINDOW_SIZE 15)
endif()
-add_definitions(-DECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
+add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]")
set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8)
@@ -73,29 +96,35 @@ check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS)
if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO")
set(SECP256K1_ECMULT_GEN_PREC_BITS 4)
endif()
-add_definitions(-DECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
+add_compile_definitions(ECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
- add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1)
+ add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1)
endif()
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
-set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]")
-set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm")
+set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
+set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
check_string_option_value(SECP256K1_ASM)
-if(SECP256K1_ASM STREQUAL "arm")
+if(SECP256K1_ASM STREQUAL "arm32")
enable_language(ASM)
- add_definitions(-DUSE_EXTERNAL_ASM=1)
+ include(CheckArm32Assembly)
+ check_arm32_assembly()
+ if(HAVE_ARM32_ASM)
+ add_compile_definitions(USE_EXTERNAL_ASM=1)
+ else()
+ message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
+ endif()
elseif(SECP256K1_ASM)
- include(Check64bitAssembly)
- check_64bit_assembly()
- if(HAS_64BIT_ASM)
+ include(CheckX86_64Assembly)
+ check_x86_64_assembly()
+ if(HAVE_X86_64_ASM)
set(SECP256K1_ASM "x86_64")
- add_definitions(-DUSE_ASM_X86_64=1)
+ add_compile_definitions(USE_ASM_X86_64=1)
elseif(SECP256K1_ASM STREQUAL "AUTO")
set(SECP256K1_ASM "OFF")
else()
@@ -105,8 +134,8 @@ endif()
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
if(NOT SECP256K1_EXPERIMENTAL)
- if(SECP256K1_ASM STREQUAL "arm")
- message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
+ if(SECP256K1_ASM STREQUAL "arm32")
+ message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
endif()
endif()
@@ -118,7 +147,7 @@ if(SECP256K1_VALGRIND)
if(Valgrind_FOUND)
set(SECP256K1_VALGRIND ON)
include_directories(${Valgrind_INCLUDE_DIR})
- add_definitions(-DVALGRIND)
+ add_compile_definitions(VALGRIND)
elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
set(SECP256K1_VALGRIND OFF)
else()
@@ -165,42 +194,51 @@ mark_as_advanced(
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)
-if(CMAKE_CONFIGURATION_TYPES)
- set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage")
-endif()
-
-get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE)
-if(cached_cmake_build_type)
+get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+set(default_build_type "RelWithDebInfo")
+if(is_multi_config)
+ set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
+ "Supported configuration types."
+ FORCE
+ )
+else()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
- STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage"
+ STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
)
+ if(NOT CMAKE_BUILD_TYPE)
+ message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
+ set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
+ "Choose the type of build."
+ FORCE
+ )
+ endif()
endif()
-set(default_build_type "RelWithDebInfo")
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
- message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
- set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
-endif()
-
-include(TryAddCompileOption)
+include(TryAppendCFlags)
if(MSVC)
- try_add_compile_option(/W2)
- try_add_compile_option(/wd4146)
+ # Keep the following commands ordered lexicographically.
+ try_append_c_flags(/W3) # Production quality warning level.
+ try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
+ try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
+ try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
+ # Eliminate deprecation warnings for the older, less secure functions.
+ add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
- try_add_compile_option(-pedantic)
- try_add_compile_option(-Wall)
- try_add_compile_option(-Wcast-align)
- try_add_compile_option(-Wcast-align=strict)
- try_add_compile_option(-Wconditional-uninitialized)
- try_add_compile_option(-Wextra)
- try_add_compile_option(-Wnested-externs)
- try_add_compile_option(-Wno-long-long)
- try_add_compile_option(-Wno-overlength-strings)
- try_add_compile_option(-Wno-unused-function)
- try_add_compile_option(-Wreserved-identifier)
- try_add_compile_option(-Wshadow)
- try_add_compile_option(-Wstrict-prototypes)
- try_add_compile_option(-Wundef)
+ # Keep the following commands ordered lexicographically.
+ try_append_c_flags(-pedantic)
+ try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers.
+ try_append_c_flags(-Wcast-align) # GCC >= 2.95.
+ try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0.
+ try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only.
+ try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
+ try_append_c_flags(-Wnested-externs)
+ try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
+ try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
+ try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall.
+ try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only.
+ try_append_c_flags(-Wshadow)
+ try_append_c_flags(-Wstrict-prototypes)
+ try_append_c_flags(-Wundef)
endif()
set(CMAKE_C_VISIBILITY_PRESET hidden)
@@ -225,13 +263,19 @@ message("\n")
message("secp256k1 configure summary")
message("===========================")
message("Build artifacts:")
-message(" shared library ...................... ${SECP256K1_BUILD_SHARED}")
-message(" static library ...................... ${SECP256K1_BUILD_STATIC}")
+if(BUILD_SHARED_LIBS)
+ set(library_type "Shared")
+else()
+ set(library_type "Static")
+endif()
+
+message(" library type ........................ ${library_type}")
message("Optional modules:")
message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
+message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
@@ -268,7 +312,7 @@ message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
get_directory_property(compile_options COMPILE_OPTIONS)
string(REPLACE ";" " " compile_options "${compile_options}")
message("Compile options ....................... " ${compile_options})
-if(DEFINED CMAKE_BUILD_TYPE)
+if(NOT is_multi_config)
message("Build type:")
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
@@ -276,7 +320,7 @@ if(DEFINED CMAKE_BUILD_TYPE)
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
else()
- message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
+ message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
message("RelWithDebInfo configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
diff --git a/src/secp256k1/CMakePresets.json b/src/secp256k1/CMakePresets.json
new file mode 100644
index 0000000000..b35cd80579
--- /dev/null
+++ b/src/secp256k1/CMakePresets.json
@@ -0,0 +1,19 @@
+{
+ "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0},
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "dev-mode",
+ "displayName": "Development mode (intended only for developers of the library)",
+ "cacheVariables": {
+ "SECP256K1_EXPERIMENTAL": "ON",
+ "SECP256K1_ENABLE_MODULE_RECOVERY": "ON",
+ "SECP256K1_BUILD_EXAMPLES": "ON"
+ },
+ "warnings": {
+ "dev": true,
+ "uninitialized": true
+ }
+ }
+ ]
+}
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 36e26e3e8a..ee14ac4509 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -1,5 +1,3 @@
-.PHONY: clean-precomp precomp
-
ACLOCAL_AMFLAGS = -I build-aux/m4
# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo
@@ -65,6 +63,7 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
+noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
@@ -190,11 +189,11 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
CLEANFILES = $(EXTRA_PROGRAMS)
precompute_ecmult_SOURCES = src/precompute_ecmult.c
-precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
precompute_ecmult_LDADD = $(COMMON_LIB)
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
-precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# See Automake manual, Section "Errors with distclean".
@@ -202,7 +201,7 @@ precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# otherwise make's decision whether to rebuild them (even in the first
# 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`.
+# forced by deleting them.
src/precomputed_ecmult.c:
$(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT)
./precompute_ecmult$(EXEEXT)
@@ -217,11 +216,29 @@ precomp: $(PRECOMP)
# e.g., after `make maintainer-clean`).
BUILT_SOURCES = $(PRECOMP)
-maintainer-clean-local: clean-precomp
-
+.PHONY: clean-precomp
clean-precomp:
rm -f $(PRECOMP)
+maintainer-clean-local: clean-precomp
+
+### Pregenerated test vectors
+### (see the comments in the previous section for detailed rationale)
+TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
+
+src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h:
+ mkdir -p $(@D)
+ python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@
+testvectors: $(TESTVECTORS)
+
+BUILT_SOURCES += $(TESTVECTORS)
+
+.PHONY: clean-testvectors
+clean-testvectors:
+ rm -f $(TESTVECTORS)
+maintainer-clean-local: clean-testvectors
+
+### Additional files to distribute
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
EXTRA_DIST += examples/EXAMPLES_COPYING
@@ -231,6 +248,9 @@ EXTRA_DIST += sage/group_prover.sage
EXTRA_DIST += sage/prove_group_implementations.sage
EXTRA_DIST += sage/secp256k1_params.sage
EXTRA_DIST += sage/weierstrass_prover.sage
+EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING
+EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
+EXTRA_DIST += tools/tests_wycheproof_generate.py
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
@@ -248,19 +268,6 @@ if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif
-EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING
-EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
-EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
-EXTRA_DIST += tools/tests_wycheproof_generate.py
-
-TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
-
-src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h:
- python3 tools/tests_wycheproof_generate.py src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@
-
-testvectors: $(TESTVECTORS)
-
-maintainer-clean-testvectors: clean-testvectors
-
-clean-testvectors:
- rm -f $(TESTVECTORS)
+if ENABLE_MODULE_ELLSWIFT
+include src/modules/ellswift/Makefile.am.include
+endif
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index 624f5e956e..11adef4f22 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -1,12 +1,31 @@
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
-AC_DEFUN([SECP_64BIT_ASM_CHECK],[
+AC_DEFUN([SECP_X86_64_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
- ]])],[has_64bit_asm=yes],[has_64bit_asm=no])
-AC_MSG_RESULT([$has_64bit_asm])
+ ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no])
+AC_MSG_RESULT([$has_x86_64_asm])
+])
+
+AC_DEFUN([SECP_ARM32_ASM_CHECK], [
+ AC_MSG_CHECKING(for ARM32 assembly availability)
+ SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS"
+ CFLAGS="-x assembler"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[
+ .syntax unified
+ .eabi_attribute 24, 1
+ .eabi_attribute 25, 1
+ .text
+ .global main
+ main:
+ ldr r0, =0x002A
+ mov r7, #1
+ swi 0
+ ]])], [has_arm32_asm=yes], [has_arm32_asm=no])
+ AC_MSG_RESULT([$has_arm32_asm])
+ CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS"
])
AC_DEFUN([SECP_VALGRIND_CHECK],[
@@ -21,6 +40,7 @@ if test x"$has_valgrind" != x"yes"; then
# error "Valgrind does not support this platform."
#endif
]])], [has_valgrind=yes])
+ CPPFLAGS="$CPPFLAGS_TEMP"
fi
AC_MSG_RESULT($has_valgrind)
])
diff --git a/src/secp256k1/ci/cirrus.sh b/src/secp256k1/ci/cirrus.sh
index b2af03bb5d..8d82818611 100755
--- a/src/secp256k1/ci/cirrus.sh
+++ b/src/secp256k1/ci/cirrus.sh
@@ -36,8 +36,7 @@ case "$WRAPPER_CMD" in
*wine*)
# Make sure to shutdown wineserver whenever we exit.
trap "wineserver -k || true" EXIT INT HUP
- # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
- wineserver -p && wine hh.exe
+ wineserver -p
;;
esac
@@ -62,6 +61,7 @@ fi
--with-ecmult-window="$ECMULTWINDOW" \
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
+ --enable-module-ellswift="$ELLSWIFT" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile
index a83a4e36db..54eafcab25 100644
--- a/src/secp256k1/ci/linux-debian.Dockerfile
+++ b/src/secp256k1/ci/linux-debian.Dockerfile
@@ -29,9 +29,10 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
git clone https://github.com/mstorsjo/msvc-wine && \
mkdir /opt/msvc && \
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
- msvc-wine/install.sh /opt/msvc
-
-# Initialize the wine environment. Wait until the wineserver process has
-# exited before closing the session, to avoid corrupting the wine prefix.
-RUN wine64 wineboot --init && \
+# Since commit 2146cbfaf037e21de56c7157ec40bb6372860f51, the
+# msvc-wine effectively initializes the wine prefix when running
+# the install.sh script.
+ msvc-wine/install.sh /opt/msvc && \
+# Wait until the wineserver process has exited before closing the session,
+# to avoid corrupting the wine prefix.
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done
diff --git a/src/secp256k1/cmake/CheckArm32Assembly.cmake b/src/secp256k1/cmake/CheckArm32Assembly.cmake
new file mode 100644
index 0000000000..15c44b24b0
--- /dev/null
+++ b/src/secp256k1/cmake/CheckArm32Assembly.cmake
@@ -0,0 +1,6 @@
+function(check_arm32_assembly)
+ try_compile(HAVE_ARM32_ASM
+ ${CMAKE_BINARY_DIR}/check_arm32_assembly
+ SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s
+ )
+endfunction()
diff --git a/src/secp256k1/cmake/CheckStringOptionValue.cmake b/src/secp256k1/cmake/CheckStringOptionValue.cmake
index bc4d7b5749..5a4d939b9e 100644
--- a/src/secp256k1/cmake/CheckStringOptionValue.cmake
+++ b/src/secp256k1/cmake/CheckStringOptionValue.cmake
@@ -1,11 +1,9 @@
function(check_string_option_value option)
get_property(expected_values CACHE ${option} PROPERTY STRINGS)
if(expected_values)
- foreach(value IN LISTS expected_values)
- if(value STREQUAL "${${option}}")
- return()
- endif()
- endforeach()
+ if(${option} IN_LIST expected_values)
+ return()
+ endif()
message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.")
endif()
message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.")
diff --git a/src/secp256k1/cmake/Check64bitAssembly.cmake b/src/secp256k1/cmake/CheckX86_64Assembly.cmake
index 3f65887765..ae82cd476e 100644
--- a/src/secp256k1/cmake/Check64bitAssembly.cmake
+++ b/src/secp256k1/cmake/CheckX86_64Assembly.cmake
@@ -1,6 +1,6 @@
include(CheckCSourceCompiles)
-function(check_64bit_assembly)
+function(check_x86_64_assembly)
check_c_source_compiles("
#include <stdint.h>
@@ -9,6 +9,6 @@ function(check_64bit_assembly)
uint64_t a = 11, tmp;
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
}
- " HAS_64BIT_ASM)
- set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE)
+ " HAVE_X86_64_ASM)
+ set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE)
endfunction()
diff --git a/src/secp256k1/cmake/FindValgrind.cmake b/src/secp256k1/cmake/FindValgrind.cmake
index f6c1f58649..3af5e691e4 100644
--- a/src/secp256k1/cmake/FindValgrind.cmake
+++ b/src/secp256k1/cmake/FindValgrind.cmake
@@ -1,4 +1,4 @@
-if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+if(CMAKE_HOST_APPLE)
find_program(BREW_COMMAND brew)
execute_process(
COMMAND ${BREW_COMMAND} --prefix valgrind
diff --git a/src/secp256k1/cmake/TryAddCompileOption.cmake b/src/secp256k1/cmake/TryAddCompileOption.cmake
deleted file mode 100644
index f53c252c2d..0000000000
--- a/src/secp256k1/cmake/TryAddCompileOption.cmake
+++ /dev/null
@@ -1,23 +0,0 @@
-include(CheckCCompilerFlag)
-
-function(try_add_compile_option option)
- string(MAKE_C_IDENTIFIER ${option} result)
- string(TOUPPER ${result} result)
- set(result "C_SUPPORTS${result}")
- set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
- if(NOT MSVC)
- set(CMAKE_REQUIRED_FLAGS "-Werror")
- endif()
- check_c_compiler_flag(${option} ${result})
- if(${result})
- get_property(compile_options
- DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- PROPERTY COMPILE_OPTIONS
- )
- list(APPEND compile_options "${option}")
- set_property(
- DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- PROPERTY COMPILE_OPTIONS "${compile_options}"
- )
- endif()
-endfunction()
diff --git a/src/secp256k1/cmake/TryAppendCFlags.cmake b/src/secp256k1/cmake/TryAppendCFlags.cmake
new file mode 100644
index 0000000000..1d81a9317a
--- /dev/null
+++ b/src/secp256k1/cmake/TryAppendCFlags.cmake
@@ -0,0 +1,24 @@
+include(CheckCCompilerFlag)
+
+function(secp256k1_check_c_flags_internal flags output)
+ string(MAKE_C_IDENTIFIER "${flags}" result)
+ string(TOUPPER "${result}" result)
+ set(result "C_SUPPORTS_${result}")
+ if(NOT MSVC)
+ set(CMAKE_REQUIRED_FLAGS "-Werror")
+ endif()
+
+ # This avoids running a linker.
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ check_c_compiler_flag("${flags}" ${result})
+
+ set(${output} ${${result}} PARENT_SCOPE)
+endfunction()
+
+# Append flags to the COMPILE_OPTIONS directory property if CC accepts them.
+macro(try_append_c_flags)
+ secp256k1_check_c_flags_internal("${ARGV}" result)
+ if(result)
+ add_compile_options(${ARGV})
+ endif()
+endmacro()
diff --git a/src/secp256k1/cmake/source_arm32.s b/src/secp256k1/cmake/source_arm32.s
new file mode 100644
index 0000000000..d3d9347057
--- /dev/null
+++ b/src/secp256k1/cmake/source_arm32.s
@@ -0,0 +1,9 @@
+.syntax unified
+.eabi_attribute 24, 1
+.eabi_attribute 25, 1
+.text
+.global main
+main:
+ ldr r0, =0x002A
+ mov r7, #1
+ swi 0
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 0b555eac67..82cf95132d 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -5,7 +5,7 @@ AC_PREREQ([2.60])
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
define(_PKG_VERSION_MINOR, 3)
-define(_PKG_VERSION_PATCH, 2)
+define(_PKG_VERSION_PATCH, 3)
define(_PKG_VERSION_IS_RELEASE, false)
# The library version is based on libtool versioning of the ABI. The set of
@@ -14,7 +14,7 @@ define(_PKG_VERSION_IS_RELEASE, false)
# 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, 2)
-define(_LIB_VERSION_REVISION, 2)
+define(_LIB_VERSION_REVISION, 3)
define(_LIB_VERSION_AGE, 0)
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
@@ -121,8 +121,12 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
# libtool makes the same assumption internally.
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
- SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
- SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
+ SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level.
+ SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
+ SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
+ SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
+ # Eliminate deprecation warnings for the older, less secure functions.
+ CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS"
# We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when
# importing variables from a statically linked secp256k1.
# (See the libtool manual, section "Windows DLLs" for background.)
@@ -186,6 +190,10 @@ AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
+AC_ARG_ENABLE(module_ellswift,
+ AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
+
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
@@ -198,8 +206,8 @@ AC_ARG_ENABLE(external_default_callbacks,
# * and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
-AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
-[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
+AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
+[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
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].]
@@ -264,8 +272,8 @@ else
fi
if test x"$req_asm" = x"auto"; then
- SECP_64BIT_ASM_CHECK
- if test x"$has_64bit_asm" = x"yes"; then
+ SECP_X86_64_ASM_CHECK
+ if test x"$has_x86_64_asm" = x"yes"; then
set_asm=x86_64
fi
if test x"$set_asm" = x; then
@@ -275,12 +283,16 @@ else
set_asm=$req_asm
case $set_asm in
x86_64)
- SECP_64BIT_ASM_CHECK
- if test x"$has_64bit_asm" != x"yes"; then
+ SECP_X86_64_ASM_CHECK
+ if test x"$has_x86_64_asm" != x"yes"; then
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
- arm)
+ arm32)
+ SECP_ARM32_ASM_CHECK
+ if test x"$has_arm32_asm" != x"yes"; then
+ AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
+ fi
;;
no)
;;
@@ -297,7 +309,7 @@ case $set_asm in
x86_64)
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
;;
-arm)
+arm32)
enable_external_asm=yes
;;
no)
@@ -394,6 +406,10 @@ if test x"$enable_module_schnorrsig" = x"yes"; then
enable_module_extrakeys=yes
fi
+if test x"$enable_module_ellswift" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_ELLSWIFT, 1, [Define this symbol to enable the ElligatorSwift module])
+fi
+
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
@@ -414,8 +430,8 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
AC_MSG_NOTICE([******])
else
- if test x"$set_asm" = x"arm"; then
- AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
+ if test x"$set_asm" = x"arm32"; then
+ AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
fi
fi
@@ -436,8 +452,9 @@ 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([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = 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"])
+AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
@@ -457,6 +474,7 @@ echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
+echo " module ellswift = $enable_module_ellswift"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
diff --git a/src/secp256k1/doc/ellswift.md b/src/secp256k1/doc/ellswift.md
new file mode 100644
index 0000000000..7fbb7c1787
--- /dev/null
+++ b/src/secp256k1/doc/ellswift.md
@@ -0,0 +1,483 @@
+# ElligatorSwift for secp256k1 explained
+
+In this document we explain how the `ellswift` module implementation is related to the
+construction in the
+["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
+paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
+
+* [1. Introduction](#1-introduction)
+* [2. The decoding function](#2-the-decoding-function)
+ + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
+* [3. The encoding function](#3-the-encoding-function)
+ + [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates)
+ + [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
+ + [3.3 Finding the inverse](#33-finding-the-inverse)
+ + [3.4 Dealing with special cases](#34-dealing-with-special-cases)
+ + [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
+* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
+ + [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
+
+## 1. Introduction
+
+The `ellswift` module effectively introduces a new 64-byte public key format, with the property
+that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally
+indistinguishable from uniform byte arrays. The module provides functions to convert public keys
+from and to this format, as well as convenience functions for key generation and ECDH that operate
+directly on ellswift-encoded keys.
+
+The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$
+and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on
+the curve.
+
+**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$
+are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid
+x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
+
+**Encoding** a given $x$ coordinate is conceptually done as follows:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements.
+ * With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
+ * Select a uniformly random $t \in L$ and return $(u, t).$
+
+This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full
+$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
+The algorithm finds a uniformly random $(u, t)$ among (almost all) those
+for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
+almost all x-coordinates on the curve (all but at most 39) is close to two times the field size
+(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field).
+
+## 2. The decoding function
+
+First some definitions:
+* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
+ * For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
+* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
+ public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
+ This implies that the order of $E$ is either odd, or a multiple of *4*.
+ If $a=0$, this condition is always fulfilled.
+ * For `secp256k1`, $a=0$ and $b=7.$
+* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
+* Let the function $h(x) = 3x^3 + 4a.$
+* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
+* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
+* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
+* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
+
+**Note**: In the paper:
+* $F_u$ corresponds to $F_{0,u}$ there.
+* $P_u(t)$ is called $P$ there.
+* All $S_u$ sets together correspond to $S$ there.
+* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
+
+Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
+hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
+out of the three right-hand side factors an even number must be non-squares.
+This implies that exactly *1* or exactly *3* out of
+$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
+at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
+to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
+
+**Define** the decoding function $F_u(t)$ as:
+* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
+* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
+
+$P_u(t) = (X(u, t), Y(u, t))$, where:
+
+$$
+\begin{array}{lcl}
+X(u, t) & = & \left\\{\begin{array}{ll}
+ \dfrac{g(u) - t^2}{2t} & a = 0 \\
+ \dfrac{g(u) + h(u)(Y_0(u) + X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0
+\end{array}\right. \\
+Y(u, t) & = & \left\\{\begin{array}{ll}
+ \dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\
+ Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0
+\end{array}\right.
+\end{array}
+$$
+
+$P_u(t)$ is defined:
+* For $a=0$, unless:
+ * $u = 0$ or $t = 0$ (division by zero)
+ * $g(u) = -t^2$ (would give $Y=0$).
+* For $a \neq 0$, unless:
+ * $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
+ * $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
+
+The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
+
+The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where:
+
+$$
+\begin{array}{lcl}
+ x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\
+ x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\
+ x_3 & = & u + 4Y^2 && \\
+ z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3}
+\end{array}
+$$
+
+### 2.1 Decoding for `secp256k1`
+
+Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
+
+**Define** $F_u(t)$ as:
+* Let $X = \dfrac{u^3 + b - t^2}{2t}.$
+* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
+* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
+
+To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
+$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
+
+**Define** $F_u(t)$ as:
+* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
+* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
+* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
+* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
+* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
+* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
+
+The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
+but the approach here is simple enough and gives fairly uniform output even in these cases.
+
+**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there.
+We wish to avoid the need for callers to deal with this special case.
+
+This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and
+in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate).
+
+## 3. The encoding function
+
+To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
+* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
+* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
+* For each of the found $t$ values, verify that $F_u(t) = x.$
+* Return the remaining $t$ values.
+
+The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
+
+$$
+P_u^{-1}(X, Y) = \left\\{\begin{array}{ll}
+Yu\sqrt{-3} - X & a = 0 \\
+\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\
+\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u)
+\end{array}\right.
+$$
+
+The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions,
+it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the
+$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected.
+
+Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$,
+the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid.
+This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of
+$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out.
+
+Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as
+$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square,
+and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined
+before those values are computed.
+
+It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would
+take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take
+precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$
+values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
+any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
+
+### 3.1 Switching to *v, w* coordinates
+
+Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
+$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
+* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
+* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
+* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
+
+$$
+\begin{array}{lcl}
+ x_1 & = & v \\
+ x_2 & = & -u - v \\
+ x_3 & = & u + w^2 \\
+ z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3}
+\end{array}
+$$
+
+We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
+expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
+* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
+* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
+* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
+
+### 3.2 Avoiding computing all inverses
+
+The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
+set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
+
+Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
+uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
+picking a uniformly random element from that, restarting whenever $\bot$ is picked:
+
+**Define** *ElligatorSwift(x)* as:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Compute the set $L = F_u^{-1}(x).$
+ * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
+ * Select a uniformly random $t \in T.$
+ * If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
+
+Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
+random element in it, so we do not need to have all $\bot$ values at the end.
+As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
+we can associate every index in $T$ with exactly one of those formulas, making sure that:
+* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
+* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
+* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
+
+The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
+to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
+for an analysis of all the negligible cases.
+
+If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
+the loop can be simplified to only compute one of the inverses instead of all of them:
+
+**Define** *ElligatorSwift(x)* as:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Pick a uniformly random integer $c$ in $[0,8).$
+ * Let $t = G_{c,u}(x).$
+ * If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
+
+This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
+
+### 3.3 Finding the inverse
+
+To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula.
+Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression).
+Ignoring the negligible cases, we get:
+
+**Define** $G_{c,u}(x)$ as:
+* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
+ * If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
+ * If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
+ * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}.$
+ * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
+* Let $w = \sqrt{s}.$
+* Depending on $c:$
+ * If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
+ * If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
+
+Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
+50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
+with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$
+implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered
+and $\bot$ would have been returned already.
+
+**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4).
+The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to
+have the $G_{c,u}$ be deterministic, and capture all choices in $c.$
+
+Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$
+transformation. Furthermore, that transformation has no effect on $s$ in the first branch
+as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
+
+**Define** $G_{c,u}(x)$ as:
+* If $c \in \\{0, 1, 4, 5\\}:$
+ * If $g(-u-x)$ is square, return $\bot.$
+ * Let $s = -g(u)/(u^2 + ux + x^2 + a).$
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}.$
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
+ * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
+ * If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
+ * If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
+
+This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
+There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
+
+### 3.4 Dealing with special cases
+
+As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs.
+For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness
+we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that
+do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
+$t$ value for multiple $c$ inputs (thereby biasing that encoding):
+
+* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
+ * When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
+ Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
+ fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
+ This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
+ the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
+ encoder anyway as there will generally be more than 8.
+ * When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
+ as it can deal with $g(u)=0$.
+ This is again only possible on even-ordered curves.
+* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
+ * When $s=0$, a division by zero would occur.
+ * When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
+ It is equivalent to checking whether $r=0$.
+ This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
+ A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
+ it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
+* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
+ * For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
+ * For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $2w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
+
+**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
+* If $a=0$ and $u=0$, return $\bot.$
+* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
+* If $c \in \\{0, 1, 4, 5\\}:$
+ * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
+ * If $g(-u-x)$ is square, return $\bot.$
+ * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
+ * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
+ * If $s = 0$, return $\bot.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}$; return $\bot$ if not square.
+* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
+ * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
+ * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
+ * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
+* If $a=0$ and $t=0$, return $\bot$ (even curves only).
+* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
+* Return $t.$
+
+Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
+for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
+* All cases where $P_u(t)$ is not defined:
+ * For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
+ * For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
+* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
+
+These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
+
+### 3.5 Encoding for `secp256k1`
+
+Specialized for odd-ordered $a=0$ curves:
+
+**Define** $G_{c,u}(x)$ as:
+* If $u=0$, return $\bot.$
+* If $c \in \\{0, 1, 4, 5\\}:$
+ * If $(-u-x)^3 + b$ is square, return $\bot$
+ * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
+ * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
+ * If $s = 0$, return $\bot.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}$; return $\bot$ if not square.
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
+ * If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
+ * If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
+ * If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
+
+This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
+
+And the x-only ElligatorSwift encoding algorithm is still:
+
+**Define** *ElligatorSwift(x)* as:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Pick a uniformly random integer $c$ in $[0,8).$
+ * Let $t = G_{c,u}(x).$
+ * If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
+
+Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
+While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
+combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
+
+## 4. Encoding and decoding full *(x, y)* coordinates
+
+So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
+for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
+in $t$ as well.
+
+Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are
+mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$
+being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order
+of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead.
+
+Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode
+the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the
+four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$
+
+**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit.
+
+To encode the sign of $y$ in the sign of $Y:$
+
+**Define** *Decode(u, t)* for full $(x, y)$ as:
+* Let $(X, Y) = P_u(t).$
+* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
+* Let $y = \sqrt{g(x)}.$
+* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
+
+And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
+
+**Define** $G_{c,u}(x, y)$ as:
+* If $c \in \\{0, 1\\}:$
+ * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
+ * If $g(-u-x)$ is square, return $\bot.$
+ * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
+ * If $c = 3$ and $r = 0$, return $\bot.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}$; return $\bot$ if not square.
+* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
+ * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
+
+Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
+This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
+
+In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation
+of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
+$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
+
+### 4.1 Full *(x, y)* coordinates for `secp256k1`
+
+For $a=0$ curves, there is another option. Note that for those,
+the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
+encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
+as decoder:
+
+**Define** *Decode(u, t)* as:
+* Let $u'=u$ if $u \neq 0$; $1$ otherwise.
+* Let $t'=t$ if $t \neq 0$; $1$ otherwise.
+* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
+* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
+* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
+* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
+* Let $y = \sqrt{g(x)}.$
+* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
+
+This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
+
+The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$
+
+This is implemented in `secp256k1_ellswift_elligatorswift_var`.
+
+Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points
+where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in
+[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift
+in the first place.
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
index 70a35f0910..ea6087c9ff 100644
--- a/src/secp256k1/doc/release-process.md
+++ b/src/secp256k1/doc/release-process.md
@@ -12,12 +12,40 @@ It is best if the maintainers are present during the release, so they can help e
This process also assumes that there will be no minor releases for old major releases.
+We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
+
+## Sanity Checks
+Perform these checks before creating a release:
+
+1. Ensure `make distcheck` doesn't fail.
+```shell
+./autogen.sh && ./configure --enable-dev-mode && make distcheck
+```
+2. Check installation with autotools:
+```shell
+dir=$(mktemp -d)
+./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -l $dir/include $dir/lib
+gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
+```
+3. Check installation with CMake:
+```shell
+dir=$(mktemp -d)
+build=$(mktemp -d)
+cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -l $dir/include $dir/lib*
+gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
+```
+
## Regular release
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
- * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`),
- * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
- * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
+ * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
+ * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
+ * removing the `[Unreleased]` section header, and
+ * including an entry for `### ABI Compatibility` if it doesn't exist that mentions the library soname of the release,
+ * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
+ * if this is not a patch release
+ * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
+ * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
2. After the PR is merged, tag the commit and push it:
```
RELEASE_COMMIT=<merge commit of step 1>
@@ -25,8 +53,9 @@ This process also assumes that there will be no minor releases for old major rel
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
- * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, and
- * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`.
+ * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
+ * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
+ * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
If other maintainers are not present to approve the PR, it can be merged without ACKs.
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
@@ -35,14 +64,14 @@ This process also assumes that there will be no minor releases for old major rel
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
-1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
+1. If there's no maintenance branch `$MAJOR.$MINOR`, create one:
```
- git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
+ git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1))
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
```
2. Open a pull request to the `$MAJOR.$MINOR` branch that
* includes the bugfixes,
- * finalizes the release notes,
+ * finalizes the release notes similar to a regular release,
* increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
diff --git a/src/secp256k1/examples/CMakeLists.txt b/src/secp256k1/examples/CMakeLists.txt
index 0884b645e0..e095b7f84f 100644
--- a/src/secp256k1/examples/CMakeLists.txt
+++ b/src/secp256k1/examples/CMakeLists.txt
@@ -2,33 +2,26 @@ add_library(example INTERFACE)
target_include_directories(example INTERFACE
${PROJECT_SOURCE_DIR}/include
)
-target_compile_options(example INTERFACE
- $<$<C_COMPILER_ID:MSVC>:/wd4005>
-)
target_link_libraries(example INTERFACE
+ secp256k1
$<$<PLATFORM_ID:Windows>:bcrypt>
)
-if(SECP256K1_BUILD_SHARED)
- target_link_libraries(example INTERFACE secp256k1)
-elseif(SECP256K1_BUILD_STATIC)
- target_link_libraries(example INTERFACE secp256k1_static)
- if(MSVC)
- target_link_options(example INTERFACE /IGNORE:4217)
- endif()
+if(NOT BUILD_SHARED_LIBS AND MSVC)
+ target_link_options(example INTERFACE /IGNORE:4217)
endif()
add_executable(ecdsa_example ecdsa.c)
target_link_libraries(ecdsa_example example)
-add_test(ecdsa_example ecdsa_example)
+add_test(NAME ecdsa_example COMMAND ecdsa_example)
if(SECP256K1_ENABLE_MODULE_ECDH)
add_executable(ecdh_example ecdh.c)
target_link_libraries(ecdh_example example)
- add_test(ecdh_example ecdh_example)
+ add_test(NAME ecdh_example COMMAND ecdh_example)
endif()
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
add_executable(schnorr_example schnorr.c)
target_link_libraries(schnorr_example example)
- add_test(schnorr_example schnorr_example)
+ add_test(NAME schnorr_example COMMAND schnorr_example)
endif()
diff --git a/src/secp256k1/examples/examples_util.h b/src/secp256k1/examples/examples_util.h
index a52b1fa115..8e3a8f00cf 100644
--- a/src/secp256k1/examples/examples_util.h
+++ b/src/secp256k1/examples/examples_util.h
@@ -17,7 +17,13 @@
*/
#if defined(_WIN32)
+/*
+ * The defined WIN32_NO_STATUS macro disables return code definitions in
+ * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h.
+ */
+#define WIN32_NO_STATUS
#include <windows.h>
+#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <bcrypt.h>
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
@@ -77,7 +83,7 @@ static void print_hex(unsigned char* data, size_t size) {
#include <Windows.h>
#endif
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
-static SECP256K1_INLINE void secure_erase(void *ptr, size_t len) {
+static void secure_erase(void *ptr, size_t len) {
#if defined(_MSC_VER)
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 4ce3e500ba..a7a2be7a3a 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -122,18 +122,6 @@ typedef int (*secp256k1_nonce_function)(
# endif
# endif
-# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
-# if SECP256K1_GNUC_PREREQ(2,7)
-# define SECP256K1_INLINE __inline__
-# elif (defined(_MSC_VER))
-# define SECP256K1_INLINE __inline
-# else
-# define SECP256K1_INLINE
-# endif
-# else
-# define SECP256K1_INLINE inline
-# endif
-
/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
diff --git a/src/secp256k1/include/secp256k1_ellswift.h b/src/secp256k1/include/secp256k1_ellswift.h
new file mode 100644
index 0000000000..3851f93098
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_ellswift.h
@@ -0,0 +1,198 @@
+#ifndef SECP256K1_ELLSWIFT_H
+#define SECP256K1_ELLSWIFT_H
+
+#include "secp256k1.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This module provides an implementation of ElligatorSwift as well as a
+ * version of x-only ECDH using it (including compatibility with BIP324).
+ *
+ * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
+ * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
+ * uniformly chosen public keys as 64-byte arrays which are indistinguishable
+ * from uniformly random arrays.
+ *
+ * Let f be the function from pairs of field elements to point X coordinates,
+ * defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
+ * f(u,t):
+ * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
+ * a square root of -3.
+ * - If u=0, set u=1 instead.
+ * - If t=0, set t=1 instead.
+ * - If u^3 + t^2 + 7 = 0, multiply t by 2.
+ * - Let X = (u^3 + 7 - t^2) / (2 * t)
+ * - Let Y = (X + t) / (C * u)
+ * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
+ * X coordinate on the curve (at least one of them is, for any u and t).
+ *
+ * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
+ * encodings of field elements u and t concatenated, where f(u,t) = x.
+ * The encoding algorithm is described in the paper, and effectively picks a
+ * uniformly random pair (u,t) among those which encode x.
+ *
+ * If the Y coordinate is relevant, it is given the same parity as t.
+ *
+ * Changes w.r.t. the the paper:
+ * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
+ * at infinity in the paper. Here they are remapped to finite points.
+ * - The paper uses an additional encoding bit for the parity of y. Here the
+ * parity of t is used (negating t does not affect the decoded x coordinate,
+ * so this is possible).
+ */
+
+/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X
+ * coordinate along with the encoded public keys to a uniform shared secret.
+ *
+ * Returns: 1 if a shared secret was successfully computed.
+ * 0 will cause secp256k1_ellswift_xdh to fail and return 0.
+ * Other return values are not allowed, and the behaviour of
+ * secp256k1_ellswift_xdh is undefined for other return values.
+ * Out: output: pointer to an array to be filled by the function
+ * In: x32: pointer to the 32-byte serialized X coordinate
+ * of the resulting shared point (will not be NULL)
+ * ell_a64: pointer to the 64-byte encoded public key of party A
+ * (will not be NULL)
+ * ell_b64: pointer to the 64-byte encoded public key of party B
+ * (will not be NULL)
+ * data: arbitrary data pointer that is passed through
+ */
+typedef int (*secp256k1_ellswift_xdh_hash_function)(
+ unsigned char *output,
+ const unsigned char *x32,
+ const unsigned char *ell_a64,
+ const unsigned char *ell_b64,
+ void *data
+);
+
+/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
+ * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte
+ * array pointed to by data. */
+SECP256K1_API_VAR const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix;
+
+/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with
+ * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the
+ * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent
+ * to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to
+ * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh").
+ * The data argument is ignored. */
+SECP256K1_API_VAR const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324;
+
+/** Construct a 64-byte ElligatorSwift encoding of a given pubkey.
+ *
+ * Returns: 1 always.
+ * Args: ctx: pointer to a context object
+ * Out: ell64: pointer to a 64-byte array to be filled
+ * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * initialized public key
+ * rnd32: pointer to 32 bytes of randomness
+ *
+ * It is recommended that rnd32 consists of 32 uniformly random bytes, not
+ * known to any adversary trying to detect whether public keys are being
+ * encoded, though 16 bytes of randomness (padded to an array of 32 bytes,
+ * e.g., with zeros) suffice to make the result indistinguishable from
+ * uniform. The randomness in rnd32 must not be a deterministic function of
+ * the pubkey (it can be derived from the private key, though).
+ *
+ * It is not guaranteed that the computed encoding is stable across versions
+ * of the library, even if all arguments to this function (including rnd32)
+ * are the same.
+ *
+ * This function runs in variable time.
+ */
+SECP256K1_API int secp256k1_ellswift_encode(
+ const secp256k1_context *ctx,
+ unsigned char *ell64,
+ const secp256k1_pubkey *pubkey,
+ const unsigned char *rnd32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Decode a 64-bytes ElligatorSwift encoded public key.
+ *
+ * Returns: always 1
+ * Args: ctx: pointer to a context object
+ * Out: pubkey: pointer to a secp256k1_pubkey that will be filled
+ * In: ell64: pointer to a 64-byte array to decode
+ *
+ * This function runs in variable time.
+ */
+SECP256K1_API int secp256k1_ellswift_decode(
+ const secp256k1_context *ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *ell64
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Compute an ElligatorSwift public key for a secret key.
+ *
+ * Returns: 1: secret was valid, public key was stored.
+ * 0: secret was invalid, try again.
+ * Args: ctx: pointer to a context object
+ * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
+ * public key
+ * In: seckey32: pointer to a 32-byte secret key
+ * auxrnd32: (optional) pointer to 32 bytes of randomness
+ *
+ * Constant time in seckey and auxrnd32, but not in the resulting public key.
+ *
+ * It is recommended that auxrnd32 contains 32 uniformly random bytes, though
+ * it is optional (and does result in encodings that are indistinguishable from
+ * uniform even without any auxrnd32). It differs from the (mandatory) rnd32
+ * argument to secp256k1_ellswift_encode in this regard.
+ *
+ * This function can be used instead of calling secp256k1_ec_pubkey_create
+ * followed by secp256k1_ellswift_encode. It is safer, as it uses the secret
+ * key as entropy for the encoding (supplemented with auxrnd32, if provided).
+ *
+ * Like secp256k1_ellswift_encode, this function does not guarantee that the
+ * computed encoding is stable across versions of the library, even if all
+ * arguments (including auxrnd32) are the same.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
+ const secp256k1_context *ctx,
+ unsigned char *ell64,
+ const unsigned char *seckey32,
+ const unsigned char *auxrnd32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Given a private key, and ElligatorSwift public keys sent in both directions,
+ * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH).
+ *
+ * Returns: 1: shared secret was succesfully computed
+ * 0: secret was invalid or hashfp returned 0
+ * Args: ctx: pointer to a context object.
+ * Out: output: pointer to an array to be filled by hashfp.
+ * In: ell_a64: pointer to the 64-byte encoded public key of party A
+ * (will not be NULL)
+ * ell_b64: pointer to the 64-byte encoded public key of party B
+ * (will not be NULL)
+ * seckey32: a pointer to our 32-byte secret key
+ * party: boolean indicating which party we are: zero if we are
+ * party A, non-zero if we are party B. seckey32 must be
+ * the private key corresponding to that party's ell_?64.
+ * This correspondence is not checked.
+ * hashfp: pointer to a hash function.
+ * data: arbitrary data pointer passed through to hashfp.
+ *
+ * Constant time in seckey32.
+ *
+ * This function is more efficient than decoding the public keys, and performing
+ * ECDH on them.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
+ const secp256k1_context *ctx,
+ unsigned char *output,
+ const unsigned char *ell_a64,
+ const unsigned char *ell_b64,
+ const unsigned char *seckey32,
+ int party,
+ secp256k1_ellswift_xdh_hash_function hashfp,
+ void *data
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_ELLSWIFT_H */
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
index 52bba240b4..673fca01f9 100644
--- a/src/secp256k1/include/secp256k1_extrakeys.h
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -185,9 +185,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
/** Get the public key from a keypair.
*
* 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.
+ * Args: ctx: pointer to a context object.
+ * Out: pubkey: pointer to a pubkey object, set to the keypair public key.
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
@@ -203,9 +202,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
*
* 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
- * xonly_pubkey. If not, it's set to an invalid value.
+ * Out: pubkey: pointer to an xonly_pubkey object, set to the keypair
+ * public key after converting it to an xonly_pubkey.
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
* In: keypair: pointer to a keypair.
diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h
index 733fee5282..1ee665fd19 100644
--- a/src/secp256k1/include/secp256k1_schnorrsig.h
+++ b/src/secp256k1/include/secp256k1_schnorrsig.h
@@ -141,12 +141,20 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
* variable length messages and accepts a pointer to an extraparams object that
* allows customizing signing by passing additional arguments.
*
- * Creates the same signatures as schnorrsig_sign if msglen is 32 and the
- * extraparams.ndata is the same as aux_rand32.
+ * Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32
+ * and extraparams is initialized as follows:
+ * ```
+ * secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
+ * extraparams.ndata = (unsigned char*)aux_rand32;
+ * ```
*
+ * Returns 1 on success, 0 on failure.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
+ * Out: sig64: pointer to a 64-byte array to store the serialized signature.
* In: msg: the message being signed. Can only be NULL if msglen is 0.
- * msglen: length of the message
- * extraparams: pointer to a extraparams object (can be NULL)
+ * msglen: length of the message.
+ * keypair: pointer to an initialized keypair.
+ * extraparams: pointer to an extraparams object (can be NULL).
*/
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
const secp256k1_context *ctx,
diff --git a/src/secp256k1/src/CMakeLists.txt b/src/secp256k1/src/CMakeLists.txt
index 26272d0950..0bba19982a 100644
--- a/src/secp256k1/src/CMakeLists.txt
+++ b/src/secp256k1/src/CMakeLists.txt
@@ -1,151 +1,165 @@
# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
include(GNUInstallDirs)
-set(${PROJECT_NAME}_installables "")
-if(SECP256K1_ASM STREQUAL "arm")
- add_library(common OBJECT
- asm/field_10x26_arm.s
- )
- set(common_obj "$<TARGET_OBJECTS:common>")
-else()
- set(common_obj "")
-endif()
-
-add_library(precomputed OBJECT
+add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
precomputed_ecmult.c
precomputed_ecmult_gen.c
)
-set(internal_obj "$<TARGET_OBJECTS:precomputed>" "${common_obj}")
-add_library(secp256k1 SHARED EXCLUDE_FROM_ALL
- secp256k1.c
- ${internal_obj}
-)
-target_include_directories(secp256k1 INTERFACE
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-)
-target_compile_definitions(secp256k1 PRIVATE
- $<$<PLATFORM_ID:Windows>:DLL_EXPORT>
-)
-set_target_properties(secp256k1 PROPERTIES
- VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}"
- SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}"
-)
-if(SECP256K1_BUILD_SHARED)
- get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
- set_target_properties(precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
- set_target_properties(secp256k1 PROPERTIES EXCLUDE_FROM_ALL FALSE)
- list(APPEND ${PROJECT_NAME}_installables secp256k1)
-endif()
+# Add objects explicitly rather than linking to the object libs to keep them
+# from being exported.
+add_library(secp256k1 secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
-add_library(secp256k1_static STATIC EXCLUDE_FROM_ALL
- secp256k1.c
- ${internal_obj}
-)
-target_include_directories(secp256k1_static INTERFACE
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-)
-if(NOT MSVC)
- set_target_properties(secp256k1_static PROPERTIES
- OUTPUT_NAME secp256k1
+add_library(secp256k1_asm INTERFACE)
+if(SECP256K1_ASM STREQUAL "arm32")
+ add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL)
+ target_sources(secp256k1_asm_arm PUBLIC
+ asm/field_10x26_arm.s
)
+ target_sources(secp256k1 PRIVATE $<TARGET_OBJECTS:secp256k1_asm_arm>)
+ target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
endif()
-if(SECP256K1_BUILD_STATIC)
- set_target_properties(secp256k1_static PROPERTIES EXCLUDE_FROM_ALL FALSE)
- list(APPEND ${PROJECT_NAME}_installables secp256k1_static)
+
+# Define our export symbol only for Win32 and only for shared libs.
+# This matches libtool's usage of DLL_EXPORT
+if(WIN32)
+ set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL "DLL_EXPORT")
endif()
-add_library(binary_interface INTERFACE)
-target_compile_definitions(binary_interface INTERFACE
- $<$<C_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
+# Object libs don't know if they're being built for a shared or static lib.
+# Grab the PIC property from secp256k1 which knows.
+get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
+set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
+
+target_include_directories(secp256k1 INTERFACE
+ # Add the include path for parent projects so that they don't have to manually add it.
+ $<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
-add_library(link_library INTERFACE)
-if(SECP256K1_BUILD_SHARED)
- target_link_libraries(link_library INTERFACE secp256k1)
-elseif(SECP256K1_BUILD_STATIC)
- target_link_libraries(link_library INTERFACE secp256k1_static)
+# This emulates Libtool to make sure Libtool and CMake agree on the ABI version,
+# see below "Calculate the version variables" in build-aux/ltmain.sh.
+math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}")
+set_target_properties(secp256k1 PROPERTIES
+ SOVERSION ${${PROJECT_NAME}_soversion}
+)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set_target_properties(secp256k1 PROPERTIES
+ VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
+ )
+elseif(APPLE)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
+ math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1")
+ set_target_properties(secp256k1 PROPERTIES
+ MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version}
+ MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
+ )
+ unset(${PROJECT_NAME}_compatibility_version)
+ elseif(BUILD_SHARED_LIBS)
+ message(WARNING
+ "The 'compatibility version' and 'current version' values of the DYLIB "
+ "will diverge from the values set by the GNU Libtool. To ensure "
+ "compatibility, it is recommended to upgrade CMake to at least version 3.17."
+ )
+ endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ set(${PROJECT_NAME}_windows "secp256k1")
+ if(MSVC)
+ set(${PROJECT_NAME}_windows "${PROJECT_NAME}")
+ endif()
+ set_target_properties(secp256k1 PROPERTIES
+ ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}"
+ RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}"
+ )
+ unset(${PROJECT_NAME}_windows)
endif()
+unset(${PROJECT_NAME}_soversion)
if(SECP256K1_BUILD_BENCHMARK)
add_executable(bench bench.c)
- target_link_libraries(bench binary_interface link_library)
- add_executable(bench_internal bench_internal.c ${internal_obj})
- target_link_libraries(bench_internal binary_interface)
- add_executable(bench_ecmult bench_ecmult.c ${internal_obj})
- target_link_libraries(bench_ecmult binary_interface)
+ target_link_libraries(bench secp256k1)
+ add_executable(bench_internal bench_internal.c)
+ target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm)
+ add_executable(bench_ecmult bench_ecmult.c)
+ target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm)
endif()
if(SECP256K1_BUILD_TESTS)
- add_executable(noverify_tests tests.c ${internal_obj})
- target_link_libraries(noverify_tests binary_interface)
- add_test(noverify_tests noverify_tests)
+ add_executable(noverify_tests tests.c)
+ target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
+ add_test(NAME noverify_tests COMMAND noverify_tests)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
- add_executable(tests tests.c ${internal_obj})
+ add_executable(tests tests.c)
target_compile_definitions(tests PRIVATE VERIFY)
- target_link_libraries(tests binary_interface)
- add_test(tests tests)
+ target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
+ add_test(NAME tests COMMAND tests)
endif()
endif()
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
- # Note: do not include $<TARGET_OBJECTS:precomputed> in exhaustive_tests (it uses runtime-generated tables).
- add_executable(exhaustive_tests tests_exhaustive.c ${common_obj})
+ # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables).
+ add_executable(exhaustive_tests tests_exhaustive.c)
+ target_link_libraries(exhaustive_tests secp256k1_asm)
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
- target_link_libraries(exhaustive_tests binary_interface)
- add_test(exhaustive_tests exhaustive_tests)
+ add_test(NAME exhaustive_tests COMMAND exhaustive_tests)
endif()
if(SECP256K1_BUILD_CTIME_TESTS)
add_executable(ctime_tests ctime_tests.c)
- target_link_libraries(ctime_tests binary_interface link_library)
+ target_link_libraries(ctime_tests secp256k1)
endif()
-install(TARGETS ${${PROJECT_NAME}_installables}
- EXPORT ${PROJECT_NAME}-targets
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-)
-set(${PROJECT_NAME}_headers
- "${PROJECT_SOURCE_DIR}/include/secp256k1.h"
- "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
-)
-if(SECP256K1_ENABLE_MODULE_ECDH)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
-endif()
-if(SECP256K1_ENABLE_MODULE_RECOVERY)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
-endif()
-if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
-endif()
-if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
-endif()
-install(FILES ${${PROJECT_NAME}_headers}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-)
+if(SECP256K1_INSTALL)
+ install(TARGETS secp256k1
+ EXPORT ${PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ set(${PROJECT_NAME}_headers
+ "${PROJECT_SOURCE_DIR}/include/secp256k1.h"
+ "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
+ )
+ if(SECP256K1_ENABLE_MODULE_ECDH)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_RECOVERY)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
+ endif()
+ install(FILES ${${PROJECT_NAME}_headers}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ )
-install(EXPORT ${PROJECT_NAME}-targets
- FILE ${PROJECT_NAME}-targets.cmake
- NAMESPACE ${PROJECT_NAME}::
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
-)
+ install(EXPORT ${PROJECT_NAME}-targets
+ FILE ${PROJECT_NAME}-targets.cmake
+ NAMESPACE ${PROJECT_NAME}::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ )
-include(CMakePackageConfigHelpers)
-configure_package_config_file(
- ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
- ${PROJECT_NAME}-config.cmake
- INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
- NO_SET_AND_CHECK_MACRO
-)
-write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
- COMPATIBILITY SameMajorVersion
-)
-install(
- FILES
- ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ include(CMakePackageConfigHelpers)
+ configure_package_config_file(
+ ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
+ ${PROJECT_NAME}-config.cmake
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ NO_SET_AND_CHECK_MACRO
+ )
+ write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
+ COMPATIBILITY SameMinorVersion
+ )
+
+ install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
+endif()
diff --git a/src/secp256k1/src/bench.c b/src/secp256k1/src/bench.c
index 833f70718b..1127df67ae 100644
--- a/src/secp256k1/src/bench.c
+++ b/src/secp256k1/src/bench.c
@@ -38,6 +38,8 @@ static void help(int default_iters) {
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
printf(" ecdsa_sign : ECDSA siging algorithm\n");
printf(" ecdsa_verify : ECDSA verification algorithm\n");
+ printf(" ec : all EC public key algorithms (keygen)\n");
+ printf(" ec_keygen : EC public key generation\n");
#ifdef ENABLE_MODULE_RECOVERY
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
@@ -53,6 +55,14 @@ static void help(int default_iters) {
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n");
+ printf(" ellswift_encode : ElligatorSwift encoding\n");
+ printf(" ellswift_decode : ElligatorSwift decoding\n");
+ printf(" ellswift_keygen : ElligatorSwift key generation\n");
+ printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n");
+#endif
+
printf("\n");
}
@@ -64,11 +74,11 @@ typedef struct {
size_t siglen;
unsigned char pubkey[33];
size_t pubkeylen;
-} bench_verify_data;
+} bench_data;
static void bench_verify(void* arg, int iters) {
int i;
- bench_verify_data* data = (bench_verify_data*)arg;
+ bench_data* data = (bench_data*)arg;
for (i = 0; i < iters; i++) {
secp256k1_pubkey pubkey;
@@ -85,15 +95,9 @@ static void bench_verify(void* arg, int iters) {
}
}
-typedef struct {
- secp256k1_context* ctx;
- unsigned char msg[32];
- unsigned char key[32];
-} bench_sign_data;
-
static void bench_sign_setup(void* arg) {
int i;
- bench_sign_data *data = (bench_sign_data*)arg;
+ bench_data *data = (bench_data*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = i + 1;
@@ -105,7 +109,7 @@ static void bench_sign_setup(void* arg) {
static void bench_sign_run(void* arg, int iters) {
int i;
- bench_sign_data *data = (bench_sign_data*)arg;
+ bench_data *data = (bench_data*)arg;
unsigned char sig[74];
for (i = 0; i < iters; i++) {
@@ -121,6 +125,30 @@ static void bench_sign_run(void* arg, int iters) {
}
}
+static void bench_keygen_setup(void* arg) {
+ int i;
+ bench_data *data = (bench_data*)arg;
+
+ for (i = 0; i < 32; i++) {
+ data->key[i] = i + 65;
+ }
+}
+
+static void bench_keygen_run(void *arg, int iters) {
+ int i;
+ bench_data *data = (bench_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ unsigned char pub33[33];
+ size_t len = 33;
+ secp256k1_pubkey pubkey;
+ CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
+ memcpy(data->key, pub33 + 1, 32);
+ }
+}
+
+
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/bench_impl.h"
#endif
@@ -133,11 +161,15 @@ static void bench_sign_run(void* arg, int iters) {
# include "modules/schnorrsig/bench_impl.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/bench_impl.h"
+#endif
+
int main(int argc, char** argv) {
int i;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
- bench_verify_data data;
+ bench_data data;
int d = argc == 1;
int default_iters = 20000;
@@ -145,7 +177,9 @@ int main(int argc, char** argv) {
/* Check for invalid user arguments */
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
- "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"};
+ "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
+ "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
+ "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
@@ -187,6 +221,16 @@ int main(int argc, char** argv) {
}
#endif
+#ifndef ENABLE_MODULE_ELLSWIFT
+ if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") ||
+ have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
+ have_flag(argc, argv, "ellswift_ecdh")) {
+ fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
+ fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n");
+ return 1;
+ }
+#endif
+
/* ECDSA benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
@@ -207,6 +251,7 @@ int main(int argc, char** argv) {
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
@@ -225,5 +270,10 @@ int main(int argc, char** argv) {
run_schnorrsig_bench(iters, argc, argv);
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ /* ElligatorSwift benchmarks */
+ run_ellswift_bench(iters, argc, argv);
+#endif
+
return 0;
}
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index bf9a932ff4..1564b1a176 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -15,7 +15,7 @@
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
# include <time.h>
#else
-# include "sys/time.h"
+# include <sys/time.h>
#endif
static int64_t gettime_i64(void) {
diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c
index 98fb798d82..8818aa81b5 100644
--- a/src/secp256k1/src/bench_ecmult.c
+++ b/src/secp256k1/src/bench_ecmult.c
@@ -113,7 +113,7 @@ static void bench_ecmult_const(void* arg, int iters) {
int i;
for (i = 0; i < iters; ++i) {
- secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], 256);
+ secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]);
}
}
@@ -138,12 +138,10 @@ static void bench_ecmult_1p_teardown(void* arg, int iters) {
static void bench_ecmult_0p_g(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
- secp256k1_scalar zero;
int i;
- secp256k1_scalar_set_int(&zero, 0);
for (i = 0; i < iters; ++i) {
- secp256k1_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]);
+ secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]);
}
}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index c248ab8ebc..f3686dd289 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -65,10 +65,10 @@ static void bench_setup(void* arg) {
secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
- secp256k1_fe_set_b32(&data->fe[0], init[0]);
- secp256k1_fe_set_b32(&data->fe[1], init[1]);
- secp256k1_fe_set_b32(&data->fe[2], init[2]);
- secp256k1_fe_set_b32(&data->fe[3], init[3]);
+ secp256k1_fe_set_b32_limit(&data->fe[0], init[0]);
+ secp256k1_fe_set_b32_limit(&data->fe[1], init[1]);
+ secp256k1_fe_set_b32_limit(&data->fe[2], init[2]);
+ secp256k1_fe_set_b32_limit(&data->fe[3], init[3]);
CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);
diff --git a/src/secp256k1/src/ctime_tests.c b/src/secp256k1/src/ctime_tests.c
index 713eb427d3..af7891a91c 100644
--- a/src/secp256k1/src/ctime_tests.c
+++ b/src/secp256k1/src/ctime_tests.c
@@ -30,6 +30,10 @@
#include "../include/secp256k1_schnorrsig.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+#include "../include/secp256k1_ellswift.h"
+#endif
+
static void run_tests(secp256k1_context *ctx, unsigned char *key);
int main(void) {
@@ -80,6 +84,10 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
#ifdef ENABLE_MODULE_EXTRAKEYS
secp256k1_keypair keypair;
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ unsigned char ellswift[64];
+ static const unsigned char prefix[64] = {'t', 'e', 's', 't'};
+#endif
for (i = 0; i < 32; i++) {
msg[i] = i + 1;
@@ -171,4 +179,31 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
+
+#ifdef ENABLE_MODULE_ELLSWIFT
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ for (i = 0; i < 2; i++) {
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ VALGRIND_MAKE_MEM_DEFINED(&ellswift, sizeof(ellswift));
+ ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ VALGRIND_MAKE_MEM_DEFINED(&ellswift, sizeof(ellswift));
+ ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+ }
+
+#endif
}
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 90b4b22b77..48e30851b5 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -239,7 +239,8 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
}
#else
secp256k1_scalar_get_b32(c, sigr);
- secp256k1_fe_set_b32(&xr, c);
+ /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
+ (void)secp256k1_fe_set_b32_limit(&xr, c);
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index e0506d3e2b..121966f8b5 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -17,10 +17,10 @@
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
secp256k1_fe x;
- return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
+ return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
secp256k1_fe x, y;
- if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
+ if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) {
return 0;
}
secp256k1_ge_set_xy(elem, &x, &y);
@@ -59,10 +59,8 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp25
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) {
secp256k1_gej pt;
- secp256k1_scalar one;
secp256k1_gej_set_ge(&pt, key);
- secp256k1_scalar_set_int(&one, 1);
- secp256k1_ecmult(&pt, &pt, &one, tweak);
+ secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak);
if (secp256k1_gej_is_infinity(&pt)) {
return 0;
@@ -80,15 +78,13 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp25
}
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) {
- secp256k1_scalar zero;
secp256k1_gej pt;
if (secp256k1_scalar_is_zero(tweak)) {
return 0;
}
- secp256k1_scalar_set_int(&zero, 0);
secp256k1_gej_set_ge(&pt, key);
- secp256k1_ecmult(&pt, &pt, tweak, &zero);
+ secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
secp256k1_ge_set_gej(key, &pt);
return 1;
}
diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h
index 417f328535..080e04bc88 100644
--- a/src/secp256k1/src/ecmult_const.h
+++ b/src/secp256k1/src/ecmult_const.h
@@ -11,12 +11,9 @@
#include "group.h"
/**
- * Multiply: R = q*A (in constant-time)
- * Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
- * one because we internally sometimes add 2 to the number during the WNAF conversion.
- * A must not be infinity.
+ * Multiply: R = q*A (in constant-time for q)
*/
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
/**
* Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point
@@ -35,7 +32,6 @@ static int secp256k1_ecmult_const_xonly(
const secp256k1_fe *n,
const secp256k1_fe *d,
const secp256k1_scalar *q,
- int bits,
int known_on_curve
);
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index f23e0ec89d..26b3e238d8 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -29,7 +29,7 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
int m = 0; \
/* Extract the sign-bit for a constant time absolute-value. */ \
- int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
+ int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
int abs_n = ((n) + mask) ^ mask; \
int idx_n = abs_n >> 1; \
secp256k1_fe neg_y; \
@@ -130,7 +130,7 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
return skew;
}
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge tmpa;
secp256k1_fe Z;
@@ -144,20 +144,17 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
int i;
- /* build wnaf representation for q. */
- int rsize = size;
- if (size > 128) {
- rsize = 128;
- /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
- secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
- skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
- skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
- } else
- {
- skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size);
- skew_lam = 0;
+ if (secp256k1_ge_is_infinity(a)) {
+ secp256k1_gej_set_infinity(r);
+ return;
}
+ /* build wnaf representation for q. */
+ /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
+ secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
+ skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
+ skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
+
/* 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
@@ -170,28 +167,23 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_fe_normalize_weak(&pre_a[i].y);
}
- if (size > 128) {
- for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
- }
-
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
- i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
+ i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
- if (size > 128) {
- i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
- secp256k1_gej_add_ge(r, r, &tmpa);
- }
+ i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
+ VERIFY_CHECK(i != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
+ secp256k1_gej_add_ge(r, r, &tmpa);
/* remaining loop iterations */
- for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
+ for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) {
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
@@ -202,12 +194,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
- if (size > 128) {
- n = wnaf_lam[i];
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
- VERIFY_CHECK(n != 0);
- secp256k1_gej_add_ge(r, r, &tmpa);
- }
+ n = wnaf_lam[i];
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
+ VERIFY_CHECK(n != 0);
+ secp256k1_gej_add_ge(r, r, &tmpa);
}
{
@@ -218,17 +208,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
secp256k1_gej_cmov(r, &tmpj, skew_1);
- if (size > 128) {
- secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
- secp256k1_gej_add_ge(&tmpj, r, &tmpa);
- secp256k1_gej_cmov(r, &tmpj, skew_lam);
- }
+ 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);
}
-static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int bits, int known_on_curve) {
+static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
/* This algorithm is a generalization of Peter Dettman's technique for
* avoiding the square root in a random-basepoint x-only multiplication
@@ -346,7 +334,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
#endif
- secp256k1_ecmult_const(&rj, &p, q, bits);
+ secp256k1_ecmult_const(&rj, &p, q);
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
#endif
diff --git a/src/secp256k1/src/ecmult_gen_compute_table_impl.h b/src/secp256k1/src/ecmult_gen_compute_table_impl.h
index ff6a2992dc..7d672b9950 100644
--- a/src/secp256k1/src/ecmult_gen_compute_table_impl.h
+++ b/src/secp256k1/src/ecmult_gen_compute_table_impl.h
@@ -31,7 +31,7 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
secp256k1_fe nums_x;
secp256k1_ge nums_ge;
int r;
- r = secp256k1_fe_set_b32(&nums_x, nums_b32);
+ r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
(void)r;
VERIFY_CHECK(r);
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 4f5ea9f3c0..af412173e9 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -87,7 +87,6 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_fe s;
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
- int overflow;
unsigned char keydata[64];
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
@@ -106,11 +105,9 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
memcpy(keydata + 32, seed32, 32);
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
memset(keydata, 0, sizeof(keydata));
- /* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
- overflow = !secp256k1_fe_set_b32(&s, nonce32);
- overflow |= secp256k1_fe_is_zero(&s);
- secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
+ secp256k1_fe_set_b32_mod(&s, nonce32);
+ secp256k1_fe_cmov(&s, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&s));
/* Randomize the projection to defend against multiplier sidechannels.
Do this before our own call to secp256k1_ecmult_gen below. */
secp256k1_gej_rescale(&ctx->initial, &s);
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index a9a63850ef..f4624677d7 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -279,9 +279,6 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
*/
tmp = a[np];
if (no) {
-#ifdef VERIFY
- secp256k1_fe_normalize_var(&Z);
-#endif
secp256k1_gej_rescale(&tmp, &Z);
}
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);
@@ -683,7 +680,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
}
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps));
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
- buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<<bucket_window) * sizeof(*buckets));
+ buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets));
if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
@@ -773,14 +770,12 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
* require a scratch space */
static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
size_t point_idx;
- secp256k1_scalar szero;
secp256k1_gej tmpj;
- secp256k1_scalar_set_int(&szero, 0);
secp256k1_gej_set_infinity(r);
secp256k1_gej_set_infinity(&tmpj);
/* r = inp_g_sc*G */
- secp256k1_ecmult(r, &tmpj, &szero, inp_g_sc);
+ secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc);
for (point_idx = 0; point_idx < n_points; point_idx++) {
secp256k1_ge point;
secp256k1_gej pointj;
@@ -828,9 +823,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback,
if (inp_g_sc == NULL && n == 0) {
return 1;
} else if (n == 0) {
- secp256k1_scalar szero;
- secp256k1_scalar_set_int(&szero, 0);
- secp256k1_ecmult(r, r, &szero, inp_g_sc);
+ secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc);
return 1;
}
if (scratch == NULL) {
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 64ceead4d2..e632f9e3e2 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -7,19 +7,36 @@
#ifndef SECP256K1_FIELD_H
#define SECP256K1_FIELD_H
-/** Field element module.
- *
- * Field elements can be represented in several ways, but code accessing
- * it (and implementations) need to take certain properties into account:
- * - Each field element can be normalized or not.
- * - Each field element has a magnitude, which represents how far away
- * its representation is away from normalization. Normalized elements
- * always have a magnitude of 0 or 1, but a magnitude of 1 doesn't
- * imply normality.
- */
-
#include "util.h"
+/* This file defines the generic interface for working with secp256k1_fe
+ * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977).
+ *
+ * The actual definition of the secp256k1_fe type depends on the chosen field
+ * implementation; see the field_5x52.h and field_10x26.h files for details.
+ *
+ * All secp256k1_fe objects have implicit properties that determine what
+ * operations are permitted on it. These are purely a function of what
+ * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at
+ * compile time, and do not depend on the chosen field implementation. Despite
+ * that, what these properties actually entail for the field representation
+ * values depends on the chosen field implementation. These properties are:
+ * - magnitude: an integer in [0,32]
+ * - normalized: 0 or 1; normalized=1 implies magnitude <= 1.
+ *
+ * In VERIFY mode, they are materialized explicitly as fields in the struct,
+ * allowing run-time verification of these properties. In that case, the field
+ * implementation also provides a secp256k1_fe_verify routine to verify that
+ * these fields match the run-time value and perform internal consistency
+ * checks. */
+#ifdef VERIFY
+# define SECP256K1_FE_VERIFY_FIELDS \
+ int magnitude; \
+ int normalized;
+#else
+# define SECP256K1_FE_VERIFY_FIELDS
+#endif
+
#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52.h"
#elif defined(SECP256K1_WIDEMUL_INT64)
@@ -28,117 +45,297 @@
#error "Please select wide multiplication implementation"
#endif
+#ifdef VERIFY
+/* Magnitude and normalized value for constants. */
+#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \
+ /* Magnitude is 0 for constant 0; 1 otherwise. */ \
+ , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \
+ /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \
+ , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f)))))
+#else
+#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0)
+#endif
+
+/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p.
+ *
+ * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0.
+ * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p.
+ *
+ * SECP256K1_FE_CONST_INNER is provided by the implementation.
+ */
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) }
+
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`.
+#ifndef VERIFY
+/* In non-VERIFY mode, we #define the fe operations to be identical to their
+ * internal field implementation, to avoid the potential overhead of a
+ * function call (even though presumably inlinable). */
+# define secp256k1_fe_normalize secp256k1_fe_impl_normalize
+# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak
+# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var
+# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero
+# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
+# define secp256k1_fe_set_int secp256k1_fe_impl_set_int
+# define secp256k1_fe_clear secp256k1_fe_impl_clear
+# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
+# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
+# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
+# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
+# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
+# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
+# define secp256k1_fe_negate secp256k1_fe_impl_negate
+# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
+# define secp256k1_fe_add secp256k1_fe_impl_add
+# define secp256k1_fe_mul secp256k1_fe_impl_mul
+# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
+# define secp256k1_fe_cmov secp256k1_fe_impl_cmov
+# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage
+# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage
+# define secp256k1_fe_inv secp256k1_fe_impl_inv
+# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var
+# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds
+# define secp256k1_fe_half secp256k1_fe_impl_half
+# define secp256k1_fe_add_int secp256k1_fe_impl_add_int
+# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var
+#endif /* !defined(VERIFY) */
+
+/** Normalize a field element.
+ *
+ * On input, r must be a valid field element.
+ * On output, r represents the same value but has normalized=1 and magnitude=1.
*/
static void secp256k1_fe_normalize(secp256k1_fe *r);
-/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
+/** Give a field element magnitude 1.
+ *
+ * On input, r must be a valid field element.
+ * On output, r represents the same value but has magnitude=1. Normalized is unchanged.
+ */
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
-/** Normalize a field element, without constant-time guarantee. */
+/** Normalize a field element, without constant-time guarantee.
+ *
+ * Identical in behavior to secp256k1_fe_normalize, but not constant time in r.
+ */
static void secp256k1_fe_normalize_var(secp256k1_fe *r);
-/** Verify whether a field element represents zero i.e. would normalize to a zero value. */
+/** Determine whether r represents field element 0.
+ *
+ * On input, r must be a valid field element.
+ * Returns whether r = 0 (mod p).
+ */
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r);
-/** Verify whether a field element represents zero i.e. would normalize to a zero value,
- * without constant-time guarantee. */
+/** Determine whether r represents field element 0, without constant-time guarantee.
+ *
+ * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r.
+ */
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
-/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer.
- * Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise.
+/** Set a field element to an integer in range [0,0x7FFF].
+ *
+ * On input, r does not need to be initialized, a must be in [0,0x7FFF].
+ * On output, r represents value a, is normalized and has magnitude (a!=0).
*/
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
-/** Sets a field element equal to zero, initializing all fields. */
+/** Set a field element to 0.
+ *
+ * On input, a does not need to be initialized.
+ * On output, a represents 0, is normalized and has magnitude 0.
+ */
static void secp256k1_fe_clear(secp256k1_fe *a);
-/** Verify whether a field element is zero. Requires the input to be normalized. */
+/** Determine whether a represents field element 0.
+ *
+ * On input, a must be a valid normalized field element.
+ * Returns whether a = 0 (mod p).
+ *
+ * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires
+ * normalized input (and is much faster).
+ */
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
-/** Check the "oddness" of a field element. Requires the input to be normalized. */
+/** Determine whether a (mod p) is odd.
+ *
+ * On input, a must be a valid normalized field element.
+ * Returns (int(a) mod p) & 1.
+ */
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
-/** Compare two field elements. Requires magnitude-1 inputs. */
+/** Determine whether two field elements are equal.
+ *
+ * On input, a and b must be valid field elements with magnitudes not exceeding
+ * 1 and 31, respectively.
+ * Returns a = b (mod p).
+ */
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Same as secp256k1_fe_equal, but may be variable time. */
+/** Determine whether two field elements are equal, without constant-time guarantee.
+ *
+ * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b.
+ */
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Compare two field elements. Requires both inputs to be normalized */
+/** Compare the values represented by 2 field elements, without constant-time guarantee.
+ *
+ * On input, a and b must be valid normalized field elements.
+ * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers
+ * in range 0..p-1).
+ */
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */
-static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);
+/** Set a field element equal to a provided 32-byte big endian value, reducing it.
+ *
+ * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
+ * On output, r = a (mod p). It will have magnitude 1, and not be normalized.
+ */
+static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
+
+/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
+ *
+ * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
+ * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
+ * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
+ */
+static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
-/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+/** Convert a field element to 32-byte big endian byte array.
+ * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array.
+ * On output, r = a (mod p).
+ */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
-/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
- * as an argument. The magnitude of the output is one higher. */
+/** Negate a field element.
+ *
+ * On input, r does not need to be initialized. a must be a valid field element with
+ * magnitude not exceeding m. m must be an integer in [0,31].
+ * Performs {r = -a}.
+ * On output, r will not be normalized, and will have magnitude m+1.
+ */
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
-/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */
+/** Add a small integer to a field element.
+ *
+ * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
+ * a must be in range [0,0x7FFF].
+ */
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
-/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
- * small integer. */
+/** Multiply a field element with a small integer.
+ *
+ * On input, r must be a valid field element. a must be an integer in [0,32].
+ * The magnitude of r times a must not exceed 32.
+ * Performs {r *= a}.
+ * On output, r's magnitude is multiplied by a, and r will not be normalized.
+ */
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
-/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
+/** Increment a field element by another.
+ *
+ * On input, r and a must be valid field elements, not necessarily normalized.
+ * The sum of their magnitudes must not exceed 32.
+ * Performs {r += a}.
+ * On output, r will not be normalized, and will have magnitude incremented by a's.
+ */
static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
-/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
- * The output magnitude is 1 (but not guaranteed to be normalized). */
+/** Multiply two field elements.
+ *
+ * On input, a and b must be valid field elements; r does not need to be initialized.
+ * r and a may point to the same object, but neither can be equal to b. The magnitudes
+ * of a and b must not exceed 8.
+ * Performs {r = a * b}
+ * On output, r will have magnitude 1, but won't be normalized.
+ */
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
-/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
- * The output magnitude is 1 (but not guaranteed to be normalized). */
+/** Square a field element.
+ *
+ * On input, a must be a valid field element; r does not need to be initialized. The magnitude
+ * of a must not exceed 8.
+ * Performs {r = a**2}
+ * On output, r will have magnitude 1, but won't be normalized.
+ */
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
-/** If a has a square root, it is computed in r and 1 is returned. If a does not
- * have a square root, the root of its negation is computed and 0 is returned.
- * The input's magnitude can be at most 8. The output magnitude is 1 (but not
- * guaranteed to be normalized). The result in r will always be a square
- * itself. */
-static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
+/** Compute a square root of a field element.
+ *
+ * On input, a must be a valid field element with magnitude<=8; r need not be initialized.
+ * Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value
+ * represented by r will be a square itself. Variables r and a must not point to the same object.
+ * On output, r will have magnitude 1 but will not be normalized.
+ */
+static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
-/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
- * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
+/** Compute the modular inverse of a field element.
+ *
+ * On input, a must be a valid field element; r need not be initialized.
+ * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its
+ * inverse).
+ * On output, r will have magnitude (a.magnitude != 0) and be normalized.
+ */
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
-/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
+/** Compute the modular inverse of a field element, without constant-time guarantee.
+ *
+ * Behaves identically to secp256k1_fe_inv, but is not constant-time in a.
+ */
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
-/** Convert a field element to the storage type. */
+/** Convert a field element to secp256k1_fe_storage.
+ *
+ * On input, a must be a valid normalized field element.
+ * Performs {r = a}.
+ */
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
-/** Convert a field element back from the storage type. */
+/** Convert a field element back from secp256k1_fe_storage.
+ *
+ * On input, r need not be initialized.
+ * Performs {r = a}.
+ * On output, r will be normalized and will have magnitude 1.
+ */
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
+/** Conditionally move a field element in constant time.
+ *
+ * On input, both r and a must be valid field elements. Flag must be 0 or 1.
+ * Performs {r = flag ? a : r}.
+ *
+ * On output, r's magnitude will be the maximum of both input magnitudes.
+ * It will be normalized if and only if both inputs were normalized.
+ */
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. */
+/** Halve the value of a field element modulo the field prime in constant-time.
+ *
+ * On input, r must be a valid field element.
+ * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is
+ * the magnitude of r on 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. */
+/** Sets r to a field element with magnitude m, normalized if (and only if) m==0.
+ * The value is chosen so that it is likely to trigger edge cases related to
+ * internal overflows. */
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
-/** Determine whether a is a square (modulo p). */
+/** Determine whether a is a square (modulo p).
+ *
+ * On input, a must be a valid field element.
+ */
static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
+/** Check invariants on a field element (no-op unless VERIFY is enabled). */
+static void secp256k1_fe_verify(const secp256k1_fe *a);
+
#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 9eb65607f1..203c10167c 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -9,15 +9,28 @@
#include <stdint.h>
+/** This field implementation represents the value as 10 uint32_t limbs in base
+ * 2^26. */
typedef struct {
- /* X = sum(i=0..9, n[i]*2^(i*26)) mod p
- * where p = 2^256 - 0x1000003D1
- */
+ /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p,
+ * where p is the field modulus, 2^256 - 2^32 - 977.
+ *
+ * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly
+ * corresponds to how much excess is allowed. The value
+ * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is
+ * normalized. */
uint32_t n[10];
-#ifdef VERIFY
- int magnitude;
- int normalized;
-#endif
+ /*
+ * Magnitude m requires:
+ * n[i] <= 2 * m * (2^26 - 1) for i=0..8
+ * n[9] <= 2 * m * (2^22 - 1)
+ *
+ * Normalized requires:
+ * n[i] <= (2^26 - 1) for i=0..8
+ * sum(i=0..9, n[i] << (i*26)) < p
+ * (together these imply n[9] <= 2^22 - 1)
+ */
+ SECP256K1_FE_VERIFY_FIELDS
} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
@@ -34,12 +47,6 @@ typedef struct {
(((uint32_t)d7) >> 10) \
}
-#ifdef VERIFY
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
-#else
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
-#endif
-
typedef struct {
uint32_t n[8];
} secp256k1_fe_storage;
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 3b7f4d2480..c1b32b80a8 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -12,47 +12,32 @@
#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) {
+static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
const uint32_t *d = a->n;
- int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
- r &= (d[0] <= 0x3FFFFFFUL * m);
- r &= (d[1] <= 0x3FFFFFFUL * m);
- r &= (d[2] <= 0x3FFFFFFUL * m);
- r &= (d[3] <= 0x3FFFFFFUL * m);
- r &= (d[4] <= 0x3FFFFFFUL * m);
- r &= (d[5] <= 0x3FFFFFFUL * m);
- r &= (d[6] <= 0x3FFFFFFUL * m);
- r &= (d[7] <= 0x3FFFFFFUL * m);
- r &= (d[8] <= 0x3FFFFFFUL * m);
- r &= (d[9] <= 0x03FFFFFUL * m);
- r &= (a->magnitude >= 0);
- r &= (a->magnitude <= 32);
+ int m = a->normalized ? 1 : 2 * a->magnitude;
+ VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m);
if (a->normalized) {
- r &= (a->magnitude <= 1);
- if (r && (d[9] == 0x03FFFFFUL)) {
+ if (d[9] == 0x03FFFFFUL) {
uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2];
if (mid == 0x3FFFFFFUL) {
- r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
+ VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
}
}
}
- VERIFY_CHECK(r == 1);
}
#endif
-static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
- VERIFY_CHECK(m >= 0);
- VERIFY_CHECK(m <= 2048);
+static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
r->n[0] = 0x3FFFFFFUL * 2 * m;
r->n[1] = 0x3FFFFFFUL * 2 * m;
r->n[2] = 0x3FFFFFFUL * 2 * m;
@@ -63,14 +48,9 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int 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) {
+static void secp256k1_fe_impl_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];
@@ -117,15 +97,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -149,14 +123,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
-
-#ifdef VERIFY
- r->magnitude = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -204,15 +173,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero(const 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];
@@ -241,7 +204,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
-static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
uint32_t z0, z1;
uint32_t x;
@@ -293,53 +256,29 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
- VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
-#ifdef VERIFY
- r->magnitude = (a != 0);
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
const uint32_t *t = a->n;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;
}
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
return a->n[0] & 1;
}
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
int i;
-#ifdef VERIFY
- a->magnitude = 0;
- a->normalized = 1;
-#endif
for (i=0; i<10; i++) {
a->n[i] = 0;
}
}
-static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- VERIFY_CHECK(b->normalized);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
-#endif
for (i = 9; i >= 0; i--) {
if (a->n[i] > b->n[i]) {
return 1;
@@ -351,8 +290,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
return 0;
}
-static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int ret;
+static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
@@ -363,26 +301,15 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
+}
- ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
-#ifdef VERIFY
- r->magnitude = 1;
- if (ret) {
- r->normalized = 1;
- secp256k1_fe_verify(r);
- } else {
- r->normalized = 0;
- }
-#endif
- return ret;
+static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
+ secp256k1_fe_impl_set_b32_mod(r, a);
+ return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[0] = (a->n[9] >> 14) & 0xff;
r[1] = (a->n[9] >> 6) & 0xff;
r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
@@ -417,15 +344,15 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[31] = a->n[0] & 0xff;
}
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= m);
- secp256k1_fe_verify(a);
+SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+ /* For all legal values of m (0..31), the following properties hold: */
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
+
+ /* Due to the properties above, the left hand in the subtractions below is never less than
+ * the right hand. */
r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0];
r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1];
r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2];
@@ -436,14 +363,9 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k
r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7];
r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8];
r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
-#ifdef VERIFY
- r->magnitude = m + 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
@@ -454,17 +376,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
r->n[7] *= a;
r->n[8] *= a;
r->n[9] *= a;
-#ifdef VERIFY
- r->magnitude *= a;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
@@ -475,25 +389,10 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
r->n[7] += a->n[7];
r->n[8] += a->n[8];
r->n[9] += a->n[9];
-#ifdef VERIFY
- r->magnitude += a->magnitude;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
-#ifdef VERIFY
- secp256k1_fe_verify(r);
- VERIFY_CHECK(a >= 0);
- VERIFY_CHECK(a <= 0x7FFF);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
r->n[0] += a;
-#ifdef VERIFY
- r->magnitude += 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
#if defined(USE_EXTERNAL_ASM)
@@ -1115,37 +1014,15 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
}
#endif
-static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- VERIFY_CHECK(b->magnitude <= 8);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
- VERIFY_CHECK(r != b);
- VERIFY_CHECK(a != b);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_mul_inner(r->n, a->n, b->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_sqr_inner(r->n, a->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1;
volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
@@ -1161,25 +1038,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
-#ifdef VERIFY
- if (flag) {
- r->magnitude = a->magnitude;
- r->normalized = a->normalized;
- }
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
+static SECP256K1_INLINE void secp256k1_fe_impl_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
@@ -1226,10 +1092,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
*
* 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:
+ *
+ * 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)
*
@@ -1239,10 +1103,6 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
* 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) {
@@ -1261,10 +1121,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
}
-static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
+static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
r->n[0] = a->n[0] | a->n[1] << 26;
r->n[1] = a->n[1] >> 6 | a->n[2] << 20;
r->n[2] = a->n[2] >> 12 | a->n[3] << 14;
@@ -1275,7 +1132,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
}
-static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0x3FFFFFFUL;
r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);
r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);
@@ -1286,11 +1143,6 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL);
r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL);
r->n[9] = a->n[7] >> 10;
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) {
@@ -1321,12 +1173,6 @@ static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32
r->n[7] = (a6 >> 2 ) & M26;
r->n[8] = (a6 >> 28 | a7 << 2) & M26;
r->n[9] = (a7 >> 24 | a8 << 6);
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) {
@@ -1334,10 +1180,6 @@ static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp2
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4],
a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9];
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
-
r->v[0] = (a0 | a1 << 26) & M30;
r->v[1] = (a1 >> 4 | a2 << 22) & M30;
r->v[2] = (a2 >> 8 | a3 << 18) & M30;
@@ -1355,37 +1197,27 @@ static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = {
0x2DDACACFL
};
-static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv32_signed30 s;
- tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
-
-#ifdef VERIFY
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
-#endif
}
-static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv32_signed30 s;
- tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
-
-#ifdef VERIFY
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
-#endif
}
-static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv32_signed30 s;
int jac, ret;
@@ -1403,10 +1235,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
-#ifdef VERIFY
- secp256k1_fe dummy;
- VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
-#endif
ret = jac >= 0;
}
return ret;
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index 50ee3f9ec9..f20c246fdd 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -9,15 +9,28 @@
#include <stdint.h>
+/** This field implementation represents the value as 5 uint64_t limbs in base
+ * 2^52. */
typedef struct {
- /* X = sum(i=0..4, n[i]*2^(i*52)) mod p
- * where p = 2^256 - 0x1000003D1
- */
+ /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p,
+ * where p is the field modulus, 2^256 - 2^32 - 977.
+ *
+ * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly
+ * corresponds to how much excess is allowed. The value
+ * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is
+ * normalized. */
uint64_t n[5];
-#ifdef VERIFY
- int magnitude;
- int normalized;
-#endif
+ /*
+ * Magnitude m requires:
+ * n[i] <= 2 * m * (2^52 - 1) for i=0..3
+ * n[4] <= 2 * m * (2^48 - 1)
+ *
+ * Normalized requires:
+ * n[i] <= (2^52 - 1) for i=0..3
+ * sum(i=0..4, n[i] << (i*52)) < p
+ * (together these imply n[4] <= 2^48 - 1)
+ */
+ SECP256K1_FE_VERIFY_FIELDS
} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
@@ -29,12 +42,6 @@ typedef struct {
((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \
}
-#ifdef VERIFY
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
-#else
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
-#endif
-
typedef struct {
uint64_t n[4];
} secp256k1_fe_storage;
diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h
index a2118044ab..04a9af2105 100644
--- a/src/secp256k1/src/field_5x52_asm_impl.h
+++ b/src/secp256k1/src/field_5x52_asm_impl.h
@@ -14,6 +14,8 @@
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
#define SECP256K1_FIELD_INNER5X52_IMPL_H
+#include "util.h"
+
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
/**
* Registers: rdx:rax = multiplication accumulator
@@ -278,7 +280,7 @@ __asm__ __volatile__(
"addq %%rsi,%%r8\n"
/* r[4] = c */
"movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3)
+: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
: "b"(b), "D"(r)
: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
);
@@ -493,7 +495,7 @@ __asm__ __volatile__(
"addq %%rsi,%%r8\n"
/* r[4] = c */
"movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3)
+: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
: "D"(r)
: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
);
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 6b97157d0f..0a4cc1a630 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -18,59 +18,33 @@
#include "field_5x52_int128_impl.h"
#endif
-/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
- * 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
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
+static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
const uint64_t *d = a->n;
- int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
+ int m = a->normalized ? 1 : 2 * a->magnitude;
/* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
- r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m);
- r &= (a->magnitude >= 0);
- r &= (a->magnitude <= 2048);
+ VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m);
if (a->normalized) {
- r &= (a->magnitude <= 1);
- if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
- r &= (d[0] < 0xFFFFEFFFFFC2FULL);
+ if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
+ VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL);
}
}
- VERIFY_CHECK(r == 1);
}
#endif
-static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
- VERIFY_CHECK(m >= 0);
- VERIFY_CHECK(m <= 2048);
+static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
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) {
+static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -105,15 +79,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
t4 &= 0x0FFFFFFFFFFFFULL;
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -130,14 +98,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
VERIFY_CHECK(t4 >> 49 == 0);
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
-
-#ifdef VERIFY
- r->magnitude = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -173,15 +136,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
}
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
@@ -204,7 +161,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
-static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
uint64_t t0, t1, t2, t3, t4;
uint64_t z0, z1;
uint64_t x;
@@ -245,53 +202,29 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
- VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
-#ifdef VERIFY
- r->magnitude = (a != 0);
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
const uint64_t *t = a->n;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
}
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
return a->n[0] & 1;
}
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
int i;
-#ifdef VERIFY
- a->magnitude = 0;
- a->normalized = 1;
-#endif
for (i=0; i<5; i++) {
a->n[i] = 0;
}
}
-static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- VERIFY_CHECK(b->normalized);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
-#endif
for (i = 4; i >= 0; i--) {
if (a->n[i] > b->n[i]) {
return 1;
@@ -303,8 +236,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
return 0;
}
-static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int ret;
+static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
r->n[0] = (uint64_t)a[31]
| ((uint64_t)a[30] << 8)
| ((uint64_t)a[29] << 16)
@@ -339,25 +271,15 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
| ((uint64_t)a[2] << 24)
| ((uint64_t)a[1] << 32)
| ((uint64_t)a[0] << 40);
- ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
-#ifdef VERIFY
- r->magnitude = 1;
- if (ret) {
- r->normalized = 1;
- secp256k1_fe_verify(r);
- } else {
- r->normalized = 0;
- }
-#endif
- return ret;
+}
+
+static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
+ secp256k1_fe_impl_set_b32_mod(r, a);
+ return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[0] = (a->n[4] >> 40) & 0xFF;
r[1] = (a->n[4] >> 32) & 0xFF;
r[2] = (a->n[4] >> 24) & 0xFF;
@@ -392,100 +314,50 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[31] = a->n[0] & 0xFF;
}
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= m);
- secp256k1_fe_verify(a);
+SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+ /* For all legal values of m (0..31), the following properties hold: */
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
+
+ /* Due to the properties above, the left hand in the subtractions below is never less than
+ * the right hand. */
r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2];
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3];
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
-#ifdef VERIFY
- r->magnitude = m + 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
-#ifdef VERIFY
- r->magnitude *= a;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
-#ifdef VERIFY
- secp256k1_fe_verify(r);
- VERIFY_CHECK(a >= 0);
- VERIFY_CHECK(a <= 0x7FFF);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
r->n[0] += a;
-#ifdef VERIFY
- r->magnitude += 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
r->n[3] += a->n[3];
r->n[4] += a->n[4];
-#ifdef VERIFY
- r->magnitude += a->magnitude;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- VERIFY_CHECK(b->magnitude <= 8);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
- VERIFY_CHECK(r != b);
- VERIFY_CHECK(a != b);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_mul_inner(r->n, a->n, b->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_sqr_inner(r->n, a->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1;
volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
@@ -496,24 +368,13 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
-#ifdef VERIFY
- if (flag) {
- r->magnitude = a->magnitude;
- r->normalized = a->normalized;
- }
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
+static SECP256K1_INLINE void secp256k1_fe_impl_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
@@ -550,10 +411,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
*
* 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:
+ *
+ * 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)
*
@@ -563,10 +422,6 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
* 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) {
@@ -581,27 +436,19 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
}
-static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
+static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
r->n[0] = a->n[0] | a->n[1] << 52;
r->n[1] = a->n[1] >> 12 | a->n[2] << 40;
r->n[2] = a->n[2] >> 24 | a->n[3] << 28;
r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
}
-static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);
r->n[4] = a->n[3] >> 16;
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) {
@@ -622,22 +469,12 @@ static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64
r->n[2] = (a1 >> 42 | a2 << 20) & M52;
r->n[3] = (a2 >> 32 | a3 << 30) & M52;
r->n[4] = (a3 >> 22 | a4 << 40);
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) {
const uint64_t M62 = UINT64_MAX >> 2;
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4];
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
-
r->v[0] = (a0 | a1 << 52) & M62;
r->v[1] = (a1 >> 10 | a2 << 42) & M62;
r->v[2] = (a2 >> 20 | a3 << 32) & M62;
@@ -650,37 +487,27 @@ static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = {
0x27C7F6E22DDACACFLL
};
-static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv64_signed62 s;
- tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
-
-#ifdef VERIFY
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
-#endif
}
-static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv64_signed62 s;
- tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
-
-#ifdef VERIFY
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
-#endif
}
-static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv64_signed62 s;
int jac, ret;
@@ -698,10 +525,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
-#ifdef VERIFY
- secp256k1_fe dummy;
- VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
-#endif
ret = jac >= 0;
}
return ret;
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 18567b95f3..b2a391dec9 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -10,6 +10,7 @@
#include <stdint.h>
#include "int128.h"
+#include "util.h"
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 0a03076bbc..f9769a4a39 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -7,6 +7,7 @@
#ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H
+#include "field.h"
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
@@ -19,6 +20,12 @@
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
+#ifdef VERIFY
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->magnitude <= 1);
+ VERIFY_CHECK(b->magnitude <= 31);
+#endif
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero(&na);
@@ -26,6 +33,12 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
+#ifdef VERIFY
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->magnitude <= 1);
+ VERIFY_CHECK(b->magnitude <= 31);
+#endif
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero_var(&na);
@@ -42,9 +55,13 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
* itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
*/
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
- int j;
+ int j, ret;
+#ifdef VERIFY
VERIFY_CHECK(r != a);
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->magnitude <= 8);
+#endif
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
@@ -128,7 +145,286 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
/* Check that a square root was actually calculated */
secp256k1_fe_sqr(&t1, r);
- return secp256k1_fe_equal(&t1, a);
+ ret = secp256k1_fe_equal(&t1, a);
+
+#ifdef VERIFY
+ if (!ret) {
+ secp256k1_fe_negate(&t1, &t1, 1);
+ secp256k1_fe_normalize_var(&t1);
+ VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a));
+ }
+#endif
+ return ret;
+}
+
+#ifndef VERIFY
+static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
+#else
+static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
+ /* Magnitude between 0 and 32. */
+ VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32));
+ /* Normalized is 0 or 1. */
+ VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
+ /* If normalized, magnitude must be 0 or 1. */
+ if (a->normalized) VERIFY_CHECK(a->magnitude <= 1);
+ /* Invoke implementation-specific checks. */
+ secp256k1_fe_impl_verify(a);
+}
+
+static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_normalize(r);
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_normalize_weak(r);
+ r->magnitude = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_normalize_var(r);
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
+SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ return secp256k1_fe_impl_normalizes_to_zero(r);
+}
+
+static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
+SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ return secp256k1_fe_impl_normalizes_to_zero_var(r);
+}
+
+static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
+SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
+ VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+ secp256k1_fe_impl_set_int(r, a);
+ r->magnitude = (a != 0);
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
+SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
+ VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_add_int(r, a);
+ r->magnitude += 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_clear(secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
+ a->magnitude = 0;
+ a->normalized = 1;
+ secp256k1_fe_impl_clear(a);
+ secp256k1_fe_verify(a);
+}
+
+static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
+SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ return secp256k1_fe_impl_is_zero(a);
+}
+
+static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
+SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ return secp256k1_fe_impl_is_odd(a);
+}
+
+static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
+SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->normalized);
+ VERIFY_CHECK(b->normalized);
+ return secp256k1_fe_impl_cmp_var(a, b);
+}
+
+static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
+SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
+ secp256k1_fe_impl_set_b32_mod(r, a);
+ r->magnitude = 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
}
+static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
+SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
+ if (secp256k1_fe_impl_set_b32_limit(r, a)) {
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+ return 1;
+ } else {
+ /* Mark the output field element as invalid. */
+ r->magnitude = -1;
+ return 0;
+ }
+}
+
+static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ secp256k1_fe_impl_get_b32(r, a);
+}
+
+static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
+SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(m >= 0 && m <= 31);
+ VERIFY_CHECK(a->magnitude <= m);
+ secp256k1_fe_impl_negate(r, a, m);
+ r->magnitude = m + 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a);
+SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(a >= 0 && a <= 32);
+ VERIFY_CHECK(a*r->magnitude <= 32);
+ secp256k1_fe_impl_mul_int(r, a);
+ r->magnitude *= a;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
+ secp256k1_fe_impl_add(r, a);
+ r->magnitude += a->magnitude;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
+SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->magnitude <= 8);
+ VERIFY_CHECK(b->magnitude <= 8);
+ VERIFY_CHECK(r != b);
+ VERIFY_CHECK(a != b);
+ secp256k1_fe_impl_mul(r, a, b);
+ r->magnitude = 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->magnitude <= 8);
+ secp256k1_fe_impl_sqr(r, a);
+ r->magnitude = 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
+SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+ VERIFY_CHECK(flag == 0 || flag == 1);
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_cmov(r, a, flag);
+ if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
+ if (!a->normalized) r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ secp256k1_fe_impl_to_storage(r, a);
+}
+
+static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
+SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+ secp256k1_fe_impl_from_storage(r, a);
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
+SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+ int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
+ secp256k1_fe_verify(x);
+ secp256k1_fe_impl_inv(r, x);
+ r->magnitude = x->magnitude > 0;
+ r->normalized = 1;
+ VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
+SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+ int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
+ secp256k1_fe_verify(x);
+ secp256k1_fe_impl_inv_var(r, x);
+ r->magnitude = x->magnitude > 0;
+ r->normalized = 1;
+ VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
+ secp256k1_fe_verify(r);
+}
+
+static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
+SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+ int ret;
+ secp256k1_fe tmp = *x, sqrt;
+ secp256k1_fe_verify(x);
+ ret = secp256k1_fe_impl_is_square_var(x);
+ secp256k1_fe_normalize_weak(&tmp);
+ VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
+ return ret;
+}
+
+static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
+SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
+ VERIFY_CHECK(m >= 0);
+ VERIFY_CHECK(m <= 32);
+ secp256k1_fe_impl_get_bounds(r, m);
+ r->magnitude = m;
+ r->normalized = (m == 0);
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_half(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(r->magnitude < 32);
+ secp256k1_fe_impl_half(r);
+ r->magnitude = (r->magnitude >> 1) + 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+#endif /* defined(VERIFY) */
+
#endif /* SECP256K1_FIELD_IMPL_H */
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index b79ba597db..877c3eaeed 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -51,6 +51,12 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
* for Y. Return value indicates whether the result is valid. */
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
+/** Determine whether x is a valid X coordinate on the curve. */
+static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
+
+/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
+static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
+
/** Check whether a group element is the point at infinity. */
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
@@ -164,4 +170,10 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
*/
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
+/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
+static void secp256k1_ge_verify(const secp256k1_ge *a);
+
+/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
+static void secp256k1_gej_verify(const secp256k1_gej *a);
+
#endif /* SECP256K1_GROUP_H */
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 82ce3f8d8b..dcd171f574 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -9,6 +9,7 @@
#include "field.h"
#include "group.h"
+#include "util.h"
/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\
@@ -72,37 +73,80 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
#endif
/* End of section generated by sage/gen_exhaustive_groups.sage. */
-static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, SECP256K1_B);
+static void secp256k1_ge_verify(const secp256k1_ge *a) {
+#ifdef VERIFY
+ secp256k1_fe_verify(&a->x);
+ secp256k1_fe_verify(&a->y);
+ VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
+#endif
+ (void)a;
+}
+
+static void secp256k1_gej_verify(const secp256k1_gej *a) {
+#ifdef VERIFY
+ secp256k1_fe_verify(&a->x);
+ secp256k1_fe_verify(&a->y);
+ secp256k1_fe_verify(&a->z);
+ VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
+#endif
+ (void)a;
+}
+/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
+ secp256k1_gej_verify(a);
+ secp256k1_fe_verify(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi);
secp256k1_fe_mul(&r->x, &a->x, &zi2);
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
+ secp256k1_ge_verify(r);
+}
+
+/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
+static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
+ secp256k1_fe zi2;
+ secp256k1_fe zi3;
+ secp256k1_ge_verify(a);
+ secp256k1_fe_verify(zi);
+ VERIFY_CHECK(!a->infinity);
+ secp256k1_fe_sqr(&zi2, zi);
+ secp256k1_fe_mul(&zi3, &zi2, zi);
+ secp256k1_fe_mul(&r->x, &a->x, &zi2);
+ secp256k1_fe_mul(&r->y, &a->y, &zi3);
+ r->infinity = a->infinity;
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
+ secp256k1_fe_verify(x);
+ secp256k1_fe_verify(y);
r->infinity = 0;
r->x = *x;
r->y = *y;
+ secp256k1_ge_verify(r);
}
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
+ secp256k1_ge_verify(a);
return a->infinity;
}
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
+ secp256k1_ge_verify(a);
*r = *a;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
+ secp256k1_gej_verify(a);
r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
@@ -112,14 +156,17 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_set_int(&a->z, 1);
r->x = a->x;
r->y = a->y;
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
- if (a->infinity) {
+ secp256k1_gej_verify(a);
+ if (secp256k1_gej_is_infinity(a)) {
secp256k1_ge_set_infinity(r);
return;
}
+ r->infinity = 0;
secp256k1_fe_inv_var(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_mul(&z3, &a->z, &z2);
@@ -127,6 +174,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
secp256k1_ge_set_xy(r, &a->x, &a->y);
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
@@ -135,6 +183,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
size_t last_i = SIZE_MAX;
for (i = 0; i < len; i++) {
+ secp256k1_gej_verify(&a[i]);
if (a[i].infinity) {
secp256k1_ge_set_infinity(&r[i]);
} else {
@@ -168,6 +217,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
}
+ secp256k1_ge_verify(&r[i]);
}
}
@@ -176,21 +226,25 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
secp256k1_fe zs;
if (len > 0) {
+ /* Verify inputs a[len-1] and zr[len-1]. */
+ secp256k1_ge_verify(&a[i]);
+ secp256k1_fe_verify(&zr[i]);
/* Ensure all y values are in weak normal form for fast negation of points */
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;
+ /* Verify all inputs a[i] and zr[i]. */
+ secp256k1_fe_verify(&zr[i]);
+ secp256k1_ge_verify(&a[i]);
if (i != len - 1) {
secp256k1_fe_mul(&zs, &zs, &zr[i]);
}
i--;
- tmpa.x = a[i].x;
- tmpa.y = a[i].y;
- tmpa.infinity = 0;
- secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
+ secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs);
+ /* Verify the output a[i]. */
+ secp256k1_ge_verify(&a[i]);
}
}
}
@@ -200,12 +254,14 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z);
+ secp256k1_gej_verify(r);
}
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
r->infinity = 1;
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
+ secp256k1_ge_verify(r);
}
static void secp256k1_gej_clear(secp256k1_gej *r) {
@@ -223,31 +279,35 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
secp256k1_fe x2, x3;
+ int ret;
+ secp256k1_fe_verify(x);
r->x = *x;
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
secp256k1_fe_add_int(&x3, SECP256K1_B);
- if (!secp256k1_fe_sqrt(&r->y, &x3)) {
- return 0;
- }
+ ret = secp256k1_fe_sqrt(&r->y, &x3);
secp256k1_fe_normalize_var(&r->y);
if (secp256k1_fe_is_odd(&r->y) != odd) {
secp256k1_fe_negate(&r->y, &r->y, 1);
}
- return 1;
-
+ secp256k1_ge_verify(r);
+ return ret;
}
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
+ secp256k1_ge_verify(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_set_int(&r->z, 1);
+ secp256k1_gej_verify(r);
}
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej tmp;
+ secp256k1_gej_verify(b);
+ secp256k1_gej_verify(a);
secp256k1_gej_neg(&tmp, a);
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
return secp256k1_gej_is_infinity(&tmp);
@@ -255,6 +315,8 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b)
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r, r2;
+ secp256k1_fe_verify(x);
+ secp256k1_gej_verify(a);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
@@ -262,20 +324,24 @@ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a)
}
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
+ secp256k1_gej_verify(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
r->z = a->z;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
+ secp256k1_gej_verify(r);
}
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
+ secp256k1_gej_verify(a);
return a->infinity;
}
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
secp256k1_fe y2, x3;
+ secp256k1_ge_verify(a);
if (a->infinity) {
return 0;
}
@@ -291,6 +357,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
secp256k1_fe l, s, t;
+ secp256k1_gej_verify(a);
r->infinity = a->infinity;
/* Formula used:
@@ -317,6 +384,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
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) */
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
@@ -330,6 +398,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
* the infinity flag even though the point doubles to infinity, and the result
* point will be gibberish (z = 0 but infinity = 0).
*/
+ secp256k1_gej_verify(a);
if (a->infinity) {
secp256k1_gej_set_infinity(r);
if (rzr != NULL) {
@@ -344,12 +413,15 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
}
secp256k1_gej_double(r, a);
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
+ secp256k1_gej_verify(a);
+ secp256k1_gej_verify(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
*r = *b;
@@ -404,11 +476,14 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
/* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
+ secp256k1_gej_verify(a);
+ secp256k1_ge_verify(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
secp256k1_gej_set_ge(r, b);
@@ -461,12 +536,16 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
+ secp256k1_gej_verify(r);
+ if (rzr != NULL) secp256k1_fe_verify(rzr);
}
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
/* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
+ secp256k1_ge_verify(b);
+ secp256k1_fe_verify(bzinv);
if (a->infinity) {
secp256k1_fe bzinv2, bzinv3;
r->infinity = b->infinity;
@@ -525,6 +604,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
+ secp256k1_gej_verify(r);
}
@@ -533,6 +613,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
int degenerate;
+ secp256k1_gej_verify(a);
+ secp256k1_ge_verify(b);
VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
@@ -658,21 +740,28 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* We have degenerate = false, r->z = (y1 + y2) * Z.
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
/* Operations: 4 mul, 1 sqr */
secp256k1_fe zz;
- VERIFY_CHECK(!secp256k1_fe_is_zero(s));
+ secp256k1_gej_verify(r);
+ secp256k1_fe_verify(s);
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
+#endif
secp256k1_fe_sqr(&zz, s);
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
secp256k1_fe_mul(&r->y, &r->y, &zz);
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
+ secp256k1_gej_verify(r);
}
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
secp256k1_fe x, y;
+ secp256k1_ge_verify(a);
VERIFY_CHECK(!a->infinity);
x = a->x;
secp256k1_fe_normalize(&x);
@@ -686,14 +775,18 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
secp256k1_fe_from_storage(&r->x, &a->x);
secp256k1_fe_from_storage(&r->y, &a->y);
r->infinity = 0;
+ secp256k1_ge_verify(r);
}
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
+ secp256k1_gej_verify(r);
+ secp256k1_gej_verify(a);
secp256k1_fe_cmov(&r->x, &a->x, flag);
secp256k1_fe_cmov(&r->y, &a->y, flag);
secp256k1_fe_cmov(&r->z, &a->z, flag);
r->infinity ^= (r->infinity ^ a->infinity) & flag;
+ secp256k1_gej_verify(r);
}
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
@@ -703,7 +796,9 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
*r = *a;
+ secp256k1_ge_verify(a);
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
+ secp256k1_ge_verify(r);
}
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
@@ -711,6 +806,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
secp256k1_gej out;
int i;
+ secp256k1_ge_verify(ge);
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
secp256k1_gej_set_infinity(&out);
for (i = 0; i < 32; ++i) {
@@ -727,4 +823,32 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
#endif
}
+static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
+ secp256k1_fe c;
+ secp256k1_fe_sqr(&c, x);
+ secp256k1_fe_mul(&c, &c, x);
+ secp256k1_fe_add_int(&c, SECP256K1_B);
+ return secp256k1_fe_is_square_var(&c);
+}
+
+static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
+ /* We want to determine whether (xn/xd) is on the curve.
+ *
+ * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
+ */
+ secp256k1_fe r, t;
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
+#endif
+ secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
+ secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
+ secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
+ secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
+ secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
+ VERIFY_CHECK(SECP256K1_B <= 31);
+ secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
+ secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
+ return secp256k1_fe_is_square_var(&r);
+}
+
#endif /* SECP256K1_GROUP_IMPL_H */
diff --git a/src/secp256k1/src/int128_native_impl.h b/src/secp256k1/src/int128_native_impl.h
index 996e542cf9..7f02e1590b 100644
--- a/src/secp256k1/src/int128_native_impl.h
+++ b/src/secp256k1/src/int128_native_impl.h
@@ -2,6 +2,7 @@
#define SECP256K1_INT128_NATIVE_IMPL_H
#include "int128.h"
+#include "util.h"
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
*r = (((uint128_t)hi) << 64) + lo;
diff --git a/src/secp256k1/src/int128_struct_impl.h b/src/secp256k1/src/int128_struct_impl.h
index cc17bad167..990982da84 100644
--- a/src/secp256k1/src/int128_struct_impl.h
+++ b/src/secp256k1/src/int128_struct_impl.h
@@ -2,6 +2,7 @@
#define SECP256K1_INT128_STRUCT_IMPL_H
#include "int128.h"
+#include "util.h"
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
# include <intrin.h>
diff --git a/src/secp256k1/src/modinv32_impl.h b/src/secp256k1/src/modinv32_impl.h
index 8e400b697b..0ea2699863 100644
--- a/src/secp256k1/src/modinv32_impl.h
+++ b/src/secp256k1/src/modinv32_impl.h
@@ -64,7 +64,7 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4],
r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8];
- int32_t cond_add, cond_negate;
+ volatile int32_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^30,2^30). */
@@ -186,7 +186,8 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* being inside [-2^31,2^31) means that casting to signed works correctly.
*/
uint32_t u = 1, v = 0, q = 0, r = 1;
- uint32_t c1, c2, f = f0, g = g0, x, y, z;
+ volatile uint32_t c1, c2;
+ uint32_t mask1, mask2, f = f0, g = g0, x, y, z;
int i;
for (i = 0; i < 30; ++i) {
@@ -195,23 +196,25 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 31;
- c2 = -(g & 1);
+ mask1 = c1;
+ c2 = g & 1;
+ mask2 = -c2;
/* Compute x,y,z, conditionally negated versions of f,u,v. */
- x = (f ^ c1) - c1;
- y = (u ^ c1) - c1;
- z = (v ^ c1) - c1;
+ x = (f ^ mask1) - mask1;
+ y = (u ^ mask1) - mask1;
+ z = (v ^ mask1) - mask1;
/* Conditionally add x,y,z to g,q,r. */
- g += x & c2;
- q += y & c2;
- r += z & c2;
- /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
- c1 &= c2;
+ g += x & mask2;
+ q += y & mask2;
+ r += z & mask2;
+ /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */
+ mask1 &= mask2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
- zeta = (zeta ^ c1) - 1;
+ zeta = (zeta ^ mask1) - 1;
/* Conditionally add g,q,r to f,u,v. */
- f += g & c1;
- u += q & c1;
- v += r & c1;
+ f += g & mask1;
+ u += q & mask1;
+ v += r & mask1;
/* Shifts */
g >>= 1;
u <<= 1;
diff --git a/src/secp256k1/src/modinv64_impl.h b/src/secp256k1/src/modinv64_impl.h
index e33727d385..c7cef872a4 100644
--- a/src/secp256k1/src/modinv64_impl.h
+++ b/src/secp256k1/src/modinv64_impl.h
@@ -88,7 +88,7 @@ static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *
static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4];
- int64_t cond_add, cond_negate;
+ volatile int64_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^62,2^62). */
@@ -175,7 +175,8 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
* being inside [-2^63,2^63) means that casting to signed works correctly.
*/
uint64_t u = 8, v = 0, q = 0, r = 8;
- uint64_t c1, c2, f = f0, g = g0, x, y, z;
+ volatile uint64_t c1, c2;
+ uint64_t mask1, mask2, f = f0, g = g0, x, y, z;
int i;
for (i = 3; i < 62; ++i) {
@@ -184,23 +185,25 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 63;
- c2 = -(g & 1);
+ mask1 = c1;
+ c2 = g & 1;
+ mask2 = -c2;
/* Compute x,y,z, conditionally negated versions of f,u,v. */
- x = (f ^ c1) - c1;
- y = (u ^ c1) - c1;
- z = (v ^ c1) - c1;
+ x = (f ^ mask1) - mask1;
+ y = (u ^ mask1) - mask1;
+ z = (v ^ mask1) - mask1;
/* Conditionally add x,y,z to g,q,r. */
- g += x & c2;
- q += y & c2;
- r += z & c2;
+ g += x & mask2;
+ q += y & mask2;
+ r += z & mask2;
/* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
- c1 &= c2;
+ mask1 &= mask2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
- zeta = (zeta ^ c1) - 1;
+ zeta = (zeta ^ mask1) - 1;
/* Conditionally add g,q,r to f,u,v. */
- f += g & c1;
- u += q & c1;
- v += r & c1;
+ f += g & mask1;
+ u += q & mask1;
+ v += r & mask1;
/* Shifts */
g >>= 1;
u <<= 1;
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
index 5408c9de70..82b082a9f0 100644
--- a/src/secp256k1/src/modules/ecdh/main_impl.h
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -50,7 +50,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
overflow |= secp256k1_scalar_is_zero(&s);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
- secp256k1_ecmult_const(&res, &pt, &s, 256);
+ secp256k1_ecmult_const(&res, &pt, &s);
secp256k1_ge_set_gej(&pt, &res);
/* Compute a hash of the point */
diff --git a/src/secp256k1/src/modules/ellswift/Makefile.am.include b/src/secp256k1/src/modules/ellswift/Makefile.am.include
new file mode 100644
index 0000000000..e7efea2981
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/Makefile.am.include
@@ -0,0 +1,4 @@
+include_HEADERS += include/secp256k1_ellswift.h
+noinst_HEADERS += src/modules/ellswift/bench_impl.h
+noinst_HEADERS += src/modules/ellswift/main_impl.h
+noinst_HEADERS += src/modules/ellswift/tests_impl.h
diff --git a/src/secp256k1/src/modules/ellswift/bench_impl.h b/src/secp256k1/src/modules/ellswift/bench_impl.h
new file mode 100644
index 0000000000..b16a3a3687
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/bench_impl.h
@@ -0,0 +1,106 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H
+#define SECP256K1_MODULE_ELLSWIFT_BENCH_H
+
+#include "../../../include/secp256k1_ellswift.h"
+
+typedef struct {
+ secp256k1_context *ctx;
+ secp256k1_pubkey point[256];
+ unsigned char rnd64[64];
+} bench_ellswift_data;
+
+static void bench_ellswift_setup(void *arg) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+ static const unsigned char init[64] = {
+ 0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68,
+ 0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e,
+ 0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79,
+ 0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21,
+ 0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f,
+ 0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30,
+ 0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85,
+ 0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc
+ };
+ memcpy(data->rnd64, init, 64);
+ for (i = 0; i < 256; ++i) {
+ int j;
+ CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64));
+ for (j = 0; j < 64; ++j) {
+ data->rnd64[j] += 1;
+ }
+ }
+ CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16));
+}
+
+static void bench_ellswift_encode(void *arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16));
+ }
+}
+
+static void bench_ellswift_create(void *arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ unsigned char buf[64];
+ CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32));
+ memcpy(data->rnd64, buf, 64);
+ }
+}
+
+static void bench_ellswift_decode(void *arg, int iters) {
+ int i;
+ secp256k1_pubkey out;
+ size_t len;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1);
+ len = 33;
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED));
+ }
+}
+
+static void bench_ellswift_xdh(void *arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ int party = i & 1;
+ CHECK(secp256k1_ellswift_xdh(data->ctx,
+ data->rnd64 + (i % 33),
+ data->rnd64,
+ data->rnd64,
+ data->rnd64 + ((i + 16) % 33),
+ party,
+ secp256k1_ellswift_xdh_hash_function_bip324,
+ NULL) == 1);
+ }
+}
+
+void run_ellswift_bench(int iters, int argc, char **argv) {
+ bench_ellswift_data data;
+ int d = argc == 1;
+
+ /* create a context with signing capabilities */
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters);
+
+ secp256k1_context_destroy(data.ctx);
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/ellswift/main_impl.h b/src/secp256k1/src/modules/ellswift/main_impl.h
new file mode 100644
index 0000000000..00bb8a3da5
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/main_impl.h
@@ -0,0 +1,589 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H
+#define SECP256K1_MODULE_ELLSWIFT_MAIN_H
+
+#include "../../../include/secp256k1.h"
+#include "../../../include/secp256k1_ellswift.h"
+#include "../../eckey.h"
+#include "../../hash.h"
+
+/** c1 = (sqrt(-3)-1)/2 */
+static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40);
+/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */
+static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee);
+/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */
+static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef);
+/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */
+static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41);
+
+/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */
+static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) {
+ /* The implemented algorithm is the following (all operations in GF(p)):
+ *
+ * - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852.
+ * - If u = 0, set u = 1.
+ * - If t = 0, set t = 1.
+ * - If u^3+7+t^2 = 0, set t = 2*t.
+ * - Let X = (u^3+7-t^2)/(2*t).
+ * - Let Y = (X+t)/(c0*u).
+ * - If x3 = u+4*Y^2 is a valid x coordinate, return it.
+ * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
+ * - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate).
+ *
+ * Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get:
+ *
+ * - Let c0 = ...
+ * - If u = 0, set u = 1.
+ * - If t = 0, set t = 1.
+ * - Let s = t^2
+ * - Let g = u^3+7
+ * - If g+s = 0, set t = 2*t, s = 4*s
+ * - Let X = (g-s)/(2*t).
+ * - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u).
+ * - If x3 = u+4*Y^2 is a valid x coordinate, return it.
+ * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
+ * - Return x1 = -(x2+u).
+ *
+ * Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This
+ * means X and Y do not need to be evaluated explicitly anymore.
+ *
+ * - ...
+ * - If g+s = 0, set s = 4*s.
+ * - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it.
+ * - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it.
+ * - Return x1 = -(x2+u).
+ *
+ * Simplifying x2 using 2 additional constants:
+ *
+ * - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
+ * - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
+ * - ...
+ * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
+ * - ...
+ *
+ * Writing x3 as a fraction:
+ *
+ * - ...
+ * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ...
+ * - ...
+
+ * Overall, we get:
+ *
+ * - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
+ * - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
+ * - If u = 0, set u = 1.
+ * - If t = 0, set s = 1, else set s = t^2.
+ * - Let g = u^3+7.
+ * - If g+s = 0, set s = 4*s.
+ * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it.
+ * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
+ * - Return x1 = -(x2+u).
+ */
+ secp256k1_fe u1, s, g, p, d, n, l;
+ u1 = *u;
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one;
+ secp256k1_fe_sqr(&s, t);
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one;
+ secp256k1_fe_sqr(&l, &u1); /* l = u^2 */
+ secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */
+ secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */
+ p = g; /* p = g */
+ secp256k1_fe_add(&p, &s); /* p = g+s */
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) {
+ secp256k1_fe_mul_int(&s, 4);
+ /* Recompute p = g+s */
+ p = g; /* p = g */
+ secp256k1_fe_add(&p, &s); /* p = g+s */
+ }
+ secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */
+ secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */
+ secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */
+ secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */
+ secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */
+ secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */
+ if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) {
+ /* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */
+ *xn = n;
+ *xd = d;
+ return;
+ }
+ *xd = p;
+ secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */
+ secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */
+ secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */
+ secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */
+ /* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed,
+ * which we already have computed above. This could be deduplicated. */
+ if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) {
+ /* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */
+ *xn = n;
+ return;
+ }
+ secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */
+ secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */
+ secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p));
+#endif
+ /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */
+}
+
+/** Decode ElligatorSwift encoding (u, t) to X coordinate. */
+static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) {
+ secp256k1_fe xn, xd;
+ secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t);
+ secp256k1_fe_inv_var(&xd, &xd);
+ secp256k1_fe_mul(x, &xn, &xd);
+}
+
+/** Decode ElligatorSwift encoding (u, t) to point P. */
+static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) {
+ secp256k1_fe x;
+ secp256k1_ellswift_xswiftec_var(&x, u, t);
+ secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t));
+}
+
+/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x.
+ *
+ * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also
+ * fewer, or none at all. Each such partial inverse can be accessed individually using a
+ * distinct input argument c (in range 0-7), and some or all of these may return failure.
+ * The following guarantees exist:
+ * - Given (x, u), no two distinct c values give the same successful result t.
+ * - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var.
+ * - Given (x, u), all t values that map back to x can be reached by combining the
+ * successful results from this function over all c values, with the exception of:
+ * - this function cannot be called with u=0
+ * - no result with t=0 will be returned
+ * - no result for which u^3 + t^2 + 7 = 0 will be returned.
+ *
+ * The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then
+ * using the low and high bits to pick signs of square roots) is to match the paper's
+ * encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through
+ * c=7 are copies of those with an additional negation of sqrt(w).
+ */
+static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) {
+ /* The implemented algorithm is this (all arithmetic, except involving c, is mod p):
+ *
+ * - If (c & 2) = 0:
+ * - If (-x-u) is a valid X coordinate, fail.
+ * - Let s=-(u^3+7)/(u^2+u*x+x^2).
+ * - If s is not square, fail.
+ * - Let v=x.
+ * - If (c & 2) = 2:
+ * - Let s=x-u.
+ * - If s is not square, fail.
+ * - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist.
+ * - If (c & 1) = 1 and r = 0, fail.
+ * - If s=0, fail.
+ * - Let v=(r/s-u)/2.
+ * - Let w=sqrt(s).
+ * - If (c & 5) = 0: return -w*(c3*u + v).
+ * - If (c & 5) = 1: return w*(c4*u + v).
+ * - If (c & 5) = 4: return w*(c3*u + v).
+ * - If (c & 5) = 5: return -w*(c4*u + v).
+ */
+ secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q;
+ int ret;
+
+ secp256k1_fe_normalize_weak(&x);
+ secp256k1_fe_normalize_weak(&u);
+
+#ifdef VERIFY
+ VERIFY_CHECK(c >= 0 && c < 8);
+ VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x));
+#endif
+
+ if (!(c & 2)) {
+ /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or
+ * c=4) formula, or x2 (if c=1 or c=5) formula. */
+
+ /* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips
+ * back under the x3 formula instead (which has priority over x1 and x2, so the decoding
+ * would not match x). */
+ m = x; /* m = x */
+ secp256k1_fe_add(&m, &u); /* m = u+x */
+ secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */
+ /* Test if (-u-x) is a valid X coordinate. If so, fail. */
+ if (secp256k1_ge_x_on_curve_var(&m)) return 0;
+
+ /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */
+ secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */
+ secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */
+ secp256k1_fe_mul(&m, &u, &x); /* m = u*x */
+ secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */
+
+ /* Note that at this point, s = 0 is impossible. If it were the case:
+ * s = -(u^2 + u*x + x^2) = 0
+ * => u^2 + u*x + x^2 = 0
+ * => (u + 2*x) * (u^2 + u*x + x^2) = 0
+ * => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0
+ * => (x + u)^3 + x^3 = 0
+ * => x^3 = -(x + u)^3
+ * => x^3 + B = (-u - x)^3 + B
+ *
+ * However, we know x^3 + B is square (because x is on the curve) and
+ * that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m)
+ * test above would have failed). This is a contradiction, and thus the
+ * assumption s=0 is false. */
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s));
+#endif
+
+ /* If s is not square, fail. We have not fully computed s yet, but s is square iff
+ * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is
+ * nonzero). */
+ secp256k1_fe_sqr(&g, &u); /* g = u^2 */
+ secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
+ secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */
+ secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */
+ if (!secp256k1_fe_is_square_var(&m)) return 0;
+
+ /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */
+ secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */
+ secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */
+
+ /* Let v = x. */
+ v = x;
+ } else {
+ /* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */
+
+ /* Let s = x-u. */
+ secp256k1_fe_negate(&m, &u, 1); /* m = -u */
+ s = m; /* s = -u */
+ secp256k1_fe_add(&s, &x); /* s = x-u */
+
+ /* If s is not square, fail. */
+ if (!secp256k1_fe_is_square_var(&s)) return 0;
+
+ /* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */
+ secp256k1_fe_sqr(&g, &u); /* g = u^2 */
+ secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */
+ secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */
+ secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
+ secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */
+ secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */
+ secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */
+ secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */
+ secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */
+ if (!secp256k1_fe_is_square_var(&q)) return 0;
+ ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */
+ VERIFY_CHECK(ret);
+
+ /* If (c & 1) = 1 and r = 0, fail. */
+ if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0;
+
+ /* If s = 0, fail. */
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0;
+
+ /* Let v = (r/s-u)/2. */
+ secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */
+ secp256k1_fe_mul(&v, &v, &r); /* v = r/s */
+ secp256k1_fe_add(&v, &m); /* v = r/s-u */
+ secp256k1_fe_half(&v); /* v = (r/s-u)/2 */
+ }
+
+ /* Let w = sqrt(s). */
+ ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */
+ VERIFY_CHECK(ret);
+
+ /* Return logic. */
+ if ((c & 5) == 0 || (c & 5) == 5) {
+ secp256k1_fe_negate(&m, &m, 1); /* m = -w */
+ }
+ /* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */
+ secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3);
+ /* u = {c4 if c&1=1; c3 otherwise}*u */
+ secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */
+ secp256k1_fe_mul(t, &m, &u);
+ return 1;
+}
+
+/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt).
+ *
+ * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
+ * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
+ * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
+static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
+ secp256k1_sha256 hash = *hasher;
+ unsigned char buf4[4];
+#ifdef VERIFY
+ size_t blocks = hash.bytes >> 6;
+#endif
+ buf4[0] = cnt;
+ buf4[1] = cnt >> 8;
+ buf4[2] = cnt >> 16;
+ buf4[3] = cnt >> 24;
+ secp256k1_sha256_write(&hash, buf4, 4);
+ secp256k1_sha256_finalize(&hash, out32);
+#ifdef VERIFY
+ /* Writing and finalizing together should trigger exactly one SHA256 compression. */
+ VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
+#endif
+}
+
+/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate.
+ *
+ * u32 is the 32-byte big endian encoding of u; t is the output field element t that still
+ * needs encoding.
+ *
+ * hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
+static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
+ /* Pool of 3-bit branch values. */
+ unsigned char branch_hash[32];
+ /* Number of 3-bit values in branch_hash left. */
+ int branches_left = 0;
+ /* Field elements u and branch values are extracted from RNG based on hasher for consecutive
+ * values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64
+ * cnt values that follow are used to generate field elements u. cnt==65 (and multiples
+ * thereof) are used to repopulate the pool and start over, if that were ever necessary.
+ * On average, 4 iterations are needed. */
+ uint32_t cnt = 0;
+ while (1) {
+ int branch;
+ secp256k1_fe u;
+ /* If the pool of branch values is empty, populate it. */
+ if (branches_left == 0) {
+ secp256k1_ellswift_prng(branch_hash, hasher, cnt++);
+ branches_left = 64;
+ }
+ /* Take a 3-bit branch value from the branch pool (top bit is discarded). */
+ --branches_left;
+ branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
+ /* Compute a new u value by hashing. */
+ secp256k1_ellswift_prng(u32, hasher, cnt++);
+ /* overflow is not a problem (we prefer uniform u32 over uniform u). */
+ secp256k1_fe_set_b32_mod(&u, u32);
+ /* Since u is the output of a hash, it should practically never be 0. We could apply the
+ * u=0 to u=1 correction here too to deal with that case still, but it's such a low
+ * probability event that we do not bother. */
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u));
+#endif
+ /* Find a remainder t, and return it if found. */
+ if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break;
+ }
+}
+
+/** Find an ElligatorSwift encoding (u, t) for point P.
+ *
+ * This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p
+ * as input, and returns an encoding that matches the provided Y coordinate rather than a random
+ * one.
+ */
+static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
+ secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher);
+ secp256k1_fe_normalize_var(t);
+ if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
+ secp256k1_fe_negate(t, t, 1);
+ secp256k1_fe_normalize_var(t);
+ }
+}
+
+/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */
+static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) {
+ secp256k1_sha256_initialize(hash);
+ hash->s[0] = 0xd1a6524bul;
+ hash->s[1] = 0x028594b3ul;
+ hash->s[2] = 0x96e42f4eul;
+ hash->s[3] = 0x1037a177ul;
+ hash->s[4] = 0x1b8fcb8bul;
+ hash->s[5] = 0x56023885ul;
+ hash->s[6] = 0x2560ede1ul;
+ hash->s[7] = 0xd626b715ul;
+
+ hash->bytes = 64;
+}
+
+int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(ell64 != NULL);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(rnd32 != NULL);
+
+ if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
+ secp256k1_fe t;
+ unsigned char p64[64] = {0};
+ size_t ser_size;
+ int ser_ret;
+ secp256k1_sha256 hash;
+
+ /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using
+ * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
+ secp256k1_ellswift_sha256_init_encode(&hash);
+ ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1);
+ VERIFY_CHECK(ser_ret && ser_size == 33);
+ secp256k1_sha256_write(&hash, p64, sizeof(p64));
+ secp256k1_sha256_write(&hash, rnd32, 32);
+
+ /* Compute ElligatorSwift encoding and construct output. */
+ secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
+ secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
+ return 1;
+ }
+ /* Only reached in case the provided pubkey is invalid. */
+ memset(ell64, 0, 64);
+ return 0;
+}
+
+/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */
+static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) {
+ secp256k1_sha256_initialize(hash);
+ hash->s[0] = 0xd29e1bf5ul;
+ hash->s[1] = 0xf7025f42ul;
+ hash->s[2] = 0x9b024773ul;
+ hash->s[3] = 0x094cb7d5ul;
+ hash->s[4] = 0xe59ed789ul;
+ hash->s[5] = 0x03bc9786ul;
+ hash->s[6] = 0x68335b35ul;
+ hash->s[7] = 0x4e363b53ul;
+
+ hash->bytes = 64;
+}
+
+int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) {
+ secp256k1_ge p;
+ secp256k1_fe t;
+ secp256k1_sha256 hash;
+ secp256k1_scalar seckey_scalar;
+ int ret;
+ static const unsigned char zero32[32] = {0};
+
+ /* Sanity check inputs. */
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(ell64 != NULL);
+ memset(ell64, 0, 64);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(seckey32 != NULL);
+
+ /* Compute (affine) public key */
+ ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32);
+ secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */
+ secp256k1_fe_normalize_var(&p.x);
+ secp256k1_fe_normalize_var(&p.y);
+
+ /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++),
+ * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */
+ secp256k1_ellswift_sha256_init_create(&hash);
+ secp256k1_sha256_write(&hash, seckey32, 32);
+ secp256k1_sha256_write(&hash, zero32, sizeof(zero32));
+ secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */
+ if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32);
+
+ /* Compute ElligatorSwift encoding and construct output. */
+ secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
+ secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
+
+ secp256k1_memczero(ell64, 64, !ret);
+ secp256k1_scalar_clear(&seckey_scalar);
+
+ return ret;
+}
+
+int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) {
+ secp256k1_fe u, t;
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(ell64 != NULL);
+
+ secp256k1_fe_set_b32_mod(&u, ell64);
+ secp256k1_fe_set_b32_mod(&t, ell64 + 32);
+ secp256k1_fe_normalize_var(&t);
+ secp256k1_ellswift_swiftec_var(&p, &u, &t);
+ secp256k1_pubkey_save(pubkey, &p);
+ return 1;
+}
+
+static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
+ secp256k1_sha256 sha;
+
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, data, 64);
+ secp256k1_sha256_write(&sha, ell_a64, 64);
+ secp256k1_sha256_write(&sha, ell_b64, 64);
+ secp256k1_sha256_write(&sha, x32, 32);
+ secp256k1_sha256_finalize(&sha, output);
+
+ return 1;
+}
+
+/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */
+static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) {
+ secp256k1_sha256_initialize(hash);
+ hash->s[0] = 0x8c12d730ul;
+ hash->s[1] = 0x827bd392ul;
+ hash->s[2] = 0x9e4fb2eeul;
+ hash->s[3] = 0x207b373eul;
+ hash->s[4] = 0x2292bd7aul;
+ hash->s[5] = 0xaa5441bcul;
+ hash->s[6] = 0x15c3779ful;
+ hash->s[7] = 0xcfb52549ul;
+
+ hash->bytes = 64;
+}
+
+static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
+ secp256k1_sha256 sha;
+
+ (void)data;
+
+ secp256k1_ellswift_sha256_init_bip324(&sha);
+ secp256k1_sha256_write(&sha, ell_a64, 64);
+ secp256k1_sha256_write(&sha, ell_b64, 64);
+ secp256k1_sha256_write(&sha, x32, 32);
+ secp256k1_sha256_finalize(&sha, output);
+
+ return 1;
+}
+
+const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix;
+const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324;
+
+int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) {
+ int ret = 0;
+ int overflow;
+ secp256k1_scalar s;
+ secp256k1_fe xn, xd, px, u, t;
+ unsigned char sx[32];
+ const unsigned char* theirs64;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(output != NULL);
+ ARG_CHECK(ell_a64 != NULL);
+ ARG_CHECK(ell_b64 != NULL);
+ ARG_CHECK(seckey32 != NULL);
+ ARG_CHECK(hashfp != NULL);
+
+ /* Load remote public key (as fraction). */
+ theirs64 = party ? ell_a64 : ell_b64;
+ secp256k1_fe_set_b32_mod(&u, theirs64);
+ secp256k1_fe_set_b32_mod(&t, theirs64 + 32);
+ secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t);
+
+ /* Load private key (using one if invalid). */
+ secp256k1_scalar_set_b32(&s, seckey32, &overflow);
+ overflow = secp256k1_scalar_is_zero(&s);
+ secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
+
+ /* Compute shared X coordinate. */
+ secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1);
+ secp256k1_fe_normalize(&px);
+ secp256k1_fe_get_b32(sx, &px);
+
+ /* Invoke hasher */
+ ret = hashfp(output, sx, ell_a64, ell_b64, data);
+
+ memset(sx, 0, 32);
+ secp256k1_fe_clear(&px);
+ secp256k1_scalar_clear(&s);
+
+ return !!ret & !overflow;
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/ellswift/tests_impl.h b/src/secp256k1/src/modules/ellswift/tests_impl.h
new file mode 100644
index 0000000000..86ca09862b
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/tests_impl.h
@@ -0,0 +1,434 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H
+#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
+
+#include "../../../include/secp256k1_ellswift.h"
+
+struct ellswift_xswiftec_inv_test {
+ int enc_bitmap;
+ secp256k1_fe u;
+ secp256k1_fe x;
+ secp256k1_fe encs[8];
+};
+
+struct ellswift_decode_test {
+ unsigned char enc[64];
+ secp256k1_fe x;
+ int odd_y;
+};
+
+struct ellswift_xdh_test {
+ unsigned char priv_ours[32];
+ unsigned char ellswift_ours[64];
+ unsigned char ellswift_theirs[64];
+ int initiating;
+ unsigned char shared_secret[32];
+};
+
+/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324
+ * test vectors. Created using an independent implementation, and tested decoding against paper
+ * authors' code. */
+static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = {
+ {0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}},
+ {0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}},
+ {0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}},
+ {0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}},
+ {0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}},
+ {0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}},
+ {0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}},
+ {0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}},
+ {0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}},
+ {0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}},
+ {0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}},
+ {0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+};
+
+/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324
+ * test vectors. Created using an independent implementation, and tested decoding against the paper
+ * authors' code. */
+static const struct ellswift_decode_test ellswift_decode_tests[] = {
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
+ {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
+ {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
+ {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0},
+ {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1},
+ {{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0},
+ {{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0},
+ {{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1},
+ {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
+ {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
+ {{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0},
+ {{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0},
+ {{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0},
+ {{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0},
+ {{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1},
+ {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
+ {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
+ {{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1},
+ {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
+ {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
+ {{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0},
+ {{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0},
+ {{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0},
+ {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0},
+ {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1},
+ {{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0},
+ {{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1},
+ {{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0},
+ {{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1},
+ {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
+ {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
+ {{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1},
+ {{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0},
+};
+
+/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating,
+ * taken from the BIP324 test vectors. Created using an independent implementation, and tested
+ * against the paper authors' decoding code. */
+static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = {
+ {{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}},
+ {{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}},
+ {{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}},
+ {{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}},
+ {{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}},
+ {{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}},
+ {{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}},
+};
+
+/** This is a hasher for ellswift_xdh which just returns the shared X coordinate.
+ *
+ * This is generally a bad idea as it means changes to the encoding of the
+ * exchanged public keys do not affect the shared secret. However, it's used here
+ * in tests to be able to verify the X coordinate through other means.
+ */
+static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
+ (void)ell_a64;
+ (void)ell_b64;
+ (void)data;
+ memcpy(output, x32, 32);
+ return 1;
+}
+
+void run_ellswift_tests(void) {
+ int i = 0;
+ /* Test vectors. */
+ for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) {
+ const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i];
+ int c;
+ for (c = 0; c < 8; ++c) {
+ secp256k1_fe t;
+ int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c);
+ CHECK(ret == ((testcase->enc_bitmap >> c) & 1));
+ if (ret) {
+ secp256k1_fe x2;
+ CHECK(check_fe_equal(&t, &testcase->encs[c]));
+ secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]);
+ CHECK(check_fe_equal(&testcase->x, &x2));
+ }
+ }
+ }
+ for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) {
+ const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i];
+ secp256k1_pubkey pubkey;
+ secp256k1_ge ge;
+ int ret;
+ ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc);
+ CHECK(ret);
+ ret = secp256k1_pubkey_load(CTX, &ge, &pubkey);
+ CHECK(ret);
+ CHECK(check_fe_equal(&testcase->x, &ge.x));
+ CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y);
+ }
+ for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) {
+ const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i];
+ unsigned char shared_secret[32];
+ int ret;
+ int party = !test->initiating;
+ const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours;
+ const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs;
+ ret = secp256k1_ellswift_xdh(CTX, shared_secret,
+ ell_a64, ell_b64,
+ test->priv_ours,
+ party,
+ secp256k1_ellswift_xdh_hash_function_bip324,
+ NULL);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0);
+ }
+ /* Verify that secp256k1_ellswift_encode + decode roundtrips. */
+ for (i = 0; i < 1000 * COUNT; i++) {
+ unsigned char rnd32[32];
+ unsigned char ell64[64];
+ secp256k1_ge g, g2;
+ secp256k1_pubkey pubkey, pubkey2;
+ /* Generate random public key and random randomizer. */
+ random_group_element_test(&g);
+ secp256k1_pubkey_save(&pubkey, &g);
+ secp256k1_testrand256(rnd32);
+ /* Convert the public key to ElligatorSwift and back. */
+ secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32);
+ secp256k1_ellswift_decode(CTX, &pubkey2, ell64);
+ secp256k1_pubkey_load(CTX, &g2, &pubkey2);
+ /* Compare with original. */
+ ge_equals_ge(&g, &g2);
+ }
+ /* Verify the behavior of secp256k1_ellswift_create */
+ for (i = 0; i < 400 * COUNT; i++) {
+ unsigned char auxrnd32[32], sec32[32];
+ secp256k1_scalar sec;
+ secp256k1_gej res;
+ secp256k1_ge dec;
+ secp256k1_pubkey pub;
+ unsigned char ell64[64];
+ int ret;
+ /* Generate random secret key and random randomizer. */
+ if (i & 1) secp256k1_testrand256_test(auxrnd32);
+ random_scalar_order_test(&sec);
+ secp256k1_scalar_get_b32(sec32, &sec);
+ /* Construct ElligatorSwift-encoded public keys for that key. */
+ ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL);
+ CHECK(ret);
+ /* Decode it, and compare with traditionally-computed public key. */
+ secp256k1_ellswift_decode(CTX, &pub, ell64);
+ secp256k1_pubkey_load(CTX, &dec, &pub);
+ secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
+ ge_equals_gej(&dec, &res);
+ }
+ /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */
+ for (i = 0; i < 800 * COUNT; i++) {
+ unsigned char ell64[64], sec32[32], share32[32];
+ secp256k1_scalar sec;
+ secp256k1_ge dec, res;
+ secp256k1_fe share_x;
+ secp256k1_gej decj, resj;
+ secp256k1_pubkey pub;
+ int ret;
+ /* Generate random secret key. */
+ random_scalar_order_test(&sec);
+ secp256k1_scalar_get_b32(sec32, &sec);
+ /* Generate random ElligatorSwift encoding for the remote key and decode it. */
+ secp256k1_testrand256_test(ell64);
+ secp256k1_testrand256_test(ell64 + 32);
+ secp256k1_ellswift_decode(CTX, &pub, ell64);
+ secp256k1_pubkey_load(CTX, &dec, &pub);
+ secp256k1_gej_set_ge(&decj, &dec);
+ /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we
+ * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works
+ * because the "hasher" function we use here ignores the ell64 arguments. */
+ ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL);
+ CHECK(ret);
+ (void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */
+ secp256k1_fe_verify(&share_x);
+ /* Compute seckey*pubkey directly. */
+ secp256k1_ecmult(&resj, &decj, &sec, NULL);
+ secp256k1_ge_set_gej(&res, &resj);
+ /* Compare. */
+ CHECK(check_fe_equal(&res.x, &share_x));
+ }
+ /* Verify the joint behavior of secp256k1_ellswift_xdh */
+ for (i = 0; i < 200 * COUNT; i++) {
+ unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32];
+ unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32];
+ secp256k1_scalar seca, secb;
+ unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64];
+ unsigned char share32a[32], share32b[32], share32_bad[32];
+ unsigned char prefix64[64];
+ secp256k1_ellswift_xdh_hash_function hash_function;
+ void* data;
+ int ret;
+
+ /* Pick hasher to use. */
+ if ((i % 3) == 0) {
+ hash_function = ellswift_xdh_hash_x32;
+ data = NULL;
+ } else if ((i % 3) == 1) {
+ hash_function = secp256k1_ellswift_xdh_hash_function_bip324;
+ data = NULL;
+ } else {
+ hash_function = secp256k1_ellswift_xdh_hash_function_prefix;
+ secp256k1_testrand256_test(prefix64);
+ secp256k1_testrand256_test(prefix64 + 32);
+ data = prefix64;
+ }
+
+ /* Generate random secret keys and random randomizers. */
+ secp256k1_testrand256_test(auxrnd32a);
+ secp256k1_testrand256_test(auxrnd32b);
+ random_scalar_order_test(&seca);
+ random_scalar_order_test(&secb);
+ secp256k1_scalar_get_b32(sec32a, &seca);
+ secp256k1_scalar_get_b32(sec32b, &secb);
+
+ /* Construct ElligatorSwift-encoded public keys for those keys. */
+ /* For A: */
+ ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a);
+ CHECK(ret);
+ /* For B: */
+ ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b);
+ CHECK(ret);
+
+ /* Compute the shared secret both ways and compare with each other. */
+ /* For A: */
+ ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data);
+ CHECK(ret);
+ /* For B: */
+ ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data);
+ CHECK(ret);
+ /* And compare: */
+ CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0);
+
+ /* Verify that the shared secret doesn't match if other side's public key is incorrect. */
+ /* For A (using a bad public key for B): */
+ memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad));
+ secp256k1_testrand_flip(ell64b_bad, sizeof(ell64b_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
+ CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */
+ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B (using a bad public key for A): */
+ memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad));
+ secp256k1_testrand_flip(ell64a_bad, sizeof(ell64a_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+
+ /* Verify that the shared secret doesn't match if the private key is incorrect. */
+ /* For A: */
+ memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad));
+ secp256k1_testrand_flip(sec32a_bad, sizeof(sec32a_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data);
+ CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B: */
+ memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad));
+ secp256k1_testrand_flip(sec32b_bad, sizeof(sec32b_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data);
+ CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+
+ if (hash_function != ellswift_xdh_hash_x32) {
+ /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */
+ /* For A (changing B's public key): */
+ memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad));
+ secp256k1_testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad));
+ ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad);
+ CHECK(ret);
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B (changing A's public key): */
+ memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad));
+ secp256k1_testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad));
+ ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad);
+ CHECK(ret);
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+
+ /* Verify that swapping sides changes the shared secret. */
+ /* For A (claiming to be B): */
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B (claiming to be A): */
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+ }
+ }
+
+ /* Test hash initializers. */
+ {
+ secp256k1_sha256 sha, sha_optimized;
+ static const unsigned char encode_tag[25] = "secp256k1_ellswift_encode";
+ static const unsigned char create_tag[25] = "secp256k1_ellswift_create";
+ static const unsigned char bip324_tag[26] = "bip324_ellswift_xonly_ecdh";
+
+ /* Check that hash initialized by
+ * secp256k1_ellswift_sha256_init_encode has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag));
+ secp256k1_ellswift_sha256_init_encode(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+
+ /* Check that hash initialized by
+ * secp256k1_ellswift_sha256_init_create has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag));
+ secp256k1_ellswift_sha256_init_create(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+
+ /* Check that hash initialized by
+ * secp256k1_ellswift_sha256_init_bip324 has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag));
+ secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+ }
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/extrakeys/main_impl.h b/src/secp256k1/src/modules/extrakeys/main_impl.h
index e1003052f4..0c7e266777 100644
--- a/src/secp256k1/src/modules/extrakeys/main_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/main_impl.h
@@ -9,6 +9,7 @@
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_extrakeys.h"
+#include "../../util.h"
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
@@ -27,7 +28,7 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p
memset(pubkey, 0, sizeof(*pubkey));
ARG_CHECK(input32 != NULL);
- if (!secp256k1_fe_set_b32(&x, input32)) {
+ if (!secp256k1_fe_set_b32_limit(&x, input32)) {
return 0;
}
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
diff --git a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
index 5ecc90d50f..d3d817a131 100644
--- a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
@@ -47,7 +47,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
/* Compare the xonly_pubkey bytes against the precomputed group. */
- secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]);
+ secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]);
CHECK(secp256k1_fe_equal_var(&fe, &group[i].x));
/* Check the parity against the precomputed group. */
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
index e7906eb62e..76a005e017 100644
--- a/src/secp256k1/src/modules/recovery/main_impl.h
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -98,7 +98,7 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp2
}
secp256k1_scalar_get_b32(brx, sigr);
- r = secp256k1_fe_set_b32(&fx, brx);
+ r = secp256k1_fe_set_b32_limit(&fx, brx);
(void)r;
VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) {
diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h
index cd651591c4..4e7b45a045 100644
--- a/src/secp256k1/src/modules/schnorrsig/main_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h
@@ -232,7 +232,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
ARG_CHECK(msg != NULL || msglen == 0);
ARG_CHECK(pubkey != NULL);
- if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
+ if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) {
return 0;
}
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
index 062005ee63..90337ff03e 100644
--- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
@@ -20,17 +20,6 @@ static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, s
CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0);
}
-/* Tests for the equality of two sha256 structs. This function only produces a
- * correct result if an integer multiple of 64 many bytes have been written
- * into the hash functions. */
-static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
- /* Is buffer fully consumed? */
- CHECK((sha1->bytes & 0x3F) == 0);
-
- CHECK(sha1->bytes == sha2->bytes);
- CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
-}
-
static void run_nonce_function_bip340_tests(void) {
unsigned char tag[13] = "BIP0340/nonce";
unsigned char aux_tag[11] = "BIP0340/aux";
@@ -215,28 +204,36 @@ static void test_schnorrsig_sha256_tagged(void) {
/* Helper function for schnorrsig_bip_vectors
* Signs the message and checks that it's the same as expected_sig. */
-static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
+static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) {
unsigned char sig[64];
secp256k1_keypair keypair;
secp256k1_xonly_pubkey pk, pk_expected;
+ secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
+ extraparams.ndata = (unsigned char*)aux_rand;
+
CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
- CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg32, &keypair, aux_rand));
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
+ if (msglen == 32) {
+ memset(sig, 0, 64);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand));
+ CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
+ }
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized));
CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
- CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk));
}
/* Helper function for schnorrsig_bip_vectors
* Checks that both verify and verify_batch (TODO) return the same value as expected. */
-static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
+static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) {
secp256k1_xonly_pubkey pk;
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized));
- CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
+ CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk));
}
/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
@@ -256,7 +253,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -278,8 +275,8 @@ static void test_schnorrsig_bip_vectors(void) {
0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47,
0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 1 */
@@ -295,7 +292,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -317,8 +314,8 @@ static void test_schnorrsig_bip_vectors(void) {
0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C,
0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 2 */
@@ -334,7 +331,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9,
0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE,
0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC,
0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C,
@@ -356,8 +353,8 @@ static void test_schnorrsig_bip_vectors(void) {
0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E,
0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 3 */
@@ -373,7 +370,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A,
0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -395,8 +392,8 @@ static void test_schnorrsig_bip_vectors(void) {
0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27,
0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 4 */
@@ -422,7 +419,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93,
0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 5 */
@@ -460,7 +457,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E,
0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 7 */
@@ -486,7 +483,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35,
0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 8 */
@@ -512,7 +509,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C,
0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 9 */
@@ -538,7 +535,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC,
0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 10 */
@@ -564,7 +561,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9,
0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 11 */
@@ -590,7 +587,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 12 */
@@ -616,7 +613,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 13 */
@@ -642,7 +639,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 14 */
@@ -656,6 +653,147 @@ static void test_schnorrsig_bip_vectors(void) {
/* No need to check the signature of the test vector as parsing the pubkey already fails */
CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
}
+ {
+ /* Test vector 15 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ /* const unsigned char msg[0] = {}; */
+ const unsigned char sig[64] = {
+ 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB,
+ 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18,
+ 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC,
+ 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF,
+ 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62,
+ 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64,
+ 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27,
+ 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63,
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1);
+ }
+ {
+ /* Test vector 16 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ const unsigned char msg[] = { 0x11 };
+ const unsigned char sig[64] = {
+ 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24,
+ 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A,
+ 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35,
+ 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03,
+ 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD,
+ 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96,
+ 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33,
+ 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF,
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+ }
+ {
+ /* Test vector 17 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ const unsigned char msg[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
+ 0x11,
+ };
+ const unsigned char sig[64] = {
+ 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B,
+ 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B,
+ 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52,
+ 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70,
+ 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8,
+ 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC,
+ 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51,
+ 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5,
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+ }
+ {
+ /* Test vector 18 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ const unsigned char sig[64] = {
+ 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34,
+ 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63,
+ 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F,
+ 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8,
+ 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7,
+ 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23,
+ 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0,
+ 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67,
+ };
+ unsigned char msg[100];
+ memset(msg, 0x99, sizeof(msg));
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+ }
}
/* Nonce function that returns constant 0 */
diff --git a/src/secp256k1/src/precompute_ecmult.c b/src/secp256k1/src/precompute_ecmult.c
index 10aba5b97d..742142cf58 100644
--- a/src/secp256k1/src/precompute_ecmult.c
+++ b/src/secp256k1/src/precompute_ecmult.c
@@ -68,7 +68,6 @@ int main(void) {
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, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult.h\"\n");
fprintf(fp, "#include \"precomputed_ecmult.h\"\n");
diff --git a/src/secp256k1/src/precompute_ecmult_gen.c b/src/secp256k1/src/precompute_ecmult_gen.c
index bfe212fdd2..ce648cb9b0 100644
--- a/src/secp256k1/src/precompute_ecmult_gen.c
+++ b/src/secp256k1/src/precompute_ecmult_gen.c
@@ -33,7 +33,6 @@ int main(int argc, char **argv) {
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, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult_gen.h\"\n");
fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n");
diff --git a/src/secp256k1/src/precomputed_ecmult.c b/src/secp256k1/src/precomputed_ecmult.c
index fbc634ef1b..cbd030ce50 100644
--- a/src/secp256k1/src/precomputed_ecmult.c
+++ b/src/secp256k1/src/precomputed_ecmult.c
@@ -2,7 +2,6 @@
/* 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.
*/
-#include "../include/secp256k1.h"
#include "group.h"
#include "ecmult.h"
#include "precomputed_ecmult.h"
diff --git a/src/secp256k1/src/precomputed_ecmult.h b/src/secp256k1/src/precomputed_ecmult.h
index a4aa83e4ca..17df102967 100644
--- a/src/secp256k1/src/precomputed_ecmult.h
+++ b/src/secp256k1/src/precomputed_ecmult.h
@@ -11,6 +11,7 @@
extern "C" {
#endif
+#include "ecmult.h"
#include "group.h"
#if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 7
diff --git a/src/secp256k1/src/precomputed_ecmult_gen.c b/src/secp256k1/src/precomputed_ecmult_gen.c
index e9d62a1c1b..75ec59c27a 100644
--- a/src/secp256k1/src/precomputed_ecmult_gen.c
+++ b/src/secp256k1/src/precomputed_ecmult_gen.c
@@ -1,6 +1,5 @@
/* This file was automatically generated by precompute_ecmult_gen. */
/* See ecmult_gen_impl.h for details about the contents of this file. */
-#include "../include/secp256k1.h"
#include "group.h"
#include "ecmult_gen.h"
#include "precomputed_ecmult_gen.h"
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 1959dae986..1d14740577 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -10,6 +10,7 @@
#include "checkmem.h"
#include "int128.h"
#include "modinv64_impl.h"
+#include "util.h"
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
@@ -110,8 +111,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
secp256k1_uint128 t;
+ volatile int vflag = flag;
VERIFY_CHECK(bit < 256);
- bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
+ bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
secp256k1_u128_from_u64(&t, r->d[0]);
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
@@ -131,10 +133,10 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
- r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56;
- r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56;
- r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56;
- r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56;
+ r->d[0] = secp256k1_read_be64(&b32[24]);
+ r->d[1] = secp256k1_read_be64(&b32[16]);
+ r->d[2] = secp256k1_read_be64(&b32[8]);
+ r->d[3] = secp256k1_read_be64(&b32[0]);
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
@@ -142,10 +144,10 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3];
- bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2];
- bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1];
- bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
+ secp256k1_write_be64(&bin[0], a->d[3]);
+ secp256k1_write_be64(&bin[8], a->d[2]);
+ secp256k1_write_be64(&bin[16], a->d[1]);
+ secp256k1_write_be64(&bin[24], a->d[0]);
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
@@ -188,7 +190,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
- uint64_t mask = !flag - 1;
+ volatile int vflag = flag;
+ uint64_t mask = -vflag;
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
secp256k1_uint128 t;
secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
@@ -380,7 +383,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"movq %%r10, %q5\n"
/* extract m6 */
"movq %%r8, %q6\n"
- : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
+ : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
: "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index a2555cbbcd..80ef3ef248 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -9,6 +9,7 @@
#include "checkmem.h"
#include "modinv32_impl.h"
+#include "util.h"
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint32_t)0xD0364141UL)
@@ -141,8 +142,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint64_t t;
+ volatile int vflag = flag;
VERIFY_CHECK(bit < 256);
- bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
+ bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
@@ -167,14 +169,14 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
- r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;
- r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;
- r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24;
- r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24;
- r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24;
- r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24;
- r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24;
- r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24;
+ r->d[0] = secp256k1_read_be32(&b32[28]);
+ r->d[1] = secp256k1_read_be32(&b32[24]);
+ r->d[2] = secp256k1_read_be32(&b32[20]);
+ r->d[3] = secp256k1_read_be32(&b32[16]);
+ r->d[4] = secp256k1_read_be32(&b32[12]);
+ r->d[5] = secp256k1_read_be32(&b32[8]);
+ r->d[6] = secp256k1_read_be32(&b32[4]);
+ r->d[7] = secp256k1_read_be32(&b32[0]);
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
@@ -182,14 +184,14 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7];
- bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6];
- bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5];
- bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4];
- bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3];
- bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2];
- bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1];
- bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
+ secp256k1_write_be32(&bin[0], a->d[7]);
+ secp256k1_write_be32(&bin[4], a->d[6]);
+ secp256k1_write_be32(&bin[8], a->d[5]);
+ secp256k1_write_be32(&bin[12], a->d[4]);
+ secp256k1_write_be32(&bin[16], a->d[3]);
+ secp256k1_write_be32(&bin[20], a->d[2]);
+ secp256k1_write_be32(&bin[24], a->d[1]);
+ secp256k1_write_be32(&bin[28], a->d[0]);
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
@@ -241,7 +243,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
- uint32_t mask = !flag - 1;
+ volatile int vflag = flag;
+ uint32_t mask = -vflag;
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
r->d[0] = t & nonzero; t >>= 32;
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
index bfd1139110..428a5deb33 100644
--- a/src/secp256k1/src/scalar_low_impl.h
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -9,6 +9,7 @@
#include "checkmem.h"
#include "scalar.h"
+#include "util.h"
#include <string.h>
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 7af333ca90..4c11e7f0b8 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -247,8 +247,8 @@ static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge,
} else {
/* Otherwise, fall back to 32-byte big endian for X and Y. */
secp256k1_fe x, y;
- secp256k1_fe_set_b32(&x, pubkey->data);
- secp256k1_fe_set_b32(&y, pubkey->data + 32);
+ ARG_CHECK(secp256k1_fe_set_b32_limit(&x, pubkey->data));
+ ARG_CHECK(secp256k1_fe_set_b32_limit(&y, pubkey->data + 32));
secp256k1_ge_set_xy(ge, &x, &y);
}
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
@@ -811,3 +811,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
#ifdef ENABLE_MODULE_SCHNORRSIG
# include "modules/schnorrsig/main_impl.h"
#endif
+
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/main_impl.h"
+#endif
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index d109bb9f8b..721099d039 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -7,6 +7,8 @@
#ifndef SECP256K1_TESTRAND_H
#define SECP256K1_TESTRAND_H
+#include "util.h"
+
/* A non-cryptographic RNG used only for test infrastructure. */
/** Seed the pseudorandom number generator for testing. */
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index e9b9d7ded4..1b7481a53b 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -13,6 +13,7 @@
#include "testrand.h"
#include "hash.h"
+#include "util.h"
static uint64_t secp256k1_test_state[4];
static uint64_t secp256k1_test_rng_integer;
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 7f61f737c6..8ada3f869b 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -10,7 +10,15 @@
#include <time.h>
+#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
+ #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.")
+ #undef USE_EXTERNAL_DEFAULT_CALLBACKS
+#endif
+#if defined(VERIFY) && defined(COVERAGE)
+ #pragma message("Defining VERIFY for tests being built for coverage analysis support is meaningless.")
+#endif
#include "secp256k1.c"
+
#include "../include/secp256k1.h"
#include "../include/secp256k1_preallocated.h"
#include "testrand_impl.h"
@@ -85,7 +93,7 @@ static void random_field_element_test(secp256k1_fe *fe) {
do {
unsigned char b32[32];
secp256k1_testrand256_test(b32);
- if (secp256k1_fe_set_b32(fe, b32)) {
+ if (secp256k1_fe_set_b32_limit(fe, b32)) {
break;
}
} while(1);
@@ -689,6 +697,17 @@ static void run_sha256_counter_tests(void) {
}
}
+/* Tests for the equality of two sha256 structs. This function only produces a
+ * correct result if an integer multiple of 64 many bytes have been written
+ * into the hash functions. This function is used by some module tests. */
+static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
+ /* Is buffer fully consumed? */
+ CHECK((sha1->bytes & 0x3F) == 0);
+
+ CHECK(sha1->bytes == sha2->bytes);
+ CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
+}
+
static 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",
@@ -2221,7 +2240,7 @@ static void scalar_test(void) {
for (i = 0; i < 100; ++i) {
int low;
int shift = 1 + secp256k1_testrand_int(15);
- int expected = r.d[0] % (1 << shift);
+ int expected = r.d[0] % (1ULL << shift);
low = secp256k1_scalar_shr_int(&r, shift);
CHECK(expected == low);
}
@@ -2299,26 +2318,23 @@ static void scalar_test(void) {
{
/* Test multiplicative identity. */
- secp256k1_scalar r1, v1;
- secp256k1_scalar_set_int(&v1,1);
- secp256k1_scalar_mul(&r1, &s1, &v1);
+ secp256k1_scalar r1;
+ secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_one);
CHECK(secp256k1_scalar_eq(&r1, &s1));
}
{
/* Test additive identity. */
- secp256k1_scalar r1, v0;
- secp256k1_scalar_set_int(&v0,0);
- secp256k1_scalar_add(&r1, &s1, &v0);
+ secp256k1_scalar r1;
+ secp256k1_scalar_add(&r1, &s1, &secp256k1_scalar_zero);
CHECK(secp256k1_scalar_eq(&r1, &s1));
}
{
/* Test zero product property. */
- secp256k1_scalar r1, v0;
- secp256k1_scalar_set_int(&v0,0);
- secp256k1_scalar_mul(&r1, &s1, &v0);
- CHECK(secp256k1_scalar_eq(&r1, &v0));
+ secp256k1_scalar r1;
+ secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_zero);
+ CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero));
}
}
@@ -2350,12 +2366,24 @@ static void run_scalar_tests(void) {
}
{
+ /* Check that the scalar constants secp256k1_scalar_zero and
+ secp256k1_scalar_one contain the expected values. */
+ secp256k1_scalar zero, one;
+
+ CHECK(secp256k1_scalar_is_zero(&secp256k1_scalar_zero));
+ secp256k1_scalar_set_int(&zero, 0);
+ CHECK(secp256k1_scalar_eq(&zero, &secp256k1_scalar_zero));
+
+ CHECK(secp256k1_scalar_is_one(&secp256k1_scalar_one));
+ secp256k1_scalar_set_int(&one, 1);
+ CHECK(secp256k1_scalar_eq(&one, &secp256k1_scalar_one));
+ }
+
+ {
/* (-1)+1 should be zero. */
- secp256k1_scalar s, o;
- secp256k1_scalar_set_int(&s, 1);
- CHECK(secp256k1_scalar_is_one(&s));
- secp256k1_scalar_negate(&o, &s);
- secp256k1_scalar_add(&o, &o, &s);
+ secp256k1_scalar o;
+ secp256k1_scalar_negate(&o, &secp256k1_scalar_one);
+ secp256k1_scalar_add(&o, &o, &secp256k1_scalar_one);
CHECK(secp256k1_scalar_is_zero(&o));
secp256k1_scalar_negate(&o, &o);
CHECK(secp256k1_scalar_is_zero(&o));
@@ -2380,7 +2408,6 @@ static void run_scalar_tests(void) {
secp256k1_scalar y;
secp256k1_scalar z;
secp256k1_scalar zz;
- secp256k1_scalar one;
secp256k1_scalar r1;
secp256k1_scalar r2;
secp256k1_scalar zzv;
@@ -2917,7 +2944,6 @@ static void run_scalar_tests(void) {
0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}
};
- secp256k1_scalar_set_int(&one, 1);
for (i = 0; i < 33; i++) {
secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
CHECK(!overflow);
@@ -2940,7 +2966,7 @@ static void run_scalar_tests(void) {
CHECK(secp256k1_scalar_eq(&x, &z));
secp256k1_scalar_mul(&zz, &zz, &y);
CHECK(!secp256k1_scalar_check_overflow(&zz));
- CHECK(secp256k1_scalar_eq(&one, &zz));
+ CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz));
}
}
}
@@ -2952,7 +2978,7 @@ static void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256(bin);
- if (secp256k1_fe_set_b32(x, bin)) {
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
return;
}
} while(1);
@@ -2962,7 +2988,7 @@ static void random_fe_test(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256_test(bin);
- if (secp256k1_fe_set_b32(x, bin)) {
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
return;
}
} while(1);
@@ -3016,7 +3042,7 @@ static void run_field_convert(void) {
unsigned char b322[32];
secp256k1_fe_storage fes2;
/* Check conversions to fe. */
- CHECK(secp256k1_fe_set_b32(&fe2, b32));
+ CHECK(secp256k1_fe_set_b32_limit(&fe2, b32));
CHECK(secp256k1_fe_equal_var(&fe, &fe2));
secp256k1_fe_from_storage(&fe2, &fes);
CHECK(secp256k1_fe_equal_var(&fe, &fe2));
@@ -3027,13 +3053,75 @@ static void run_field_convert(void) {
CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0);
}
+static void run_field_be32_overflow(void) {
+ {
+ static const unsigned char zero_overflow[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F,
+ };
+ static const unsigned char zero[32] = { 0x00 };
+ unsigned char out[32];
+ secp256k1_fe fe;
+ CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0);
+ secp256k1_fe_set_b32_mod(&fe, zero_overflow);
+ CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1);
+ secp256k1_fe_normalize(&fe);
+ CHECK(secp256k1_fe_is_zero(&fe) == 1);
+ secp256k1_fe_get_b32(out, &fe);
+ CHECK(secp256k1_memcmp_var(out, zero, 32) == 0);
+ }
+ {
+ static const unsigned char one_overflow[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30,
+ };
+ static const unsigned char one[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ };
+ unsigned char out[32];
+ secp256k1_fe fe;
+ CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0);
+ secp256k1_fe_set_b32_mod(&fe, one_overflow);
+ secp256k1_fe_normalize(&fe);
+ CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0);
+ secp256k1_fe_get_b32(out, &fe);
+ CHECK(secp256k1_memcmp_var(out, one, 32) == 0);
+ }
+ {
+ static const unsigned char ff_overflow[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ };
+ static const unsigned char ff[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0,
+ };
+ unsigned char out[32];
+ secp256k1_fe fe;
+ const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0);
+ CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0);
+ secp256k1_fe_set_b32_mod(&fe, ff_overflow);
+ secp256k1_fe_normalize(&fe);
+ CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0);
+ secp256k1_fe_get_b32(out, &fe);
+ CHECK(secp256k1_memcmp_var(out, ff, 32) == 0);
+ }
+}
+
/* Returns true if two field elements have the same representation. */
static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
int ret = 1;
-#ifdef VERIFY
- ret &= (a->magnitude == b->magnitude);
- ret &= (a->normalized == b->normalized);
-#endif
/* Compare the struct member that holds the limbs. */
ret &= (secp256k1_memcmp_var(a->n, b->n, sizeof(a->n)) == 0);
return ret;
@@ -3121,16 +3209,22 @@ static void run_field_misc(void) {
q = x;
secp256k1_fe_cmov(&x, &z, 0);
#ifdef VERIFY
- CHECK(x.normalized && x.magnitude == 1);
+ CHECK(!x.normalized);
+ CHECK((x.magnitude == q.magnitude) || (x.magnitude == z.magnitude));
+ CHECK((x.magnitude >= q.magnitude) && (x.magnitude >= z.magnitude));
#endif
+ x = q;
secp256k1_fe_cmov(&x, &x, 1);
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);
+ CHECK(!q.normalized);
+ CHECK((q.magnitude == x.magnitude) || (q.magnitude == z.magnitude));
+ CHECK((q.magnitude >= x.magnitude) && (q.magnitude >= z.magnitude));
#endif
CHECK(fe_identical(&q, &z));
+ q = z;
secp256k1_fe_normalize_var(&x);
secp256k1_fe_normalize_var(&z);
CHECK(!secp256k1_fe_equal_var(&x, &z));
@@ -3144,7 +3238,7 @@ static void run_field_misc(void) {
secp256k1_fe_normalize_var(&q);
secp256k1_fe_cmov(&q, &z, (j&1));
#ifdef VERIFY
- CHECK((q.normalized != (j&1)) && q.magnitude == ((j&1) ? z.magnitude : 1));
+ CHECK(!q.normalized && q.magnitude == z.magnitude);
#endif
}
secp256k1_fe_normalize_var(&z);
@@ -3605,7 +3699,7 @@ static void run_inverse_tests(void)
b32[31] = i & 0xff;
b32[30] = (i >> 8) & 0xff;
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
- secp256k1_fe_set_b32(&x_fe, b32);
+ secp256k1_fe_set_b32_mod(&x_fe, b32);
for (var = 0; var <= 1; ++var) {
test_inverse_scalar(NULL, &x_scalar, var);
test_inverse_field(NULL, &x_fe, var);
@@ -3622,7 +3716,7 @@ static void run_inverse_tests(void)
for (i = 0; i < 64 * COUNT; ++i) {
(testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32);
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
- secp256k1_fe_set_b32(&x_fe, b32);
+ secp256k1_fe_set_b32_mod(&x_fe, b32);
for (var = 0; var <= 1; ++var) {
test_inverse_scalar(NULL, &x_scalar, var);
test_inverse_field(NULL, &x_fe, var);
@@ -3692,7 +3786,7 @@ static void test_ge(void) {
*/
secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
- secp256k1_fe zf;
+ secp256k1_fe zf, r;
secp256k1_fe zfi2, zfi3;
secp256k1_gej_set_infinity(&gej[0]);
@@ -3734,6 +3828,11 @@ static void test_ge(void) {
secp256k1_fe_sqr(&zfi2, &zfi3);
secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);
+ /* Generate random r */
+ do {
+ random_field_element_test(&r);
+ } while(secp256k1_fe_is_zero(&r));
+
for (i1 = 0; i1 < 1 + 4 * runs; i1++) {
int i2;
for (i2 = 0; i2 < 1 + 4 * runs; i2++) {
@@ -3846,6 +3945,29 @@ static void test_ge(void) {
free(ge_set_all);
}
+ /* Test that all elements have X coordinates on the curve. */
+ for (i = 1; i < 4 * runs + 1; i++) {
+ secp256k1_fe n;
+ CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x));
+ /* And the same holds after random rescaling. */
+ secp256k1_fe_mul(&n, &zf, &ge[i].x);
+ CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf));
+ }
+
+ /* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */
+ {
+ secp256k1_fe n;
+ secp256k1_ge q;
+ int ret_on_curve, ret_frac_on_curve, ret_set_xo;
+ secp256k1_fe_mul(&n, &zf, &r);
+ ret_on_curve = secp256k1_ge_x_on_curve_var(&r);
+ ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf);
+ ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0);
+ CHECK(ret_on_curve == ret_frac_on_curve);
+ CHECK(ret_on_curve == ret_set_xo);
+ if (ret_set_xo) CHECK(secp256k1_fe_equal_var(&r, &q.x));
+ }
+
/* Test batch gej -> ge conversion with many infinities. */
for (i = 0; i < 4 * runs + 1; i++) {
int odd;
@@ -4338,9 +4460,9 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) {
secp256k1_ecmult(&p2j, &pj, &n2, &zero);
secp256k1_ecmult(&ptj, &pj, target, &zero);
} else {
- secp256k1_ecmult_const(&p1j, &p, &n1, 256);
- secp256k1_ecmult_const(&p2j, &p, &n2, 256);
- secp256k1_ecmult_const(&ptj, &p, target, 256);
+ secp256k1_ecmult_const(&p1j, &p, &n1);
+ secp256k1_ecmult_const(&p2j, &p, &n2);
+ secp256k1_ecmult_const(&ptj, &p, target);
}
/* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */
@@ -4403,7 +4525,7 @@ static void ecmult_const_random_mult(void) {
0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
);
secp256k1_gej b;
- secp256k1_ecmult_const(&b, &a, &xn, 256);
+ secp256k1_ecmult_const(&b, &a, &xn);
CHECK(secp256k1_ge_is_valid_var(&a));
ge_equals_gej(&expected_b, &b);
@@ -4419,12 +4541,12 @@ static void ecmult_const_commutativity(void) {
random_scalar_order_test(&a);
random_scalar_order_test(&b);
- secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256);
- secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256);
+ secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
+ secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
- secp256k1_ecmult_const(&res1, &mid1, &b, 256);
- secp256k1_ecmult_const(&res2, &mid2, &a, 256);
+ secp256k1_ecmult_const(&res1, &mid1, &b);
+ secp256k1_ecmult_const(&res2, &mid2, &a);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
ge_equals_ge(&mid1, &mid2);
@@ -4440,13 +4562,13 @@ static void ecmult_const_mult_zero_one(void) {
secp256k1_scalar_negate(&negone, &one);
random_group_element_test(&point);
- secp256k1_ecmult_const(&res1, &point, &zero, 3);
+ secp256k1_ecmult_const(&res1, &point, &zero);
secp256k1_ge_set_gej(&res2, &res1);
CHECK(secp256k1_ge_is_infinity(&res2));
- secp256k1_ecmult_const(&res1, &point, &one, 2);
+ secp256k1_ecmult_const(&res1, &point, &one);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
- secp256k1_ecmult_const(&res1, &point, &negone, 256);
+ secp256k1_ecmult_const(&res1, &point, &negone);
secp256k1_gej_neg(&res1, &res1);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
@@ -4476,7 +4598,7 @@ static void ecmult_const_mult_xonly(void) {
n = base.x;
}
/* Perform x-only multiplication. */
- res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, 256, i & 2);
+ res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2);
CHECK(res);
/* Perform normal multiplication. */
secp256k1_gej_set_ge(&basej, &base);
@@ -4498,7 +4620,7 @@ static void ecmult_const_mult_xonly(void) {
random_field_element_test(&x);
secp256k1_fe_sqr(&c, &x);
secp256k1_fe_mul(&c, &c, &x);
- secp256k1_fe_add(&c, &secp256k1_fe_const_b);
+ secp256k1_fe_add_int(&c, SECP256K1_B);
} while (secp256k1_fe_is_square_var(&c));
/* If i is odd, n=d*x for random non-zero d. */
if (i & 1) {
@@ -4509,7 +4631,7 @@ static void ecmult_const_mult_xonly(void) {
} else {
n = x;
}
- res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 256, 0);
+ res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0);
CHECK(res == 0);
}
}
@@ -4534,7 +4656,7 @@ static void ecmult_const_chain_multiply(void) {
for (i = 0; i < 100; ++i) {
secp256k1_ge tmp;
secp256k1_ge_set_gej(&tmp, &point);
- secp256k1_ecmult_const(&point, &tmp, &scalar, 256);
+ secp256k1_ecmult_const(&point, &tmp, &scalar);
}
secp256k1_ge_set_gej(&res, &point);
ge_equals_gej(&res, &expected_point);
@@ -4570,7 +4692,6 @@ static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, s
static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) {
int ncount;
- secp256k1_scalar szero;
secp256k1_scalar sc[32];
secp256k1_ge pt[32];
secp256k1_gej r;
@@ -4579,7 +4700,6 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
data.sc = sc;
data.pt = pt;
- secp256k1_scalar_set_int(&szero, 0);
/* No points to multiply */
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
@@ -4597,21 +4717,21 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
pt[1] = secp256k1_ge_const_g;
/* only G scalar */
- secp256k1_ecmult(&r2, &ptgj, &szero, &sc[0]);
+ secp256k1_ecmult(&r2, &ptgj, &secp256k1_scalar_zero, &sc[0]);
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 1-point */
- secp256k1_ecmult(&r2, &ptgj, &sc[0], &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
+ secp256k1_ecmult(&r2, &ptgj, &sc[0], &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* Try to multiply 1 point, but callback returns false */
- CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
+ CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_false_callback, &data, 1));
/* 2-point */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 2-point with G scalar */
@@ -4631,7 +4751,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
random_scalar_order(&sc[i]);
secp256k1_ge_set_infinity(&pt[i]);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4641,7 +4761,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
pt[i] = ptg;
secp256k1_scalar_set_int(&sc[i], 0);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4654,7 +4774,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
pt[2 * i + 1] = ptg;
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
random_scalar_order(&sc[0]);
@@ -4667,7 +4787,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4682,7 +4802,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_scalar_negate(&sc[i], &sc[i]);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 32));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4700,8 +4820,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL);
}
- secp256k1_ecmult(&r2, &r, &sc[0], &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_ecmult(&r2, &r, &sc[0], &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
@@ -4721,8 +4841,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
}
secp256k1_gej_set_ge(&p0j, &pt[0]);
- secp256k1_ecmult(&r2, &p0j, &rs, &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_ecmult(&r2, &p0j, &rs, &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
@@ -4733,13 +4853,13 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
}
secp256k1_scalar_clear(&sc[0]);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20));
secp256k1_scalar_clear(&sc[1]);
secp256k1_scalar_clear(&sc[2]);
secp256k1_scalar_clear(&sc[3]);
secp256k1_scalar_clear(&sc[4]);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 6));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5));
CHECK(secp256k1_gej_is_infinity(&r));
/* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */
@@ -4763,8 +4883,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_scalar_set_int(&t1, (t1i + 1) / 2);
secp256k1_scalar_cond_negate(&t1, t1i & 1);
- secp256k1_ecmult(&t0p, &ptgj, &t0, &szero);
- secp256k1_ecmult(&t1p, &ptgj, &t1, &szero);
+ secp256k1_ecmult(&t0p, &ptgj, &t0, &secp256k1_scalar_zero);
+ secp256k1_ecmult(&t1p, &ptgj, &t1, &secp256k1_scalar_zero);
for(s0i = 0; s0i < TOP; s0i++) {
for(s1i = 0; s1i < TOP; s1i++) {
@@ -4783,8 +4903,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_scalar_mul(&tmp2, &t1, &sc[1]);
secp256k1_scalar_add(&tmp1, &tmp1, &tmp2);
- secp256k1_ecmult(&expected, &ptgj, &tmp1, &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
+ secp256k1_ecmult(&expected, &ptgj, &tmp1, &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2));
CHECK(secp256k1_gej_eq_var(&actual, &expected));
}
}
@@ -4960,7 +5080,6 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) {
}
static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
- secp256k1_scalar szero;
secp256k1_scalar sc;
secp256k1_ge pt;
secp256k1_gej r;
@@ -4971,11 +5090,10 @@ static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_mu
random_scalar_order(&sc);
data.sc = &sc;
data.pt = &pt;
- secp256k1_scalar_set_int(&szero, 0);
/* Try to multiply 1 point, but scratch space is empty.*/
scratch_empty = secp256k1_scratch_create(&CTX->error_callback, 0);
- CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
+ CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(&CTX->error_callback, scratch_empty);
}
@@ -5083,7 +5201,6 @@ static void test_ecmult_multi_batch_size_helper(void) {
static void test_ecmult_multi_batching(void) {
static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD;
secp256k1_scalar scG;
- secp256k1_scalar szero;
secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points);
secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points);
secp256k1_gej r;
@@ -5093,11 +5210,10 @@ static void test_ecmult_multi_batching(void) {
secp256k1_scratch *scratch;
secp256k1_gej_set_infinity(&r2);
- secp256k1_scalar_set_int(&szero, 0);
/* Get random scalars and group elements and compute result */
random_scalar_order(&scG);
- secp256k1_ecmult(&r2, &r2, &szero, &scG);
+ secp256k1_ecmult(&r2, &r2, &secp256k1_scalar_zero, &scG);
for(i = 0; i < n_points; i++) {
secp256k1_ge ptg;
secp256k1_gej ptgj;
@@ -5432,7 +5548,7 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar
secp256k1_ecmult(&rj3, &infj, &zero, x);
secp256k1_ecmult_multi_var(NULL, scratch, &rj4, x, NULL, NULL, 0);
secp256k1_ecmult_multi_var(NULL, scratch, &rj5, &zero, test_ecmult_accumulate_cb, (void*)x, 1);
- secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x, 256);
+ secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x);
secp256k1_ge_set_gej_var(&r, &rj1);
ge_equals_gej(&r, &rj2);
ge_equals_gej(&r, &rj3);
@@ -7423,6 +7539,10 @@ static void run_ecdsa_wycheproof(void) {
# include "modules/schnorrsig/tests_impl.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/tests_impl.h"
+#endif
+
static void run_secp256k1_memczero_test(void) {
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
unsigned char buf2[sizeof(buf1)];
@@ -7439,16 +7559,31 @@ static void run_secp256k1_memczero_test(void) {
}
static 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_;
+ {
+ 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_);
+ }
+
+ {
+ const uint64_t x = 0xCAFE0123BEEF4567;
+ const unsigned char x_be[8] = {0xCA, 0xFE, 0x01, 0x23, 0xBE, 0xEF, 0x45, 0x67};
+ unsigned char buf[8];
+ uint64_t x_;
- secp256k1_write_be32(buf, x);
- CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
+ secp256k1_write_be64(buf, x);
+ CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
- x_ = secp256k1_read_be32(buf);
- CHECK(x == x_);
+ x_ = secp256k1_read_be64(buf);
+ CHECK(x == x_);
+ }
}
static void int_cmov_test(void) {
@@ -7487,23 +7622,23 @@ static void fe_cmov_test(void) {
secp256k1_fe a = zero;
secp256k1_fe_cmov(&r, &a, 0);
- CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &max));
r = zero; a = max;
secp256k1_fe_cmov(&r, &a, 1);
- CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &max));
a = zero;
secp256k1_fe_cmov(&r, &a, 1);
- CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &zero));
a = one;
secp256k1_fe_cmov(&r, &a, 1);
- CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &one));
r = one; a = zero;
secp256k1_fe_cmov(&r, &a, 0);
- CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &one));
}
static void fe_storage_cmov_test(void) {
@@ -7693,6 +7828,7 @@ int main(int argc, char **argv) {
run_field_half();
run_field_misc();
run_field_convert();
+ run_field_be32_overflow();
run_fe_mul();
run_sqr();
run_sqrt();
@@ -7754,6 +7890,10 @@ int main(int argc, char **argv) {
run_schnorrsig_tests();
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ run_ellswift_tests();
+#endif
+
/* util tests */
run_secp256k1_memczero_test();
run_secp256k1_byteorder_tests();
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index 63b6ef03af..d35acdd58e 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -13,13 +13,19 @@
#define EXHAUSTIVE_TEST_ORDER 13
#endif
+#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
+ #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.")
+ #undef USE_EXTERNAL_DEFAULT_CALLBACKS
+#endif
#include "secp256k1.c"
+
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "group.h"
#include "testrand_impl.h"
#include "ecmult_compute_table_impl.h"
#include "ecmult_gen_compute_table_impl.h"
+#include "util.h"
static int count = 2;
@@ -54,7 +60,7 @@ static void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256(bin);
- if (secp256k1_fe_set_b32(x, bin)) {
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
return;
}
} while(1);
@@ -192,7 +198,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
}
for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) {
- for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
+ for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
int ret;
secp256k1_gej tmp;
secp256k1_fe xn, xd, tmpf;
@@ -203,19 +209,19 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
secp256k1_scalar_set_int(&ng, j);
/* Test secp256k1_ecmult_const. */
- secp256k1_ecmult_const(&tmp, &group[i], &ng, 256);
+ secp256k1_ecmult_const(&tmp, &group[i], &ng);
ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp);
- if (j != 0) {
+ if (i != 0 && j != 0) {
/* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */
- ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 256, 0);
+ ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0);
CHECK(ret);
CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
/* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */
random_fe_non_zero(&xd);
secp256k1_fe_mul(&xn, &xd, &group[i].x);
- ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 256, 0);
+ ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0);
CHECK(ret);
CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index e75c5ad552..e2ee8a8f19 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -7,6 +7,8 @@
#ifndef SECP256K1_UTIL_H
#define SECP256K1_UTIL_H
+#include "../include/secp256k1.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
@@ -17,6 +19,38 @@
#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x
#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x))
+/* Debug helper for printing arrays of unsigned char. */
+#define PRINT_BUF(buf, len) do { \
+ printf("%s[%lu] = ", #buf, (unsigned long)len); \
+ print_buf_plain(buf, len); \
+} while(0)
+
+static void print_buf_plain(const unsigned char *buf, size_t len) {
+ size_t i;
+ printf("{");
+ for (i = 0; i < len; i++) {
+ if (i % 8 == 0) {
+ printf("\n ");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X,", buf[i]);
+ }
+ printf("\n}\n");
+}
+
+# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if SECP256K1_GNUC_PREREQ(2,7)
+# define SECP256K1_INLINE __inline__
+# elif (defined(_MSC_VER))
+# define SECP256K1_INLINE __inline
+# else
+# define SECP256K1_INLINE
+# endif
+# else
+# define SECP256K1_INLINE inline
+# endif
+
typedef struct {
void (*fn)(const char *text, void* data);
const void* data;
@@ -319,4 +353,28 @@ SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x)
p[0] = x >> 24;
}
+/* Read a uint64_t in big endian */
+SECP256K1_INLINE static uint64_t secp256k1_read_be64(const unsigned char* p) {
+ return (uint64_t)p[0] << 56 |
+ (uint64_t)p[1] << 48 |
+ (uint64_t)p[2] << 40 |
+ (uint64_t)p[3] << 32 |
+ (uint64_t)p[4] << 24 |
+ (uint64_t)p[5] << 16 |
+ (uint64_t)p[6] << 8 |
+ (uint64_t)p[7];
+}
+
+/* Write a uint64_t in big endian */
+SECP256K1_INLINE static void secp256k1_write_be64(unsigned char* p, uint64_t x) {
+ p[7] = x;
+ p[6] = x >> 8;
+ p[5] = x >> 16;
+ p[4] = x >> 24;
+ p[3] = x >> 32;
+ p[2] = x >> 40;
+ p[1] = x >> 48;
+ p[0] = x >> 56;
+}
+
#endif /* SECP256K1_UTIL_H */
diff --git a/src/secp256k1/tools/tests_wycheproof_generate.py b/src/secp256k1/tools/tests_wycheproof_generate.py
index 333f6fbef0..b26dfa89d6 100755
--- a/src/secp256k1/tools/tests_wycheproof_generate.py
+++ b/src/secp256k1/tools/tests_wycheproof_generate.py
@@ -7,8 +7,6 @@ Generate a C file with ECDSA testvectors from the Wycheproof project.
'''
import json
-import hashlib
-import urllib.request
import sys
filename_input = sys.argv[1]
@@ -19,7 +17,8 @@ with open(filename_input) as f:
num_groups = len(doc['testGroups'])
def to_c_array(x):
- if x == "": return ""
+ if x == "":
+ return ""
s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2]))
return "0x" + s
@@ -43,18 +42,23 @@ for i in range(num_groups):
sig_size = len(test_vector['sig']) // 2
msg_size = len(test_vector['msg']) // 2
- if test_vector['result'] == "invalid": expected_verify = 0
- elif test_vector['result'] == "valid": expected_verify = 1
- else: raise ValueError("invalid result field")
+ if test_vector['result'] == "invalid":
+ expected_verify = 0
+ elif test_vector['result'] == "valid":
+ expected_verify = 1
+ else:
+ raise ValueError("invalid result field")
- if num_vectors != 0 and sig_size != 0: signatures += ",\n "
+ if num_vectors != 0 and sig_size != 0:
+ signatures += ",\n "
new_msg = False
msg = to_c_array(test_vector['msg'])
msg_offset = offset_msg_running
# check for repeated msg
- if msg not in cache_msgs.keys():
- if num_vectors != 0 and msg_size != 0: messages += ",\n "
+ if msg not in cache_msgs:
+ if num_vectors != 0 and msg_size != 0:
+ messages += ",\n "
cache_msgs[msg] = offset_msg_running
messages += msg
new_msg = True
@@ -65,8 +69,9 @@ for i in range(num_groups):
pk = to_c_array(public_key['uncompressed'])
pk_offset = offset_pk_running
# check for repeated pk
- if pk not in cache_public_keys.keys():
- if num_vectors != 0: public_keys += ",\n "
+ if pk not in cache_public_keys:
+ if num_vectors != 0:
+ public_keys += ",\n "
cache_public_keys[pk] = offset_pk_running
public_keys += pk
new_pk = True
@@ -76,15 +81,11 @@ for i in range(num_groups):
signatures += to_c_array(test_vector['sig'])
out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n"
- out += " {" + "{0}, {1}, {2}, {3}, {4}, {5}".format(
- pk_offset,
- msg_offset,
- msg_size,
- offset_sig,
- sig_size,
- expected_verify) + " },\n"
- if new_msg: offset_msg_running += msg_size
- if new_pk: offset_pk_running += 65
+ out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n"
+ if new_msg:
+ offset_msg_running += msg_size
+ if new_pk:
+ offset_pk_running += 65
offset_sig += sig_size
num_vectors += 1
@@ -101,7 +102,7 @@ typedef struct {
print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */")
-print("#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({})".format(num_vectors))
+print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})")
print(struct_definition)
diff --git a/src/span.h b/src/span.h
index 4692eca7fb..c98784aee4 100644
--- a/src/span.h
+++ b/src/span.h
@@ -274,6 +274,7 @@ Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
// Helper functions to safely cast to unsigned char pointers.
inline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }
inline unsigned char* UCharCast(unsigned char* c) { return c; }
+inline unsigned char* UCharCast(std::byte* c) { return (unsigned char*)c; }
inline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }
inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index a0918bf463..b2076bea07 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -32,9 +32,9 @@ struct secure_allocator : public std::allocator<T> {
{
}
~secure_allocator() noexcept {}
- template <typename _Other>
+ template <typename Other>
struct rebind {
- typedef secure_allocator<_Other> other;
+ typedef secure_allocator<Other> other;
};
T* allocate(std::size_t n, const void* hint = nullptr)
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 795eea3bc0..2dc644c242 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -27,9 +27,9 @@ struct zero_after_free_allocator : public std::allocator<T> {
{
}
~zero_after_free_allocator() noexcept {}
- template <typename _Other>
+ template <typename Other>
struct rebind {
- typedef zero_after_free_allocator<_Other> other;
+ typedef zero_after_free_allocator<Other> other;
};
void deallocate(T* p, std::size_t n)
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index 3eab2e20c0..25ea547435 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -15,13 +15,17 @@
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <util/chaintype.h>
#include <util/strencodings.h>
+#include <array>
#include <cassert>
+#include <cstddef>
#include <cstdint>
#include <numeric>
+#include <optional>
#include <string>
#include <vector>
@@ -303,3 +307,79 @@ FUZZ_TARGET_INIT(key, initialize_key)
}
}
}
+
+FUZZ_TARGET_INIT(ellswift_roundtrip, initialize_key)
+{
+ FuzzedDataProvider fdp{buffer.data(), buffer.size()};
+
+ auto key_bytes = fdp.ConsumeBytes<uint8_t>(32);
+ key_bytes.resize(32);
+ CKey key;
+ key.Set(key_bytes.begin(), key_bytes.end(), true);
+ if (!key.IsValid()) return;
+
+ auto ent32 = fdp.ConsumeBytes<std::byte>(32);
+ ent32.resize(32);
+
+ auto encoded_ellswift = key.EllSwiftCreate(ent32);
+ auto decoded_pubkey = encoded_ellswift.Decode();
+
+ assert(key.VerifyPubKey(decoded_pubkey));
+}
+
+FUZZ_TARGET_INIT(bip324_ecdh, initialize_key)
+{
+ FuzzedDataProvider fdp{buffer.data(), buffer.size()};
+
+ // We generate private key, k1.
+ auto rnd32 = fdp.ConsumeBytes<uint8_t>(32);
+ rnd32.resize(32);
+ CKey k1;
+ k1.Set(rnd32.begin(), rnd32.end(), true);
+ if (!k1.IsValid()) return;
+
+ // They generate private key, k2.
+ rnd32 = fdp.ConsumeBytes<uint8_t>(32);
+ rnd32.resize(32);
+ CKey k2;
+ k2.Set(rnd32.begin(), rnd32.end(), true);
+ if (!k2.IsValid()) return;
+
+ // We construct an ellswift encoding for our key, k1_ellswift.
+ auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
+ ent32_1.resize(32);
+ auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
+
+ // They construct an ellswift encoding for their key, k2_ellswift.
+ auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
+ ent32_2.resize(32);
+ auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
+
+ // They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
+ auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
+ ent32_2_bad.resize(32);
+ auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
+ assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
+
+ // Determine who is who.
+ bool initiating = fdp.ConsumeBool();
+
+ // We compute our shared secret using our key and their public key.
+ auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
+ // They compute their shared secret using their key and our public key.
+ auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
+ // Those must match, as everyone is behaving correctly.
+ assert(ecdh_secret_1 == ecdh_secret_2);
+
+ if (k1_ellswift != k2_ellswift) {
+ // Unless the two keys are exactly identical, acting as the wrong party breaks things.
+ auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
+ assert(ecdh_secret_bad != ecdh_secret_1);
+ }
+
+ if (k2_ellswift_bad != k2_ellswift) {
+ // Unless both encodings created by them are identical, using the second one breaks things.
+ auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
+ assert(ecdh_secret_bad != ecdh_secret_1);
+ }
+}
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 116fbd9015..aa3cfe81df 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -31,7 +31,7 @@ void initialize_policy_estimator()
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
+ CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
fuzzed_data_provider,
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 7c3289cd26..3df40197d8 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -28,7 +28,7 @@ FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()};
// Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
- static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
+ static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES};
if (block_policy_estimator.Read(fuzzed_auto_file)) {
block_policy_estimator.Write(fuzzed_auto_file);
}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 7035c53d13..c561675d1a 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -101,7 +101,14 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)AreInputsStandard(tx, coins_view_cache);
(void)IsWitnessStandard(tx, coins_view_cache);
- UniValue u(UniValue::VOBJ);
- TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u);
- TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u);
+ if (tx.GetTotalSize() < 250'000) { // Avoid high memory usage (with msan) due to json encoding
+ {
+ UniValue u{UniValue::VOBJ};
+ TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u);
+ }
+ {
+ UniValue u{UniValue::VOBJ};
+ TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u);
+ }
+ }
}
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 8f11bf5db2..86a8d17a76 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -344,4 +344,24 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
}
}
+BOOST_AUTO_TEST_CASE(key_ellswift)
+{
+ for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
+ CKey key = DecodeSecret(secret);
+ BOOST_CHECK(key.IsValid());
+
+ uint256 ent32 = InsecureRand256();
+ auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
+
+ CPubKey decoded_pubkey = ellswift.Decode();
+ if (!key.IsCompressed()) {
+ // The decoding constructor returns a compressed pubkey. If the
+ // original was uncompressed, we must decompress the decoded one
+ // to compare.
+ decoded_pubkey.Decompress();
+ }
+ BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp
index beb9398c74..2699d316da 100644
--- a/src/test/logging_tests.cpp
+++ b/src/test/logging_tests.cpp
@@ -200,7 +200,9 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
const char* argv_test[] = {"bitcoind", "-loglevel=debug"};
std::string err;
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
- init::SetLoggingLevel(args);
+
+ auto result = init::SetLoggingLevel(args);
+ BOOST_REQUIRE(result);
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
}
@@ -212,7 +214,9 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
const char* argv_test[] = {"bitcoind", "-loglevel=net:trace"};
std::string err;
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
- init::SetLoggingLevel(args);
+
+ auto result = init::SetLoggingLevel(args);
+ BOOST_REQUIRE(result);
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::DEFAULT_LOG_LEVEL);
const auto& category_levels{LogInstance().CategoryLevels()};
@@ -229,7 +233,9 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
const char* argv_test[] = {"bitcoind", "-loglevel=debug", "-loglevel=net:trace", "-loglevel=http:info"};
std::string err;
BOOST_REQUIRE(args.ParseParameters(4, argv_test, err));
- init::SetLoggingLevel(args);
+
+ auto result = init::SetLoggingLevel(args);
+ BOOST_REQUIRE(result);
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
const auto& category_levels{LogInstance().CategoryLevels()};
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index c24921bf9b..eb11df0497 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -35,7 +35,7 @@ inline std::ostream& operator<<(std::ostream& os, const common::SettingsValue& v
inline std::ostream& operator<<(std::ostream& os, const std::pair<std::string, common::SettingsValue>& kv)
{
common::SettingsValue out(common::SettingsValue::VOBJ);
- out.__pushKV(kv.first, kv.second);
+ out.pushKVEnd(kv.first, kv.second);
os << out.write();
return os;
}
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 483404779e..93a60db832 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -179,7 +179,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); });
GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
- m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args));
+ m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
m_cache_sizes = CalculateCacheSizes(m_args);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 1286eba035..845fbdb66e 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -370,8 +370,8 @@ void CTxMemPoolEntry::UpdateDescendantState(int32_t modifySize, CAmount modifyFe
nSizeWithDescendants += modifySize;
assert(nSizeWithDescendants > 0);
nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, modifyFee);
- nCountWithDescendants += uint64_t(modifyCount);
- assert(int64_t(nCountWithDescendants) > 0);
+ m_count_with_descendants += modifyCount;
+ assert(m_count_with_descendants > 0);
}
void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
@@ -379,8 +379,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee,
nSizeWithAncestors += modifySize;
assert(nSizeWithAncestors > 0);
nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, modifyFee);
- nCountWithAncestors += uint64_t(modifyCount);
- assert(int64_t(nCountWithAncestors) > 0);
+ m_count_with_ancestors += modifyCount;
+ assert(m_count_with_ancestors > 0);
nSigOpCostWithAncestors += modifySigOps;
assert(int(nSigOpCostWithAncestors) >= 0);
}
diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp
index 19f9fae998..af86baa8ac 100644
--- a/src/txorphanage.cpp
+++ b/src/txorphanage.cpp
@@ -55,10 +55,10 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
int TxOrphanage::EraseTx(const uint256& txid)
{
LOCK(m_mutex);
- return _EraseTx(txid);
+ return EraseTxNoLock(txid);
}
-int TxOrphanage::_EraseTx(const uint256& txid)
+int TxOrphanage::EraseTxNoLock(const uint256& txid)
{
AssertLockHeld(m_mutex);
std::map<uint256, OrphanTx>::iterator it = m_orphans.find(txid);
@@ -103,7 +103,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
std::map<uint256, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
- nErased += _EraseTx(maybeErase->second.tx->GetHash());
+ nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
}
}
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
@@ -125,7 +125,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
std::map<uint256, OrphanTx>::iterator maybeErase = iter++;
if (maybeErase->second.nTimeExpire <= nNow) {
- nErased += _EraseTx(maybeErase->second.tx->GetHash());
+ nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
} else {
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
}
@@ -139,7 +139,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
// Evict a random orphan:
size_t randompos = rng.randrange(m_orphan_list.size());
- _EraseTx(m_orphan_list[randompos]->first);
+ EraseTxNoLock(m_orphan_list[randompos]->first);
++nEvicted;
}
if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
@@ -231,7 +231,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
if (vOrphanErase.size()) {
int nErased = 0;
for (const uint256& orphanHash : vOrphanErase) {
- nErased += _EraseTx(orphanHash);
+ nErased += EraseTxNoLock(orphanHash);
}
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
diff --git a/src/txorphanage.h b/src/txorphanage.h
index 45276c6c98..a4705bf382 100644
--- a/src/txorphanage.h
+++ b/src/txorphanage.h
@@ -99,7 +99,7 @@ protected:
std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(m_mutex);
/** Erase an orphan by txid */
- int _EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
+ int EraseTxNoLock(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
};
#endif // BITCOIN_TXORPHANAGE_H
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 004135ef97..94f80f9c27 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -87,7 +87,7 @@ public:
template <class It>
void push_backV(It first, It last);
- void __pushKV(std::string key, UniValue val);
+ void pushKVEnd(std::string key, UniValue val);
void pushKV(std::string key, UniValue val);
void pushKVs(UniValue obj);
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index c3d19caae0..656d2e8203 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -115,7 +115,7 @@ void UniValue::push_backV(const std::vector<UniValue>& vec)
values.insert(values.end(), vec.begin(), vec.end());
}
-void UniValue::__pushKV(std::string key, UniValue val)
+void UniValue::pushKVEnd(std::string key, UniValue val)
{
checkType(VOBJ);
@@ -131,7 +131,7 @@ void UniValue::pushKV(std::string key, UniValue val)
if (findKey(key, idx))
values[idx] = std::move(val);
else
- __pushKV(std::move(key), std::move(val));
+ pushKVEnd(std::move(key), std::move(val));
}
void UniValue::pushKVs(UniValue obj)
@@ -140,7 +140,7 @@ void UniValue::pushKVs(UniValue obj)
obj.checkType(VOBJ);
for (size_t i = 0; i < obj.keys.size(); i++)
- __pushKV(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
+ pushKVEnd(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
}
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index 5fb973c67b..8b90448b36 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -86,7 +86,7 @@ void univalue_push_throw()
UniValue j;
BOOST_CHECK_THROW(j.push_back(1), std::runtime_error);
BOOST_CHECK_THROW(j.push_backV({1}), std::runtime_error);
- BOOST_CHECK_THROW(j.__pushKV("k", 1), std::runtime_error);
+ BOOST_CHECK_THROW(j.pushKVEnd("k", 1), std::runtime_error);
BOOST_CHECK_THROW(j.pushKV("k", 1), std::runtime_error);
BOOST_CHECK_THROW(j.pushKVs({}), std::runtime_error);
}
@@ -364,7 +364,7 @@ void univalue_object()
obj.setObject();
UniValue uv;
uv.setInt(42);
- obj.__pushKV("age", uv);
+ obj.pushKVEnd("age", uv);
BOOST_CHECK_EQUAL(obj.size(), 1);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42");
diff --git a/src/validation.cpp b/src/validation.cpp
index d9a0fce34f..6836498a64 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2914,6 +2914,7 @@ CBlockIndex* Chainstate::FindMostWorkChain()
while (pindexTest != pindexFailed) {
if (fFailedChain) {
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
+ m_blockman.m_dirty_blockindex.insert(pindexFailed);
} else if (fMissingData) {
// If we're missing data, then add back to m_blocks_unlinked,
// so that if the block arrives in the future we can try adding
@@ -4998,15 +4999,15 @@ static bool DeleteCoinsDBFromDisk(const fs::path db_path, bool is_snapshot)
if (is_snapshot) {
fs::path base_blockhash_path = db_path / node::SNAPSHOT_BLOCKHASH_FILENAME;
- if (fs::exists(base_blockhash_path)) {
- bool removed = fs::remove(base_blockhash_path);
- if (!removed) {
- LogPrintf("[snapshot] failed to remove file %s\n",
- fs::PathToString(base_blockhash_path));
+ try {
+ bool existed = fs::remove(base_blockhash_path);
+ if (!existed) {
+ LogPrintf("[snapshot] snapshot chainstate dir being removed lacks %s file\n",
+ fs::PathToString(node::SNAPSHOT_BLOCKHASH_FILENAME));
}
- } else {
- LogPrintf("[snapshot] snapshot chainstate dir being removed lacks %s file\n",
- fs::PathToString(node::SNAPSHOT_BLOCKHASH_FILENAME));
+ } catch (const fs::filesystem_error& e) {
+ LogPrintf("[snapshot] failed to remove file %s: %s\n",
+ fs::PathToString(base_blockhash_path), fsbridge::get_filesystem_error_message(e));
}
}
@@ -5411,7 +5412,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
"restart, the node will resume syncing from %d "
"without using any snapshot data. "
"Please report this incident to %s, including how you obtained the snapshot. "
- "The invalid snapshot chainstate has been left on disk in case it is "
+ "The invalid snapshot chainstate will be left on disk in case it is "
"helpful in diagnosing the issue that caused this error."),
PACKAGE_NAME, snapshot_tip_height, snapshot_base_height, snapshot_base_height, PACKAGE_BUGREPORT
);
@@ -5424,7 +5425,10 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
assert(!this->IsUsable(m_snapshot_chainstate.get()));
assert(this->IsUsable(m_ibd_chainstate.get()));
- m_snapshot_chainstate->InvalidateCoinsDBOnDisk();
+ auto rename_result = m_snapshot_chainstate->InvalidateCoinsDBOnDisk();
+ if (!rename_result) {
+ user_error = strprintf(Untranslated("%s\n%s"), user_error, util::ErrorString(rename_result));
+ }
shutdown_fnc(user_error);
};
@@ -5626,7 +5630,7 @@ bool IsBIP30Unspendable(const CBlockIndex& block_index)
(block_index.nHeight==91812 && block_index.GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"));
}
-void Chainstate::InvalidateCoinsDBOnDisk()
+util::Result<void> Chainstate::InvalidateCoinsDBOnDisk()
{
AssertLockHeld(::cs_main);
// Should never be called on a non-snapshot chainstate.
@@ -5655,13 +5659,14 @@ void Chainstate::InvalidateCoinsDBOnDisk()
LogPrintf("%s: error renaming file '%s' -> '%s': %s\n",
__func__, src_str, dest_str, e.what());
- AbortNode(strprintf(
+ return util::Error{strprintf(_(
"Rename of '%s' -> '%s' failed. "
"You should resolve this by manually moving or deleting the invalid "
"snapshot directory %s, otherwise you will encounter the same error again "
- "on the next startup.",
- src_str, dest_str, src_str));
+ "on the next startup."),
+ src_str, dest_str, src_str)};
}
+ return {};
}
const CBlockIndex* ChainstateManager::GetSnapshotBaseBlock() const
diff --git a/src/validation.h b/src/validation.h
index cb5b291dab..7b215dea6b 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -31,6 +31,7 @@
#include <util/check.h>
#include <util/fs.h>
#include <util/hasher.h>
+#include <util/result.h>
#include <util/translation.h>
#include <versionbits.h>
@@ -810,7 +811,7 @@ private:
* In case of an invalid snapshot, rename the coins leveldb directory so
* that it can be examined for issue diagnosis.
*/
- void InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ [[nodiscard]] util::Result<void> InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
friend ChainstateManager;
};
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index bd74025f09..d6b9b68e1f 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -191,7 +191,7 @@ public:
}
};
-util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng,
+util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,
int max_weight)
{
SelectionResult result(target_value, SelectionAlgorithm::SRD);
@@ -201,7 +201,7 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx
// barely meets the target. Just use the lower bound change target instead of the randomly
// generated one, since SRD will result in a random change amount anyway; avoid making the
// target needlessly large.
- target_value += CHANGE_LOWER;
+ target_value += CHANGE_LOWER + change_fee;
std::vector<size_t> indexes;
indexes.resize(utxo_pool.size());
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 432d7d1431..afd868fc89 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -421,7 +421,7 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
* @param[in] max_weight The maximum allowed weight for a selection result to be valid
* @returns If successful, a valid SelectionResult, otherwise, util::Error
*/
-util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng,
+util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,
int max_weight);
// Original coin selection algorithm as a fallback
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index 0bd6a9670c..a8ef0a5731 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -677,11 +677,11 @@ RPCHelpMan getaddressesbylabel()
CHECK_NONFATAL(unique);
// UniValue::pushKV checks if the key exists in O(N)
// and since duplicate addresses are unexpected (checked with
- // std::set in O(log(N))), UniValue::__pushKV is used instead,
+ // std::set in O(log(N))), UniValue::pushKVEnd is used instead,
// which currently is O(1).
UniValue value(UniValue::VOBJ);
value.pushKV("purpose", _purpose ? PurposeToString(*_purpose) : "unknown");
- ret.__pushKV(address, value);
+ ret.pushKVEnd(address, value);
}
});
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 99c6582f9c..a3728223fb 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -583,7 +583,7 @@ util::Result<SelectionResult> ChooseSelectionResult(const CAmount& nTargetValue,
results.push_back(*knapsack_result);
} else append_error(knapsack_result);
- if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.rng_fast, max_inputs_weight)}) {
+ if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.m_change_fee, coin_selection_params.rng_fast, max_inputs_weight)}) {
srd_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
results.push_back(*srd_result);
} else append_error(srd_result);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index b1d67c1432..c8283f453a 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -968,7 +968,7 @@ static util::Result<SelectionResult> SelectCoinsSRD(const CAmount& target,
std::unique_ptr<CWallet> wallet = NewWallet(m_node);
CoinEligibilityFilter filter(0, 0, 0); // accept all coins without ancestors
Groups group = GroupOutputs(*wallet, coin_setup(*wallet), cs_params, {{filter}})[filter].all_groups;
- return SelectCoinsSRD(group.positive_group, target, cs_params.rng_fast, max_weight);
+ return SelectCoinsSRD(group.positive_group, target, cs_params.m_change_fee, cs_params.rng_fast, max_weight);
}
BOOST_AUTO_TEST_CASE(srd_tests)
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 4cda35ed8d..e0b4a1e74c 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -5,6 +5,7 @@
#include <boost/test/unit_test.hpp>
#include <test/util/setup_common.h>
+#include <util/check.h>
#include <util/fs.h>
#include <util/translation.h>
#ifdef USE_BDB
@@ -141,12 +142,10 @@ BOOST_AUTO_TEST_CASE(db_cursor_prefix_range_test)
{
// Test each supported db
for (const auto& database : TestDatabases(m_path_root)) {
- BOOST_ASSERT(database);
-
std::vector<std::string> prefixes = {"", "FIRST", "SECOND", "P\xfe\xff", "P\xff\x01", "\xff\xff"};
// Write elements to it
- std::unique_ptr<DatabaseBatch> handler = database->MakeBatch();
+ std::unique_ptr<DatabaseBatch> handler = Assert(database)->MakeBatch();
for (unsigned int i = 0; i < 10; i++) {
for (const auto& prefix : prefixes) {
BOOST_CHECK(handler->Write(std::make_pair(prefix, i), i));
@@ -162,7 +161,7 @@ BOOST_AUTO_TEST_CASE(db_cursor_prefix_range_test)
DataStream value;
for (int i = 0; i < 10; i++) {
DatabaseCursor::Status status = cursor->Next(key, value);
- BOOST_ASSERT(status == DatabaseCursor::Status::MORE);
+ BOOST_CHECK_EQUAL(status, DatabaseCursor::Status::MORE);
std::string key_back;
unsigned int i_back;
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 9be8efab62..bc935157b1 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -90,8 +90,11 @@ FUZZ_TARGET(coinselection)
// Run coinselection algorithms
const auto result_bnb = SelectCoinsBnB(group_pos, target, cost_of_change, MAX_STANDARD_TX_WEIGHT);
- auto result_srd = SelectCoinsSRD(group_pos, target, fast_random_context, MAX_STANDARD_TX_WEIGHT);
- if (result_srd) result_srd->ComputeAndSetWaste(cost_of_change, cost_of_change, 0);
+ auto result_srd = SelectCoinsSRD(group_pos, target, coin_params.m_change_fee, fast_random_context, MAX_STANDARD_TX_WEIGHT);
+ if (result_srd) {
+ assert(result_srd->GetChange(CHANGE_LOWER, coin_params.m_change_fee) > 0); // Demonstrate that SRD creates change of at least CHANGE_LOWER
+ result_srd->ComputeAndSetWaste(cost_of_change, cost_of_change, 0);
+ }
CAmount change_target{GenerateChangeTarget(target, coin_params.m_change_fee, fast_random_context)};
auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context, MAX_STANDARD_TX_WEIGHT);
diff --git a/src/wallet/test/fuzz/fees.cpp b/src/wallet/test/fuzz/fees.cpp
index 8453ecb720..24e1098941 100644
--- a/src/wallet/test/fuzz/fees.cpp
+++ b/src/wallet/test/fuzz/fees.cpp
@@ -56,7 +56,7 @@ FUZZ_TARGET_INIT(wallet_fees, initialize_setup)
coin_control.m_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
}
if (fuzzed_data_provider.ConsumeBool()) {
- coin_control.m_confirm_target = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ coin_control.m_confirm_target = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 999'000);
}
FeeCalculation fee_calculation;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 62f0f53b01..ba11933b91 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3856,16 +3856,19 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
// Close this database and delete the file
fs::path db_path = fs::PathFromString(m_database->Filename());
- fs::path db_dir = db_path.parent_path();
m_database->Close();
fs::remove(db_path);
+ // Generate the path for the location of the migrated wallet
+ // Wallets that are plain files rather than wallet directories will be migrated to be wallet directories.
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(m_name));
+
// Make new DB
DatabaseOptions opts;
opts.require_create = true;
opts.require_format = DatabaseFormat::SQLITE;
DatabaseStatus db_status;
- std::unique_ptr<WalletDatabase> new_db = MakeDatabase(db_dir, opts, db_status, error);
+ std::unique_ptr<WalletDatabase> new_db = MakeDatabase(wallet_path, opts, db_status, error);
assert(new_db); // This is to prevent doing anything further with this wallet. The original file was deleted, but a backup exists.
m_database.reset();
m_database = std::move(new_db);
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 36ee79dab9..613d2eab14 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -35,7 +35,6 @@ from test_framework.blocktools import (
create_block,
create_coinbase,
)
-from test_framework.key import ECKey
from test_framework.messages import (
CBlockHeader,
COutPoint,
@@ -46,9 +45,13 @@ from test_framework.messages import (
msg_headers,
)
from test_framework.p2p import P2PInterface
-from test_framework.script import (CScript, OP_TRUE)
+from test_framework.script import (
+ CScript,
+ OP_TRUE,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+from test_framework.wallet_util import generate_keypair
class BaseNode(P2PInterface):
@@ -90,9 +93,7 @@ class AssumeValidTest(BitcoinTestFramework):
self.blocks = []
# Get a pubkey for the coinbase TXO
- coinbase_key = ECKey()
- coinbase_key.generate()
- coinbase_pubkey = coinbase_key.get_pubkey().get_bytes()
+ _, coinbase_pubkey = generate_keypair()
# Create the first block with a coinbase output to our key
height = 1
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 1080e77c40..765db97445 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -14,7 +14,6 @@ from test_framework.blocktools import (
get_legacy_sigopcount_block,
MAX_BLOCK_SIGOPS,
)
-from test_framework.key import ECKey
from test_framework.messages import (
CBlock,
COIN,
@@ -55,6 +54,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
)
+from test_framework.wallet_util import generate_keypair
from data import invalid_txs
@@ -98,9 +98,7 @@ class FullBlockTest(BitcoinTestFramework):
self.bootstrap_p2p() # Add one p2p connection to the node
self.block_heights = {}
- self.coinbase_key = ECKey()
- self.coinbase_key.generate()
- self.coinbase_pubkey = self.coinbase_key.get_pubkey().get_bytes()
+ self.coinbase_key, self.coinbase_pubkey = generate_keypair()
self.tip = None
self.blocks = {}
self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 2257605870..b898488924 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -253,7 +253,7 @@ class ConfArgsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
- "Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n",
+ "Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n",
]):
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1'])
assert time.time() - start < 60
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 05ee556ece..03970415ac 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -7,6 +7,7 @@ from copy import deepcopy
from decimal import Decimal
import os
import random
+import time
from test_framework.messages import (
COIN,
@@ -21,6 +22,8 @@ from test_framework.util import (
)
from test_framework.wallet import MiniWallet
+MAX_FILE_AGE = 60
+SECONDS_PER_HOUR = 60 * 60
def small_txpuzzle_randfee(
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs
@@ -290,6 +293,95 @@ class EstimateFeeTest(BitcoinTestFramework):
est_feerate = node.estimatesmartfee(2)["feerate"]
assert_equal(est_feerate, high_feerate_kvb)
+ def test_old_fee_estimate_file(self):
+ # Get the initial fee rate while node is running
+ fee_rate = self.nodes[0].estimatesmartfee(1)["feerate"]
+
+ # Restart node to ensure fee_estimate.dat file is read
+ self.restart_node(0)
+ assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)
+
+ fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
+
+ # Stop the node and backdate the fee_estimates.dat file more than MAX_FILE_AGE
+ self.stop_node(0)
+ last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
+ os.utime(fee_dat, (last_modified_time, last_modified_time))
+
+ # Start node and ensure the fee_estimates.dat file was not read
+ self.start_node(0)
+ assert_equal(self.nodes[0].estimatesmartfee(1)["errors"], ["Insufficient data or no feerate found"])
+
+
+ def test_estimate_dat_is_flushed_periodically(self):
+ fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
+ os.remove(fee_dat) if os.path.exists(fee_dat) else None
+
+ # Verify that fee_estimates.dat does not exist
+ assert_equal(os.path.isfile(fee_dat), False)
+
+ # Verify if the string "Flushed fee estimates to fee_estimates.dat." is present in the debug log file.
+ # If present, it indicates that fee estimates have been successfully flushed to disk.
+ with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
+ # Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
+ self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
+
+ # Verify that fee estimates were flushed and fee_estimates.dat file is created
+ assert_equal(os.path.isfile(fee_dat), True)
+
+ # Verify that the estimates remain the same if there are no blocks in the flush interval
+ block_hash_before = self.nodes[0].getbestblockhash()
+ fee_dat_initial_content = open(fee_dat, "rb").read()
+ with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
+ # Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
+ self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
+
+ # Verify that there were no blocks in between the flush interval
+ assert_equal(block_hash_before, self.nodes[0].getbestblockhash())
+
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert_equal(fee_dat_current_content, fee_dat_initial_content)
+
+ # Verify that the estimates remain the same after shutdown with no blocks before shutdown
+ self.restart_node(0)
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert_equal(fee_dat_current_content, fee_dat_initial_content)
+
+ # Verify that the estimates are not the same if new blocks were produced in the flush interval
+ with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
+ # Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
+ self.generate(self.nodes[0], 5, sync_fun=self.no_op)
+ self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
+
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert fee_dat_current_content != fee_dat_initial_content
+
+ fee_dat_initial_content = fee_dat_current_content
+
+ # Generate blocks before shutdown and verify that the fee estimates are not the same
+ self.generate(self.nodes[0], 5, sync_fun=self.no_op)
+ self.restart_node(0)
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert fee_dat_current_content != fee_dat_initial_content
+
+
+ def test_acceptstalefeeestimates_option(self):
+ # Get the initial fee rate while node is running
+ fee_rate = self.nodes[0].estimatesmartfee(1)["feerate"]
+
+ self.stop_node(0)
+
+ fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
+
+ # Stop the node and backdate the fee_estimates.dat file more than MAX_FILE_AGE
+ last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
+ os.utime(fee_dat, (last_modified_time, last_modified_time))
+
+ # Restart node with -acceptstalefeeestimates option to ensure fee_estimate.dat file is read
+ self.start_node(0,extra_args=["-acceptstalefeeestimates"])
+ assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)
+
+
def run_test(self):
self.log.info("This test is time consuming, please be patient")
self.log.info("Splitting inputs so we can generate tx's")
@@ -312,12 +404,21 @@ class EstimateFeeTest(BitcoinTestFramework):
self.log.info("Testing estimates with single transactions.")
self.sanity_check_estimates_range()
+ self.log.info("Test fee_estimates.dat is flushed periodically")
+ self.test_estimate_dat_is_flushed_periodically()
+
# check that the effective feerate is greater than or equal to the mempoolminfee even for high mempoolminfee
self.log.info(
"Test fee rate estimation after restarting node with high MempoolMinFee"
)
self.test_feerate_mempoolminfee()
+ self.log.info("Test acceptstalefeeestimates option")
+ self.test_acceptstalefeeestimates_option()
+
+ self.log.info("Test reading old fee_estimates.dat")
+ self.test_old_fee_estimate_file()
+
self.log.info("Restarting node with fresh estimation")
self.stop_node(0)
fee_dat = os.path.join(self.nodes[0].datadir, self.chain, "fee_estimates.dat")
diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py
index fe4f02dfe6..b0788e2a2d 100755
--- a/test/functional/feature_logging.py
+++ b/test/functional/feature_logging.py
@@ -69,6 +69,36 @@ class LoggingTest(BitcoinTestFramework):
# just sanity check no crash here
self.restart_node(0, [f"-debuglogfile={os.devnull}"])
+ self.log.info("Test -debug and -debugexclude raise when invalid values are passed")
+ self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-debug=abc"],
+ expected_msg="Error: Unsupported logging category -debug=abc.",
+ match=ErrorMatch.FULL_REGEX,
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-debugexclude=abc"],
+ expected_msg="Error: Unsupported logging category -debugexclude=abc.",
+ match=ErrorMatch.FULL_REGEX,
+ )
+
+ self.log.info("Test -loglevel raises when invalid values are passed")
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-loglevel=abc"],
+ expected_msg="Error: Unsupported global logging level -loglevel=abc. Valid values: info, debug, trace.",
+ match=ErrorMatch.FULL_REGEX,
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-loglevel=net:abc"],
+ expected_msg="Error: Unsupported category-specific logging level -loglevel=net:abc.",
+ match=ErrorMatch.PARTIAL_REGEX,
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-loglevel=net:info:abc"],
+ expected_msg="Error: Unsupported category-specific logging level -loglevel=net:info:abc.",
+ match=ErrorMatch.PARTIAL_REGEX,
+ )
+
if __name__ == '__main__':
LoggingTest().main()
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index c95657dbbb..7b2a29bdb4 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -35,8 +35,7 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import getnewdestination
-from test_framework.key import ECKey
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
@@ -71,12 +70,9 @@ class NULLDUMMYTest(BitcoinTestFramework):
return tx_from_hex(signedtx["hex"])
def run_test(self):
- eckey = ECKey()
- eckey.generate()
- self.privkey = bytes_to_wif(eckey.get_bytes())
- self.pubkey = eckey.get_pubkey().get_bytes().hex()
- cms = self.nodes[0].createmultisig(1, [self.pubkey])
- wms = self.nodes[0].createmultisig(1, [self.pubkey], 'p2sh-segwit')
+ self.privkey, self.pubkey = generate_keypair(wif=True)
+ cms = self.nodes[0].createmultisig(1, [self.pubkey.hex()])
+ wms = self.nodes[0].createmultisig(1, [self.pubkey.hex()], 'p2sh-segwit')
self.ms_address = cms["address"]
ms_unlock_details = {"scriptPubKey": address_to_scriptpubkey(self.ms_address).hex(),
"redeemScript": cms["redeemScript"]}
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 8be2040d91..ec1e580369 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -97,6 +97,7 @@ from test_framework.util import (
assert_equal,
random_bytes,
)
+from test_framework.wallet_util import generate_keypair
from test_framework.key import (
generate_privkey,
compute_xonly_pubkey,
@@ -738,7 +739,11 @@ def spenders_taproot_active():
scripts = [
("pk_codesep", CScript(random_checksig_style(pubs[1]) + bytes([OP_CODESEPARATOR]))), # codesep after checksig
("codesep_pk", CScript(bytes([OP_CODESEPARATOR]) + random_checksig_style(pubs[1]))), # codesep before checksig
- ("branched_codesep", CScript([random_bytes(random.randrange(511)), OP_DROP, OP_IF, OP_CODESEPARATOR, pubs[0], OP_ELSE, OP_CODESEPARATOR, pubs[1], OP_ENDIF, OP_CHECKSIG])), # branch dependent codesep
+ ("branched_codesep", CScript([random_bytes(random.randrange(2, 511)), OP_DROP, OP_IF, OP_CODESEPARATOR, pubs[0], OP_ELSE, OP_CODESEPARATOR, pubs[1], OP_ENDIF, OP_CHECKSIG])), # branch dependent codesep
+ # Note that the first data push in the "branched_codesep" script has the purpose of
+ # randomizing the sighash, both by varying script size and content. In order to
+ # avoid MINIMALDATA script verification errors caused by not-minimal-encoded data
+ # pushes (e.g. `OP_PUSH1 1` instead of `OP_1`), we set a minimum data size of 2 bytes.
]
random.shuffle(scripts)
tap = taproot_construct(pubs[0], scripts)
@@ -1186,11 +1191,8 @@ def spenders_taproot_active():
# Also add a few legacy spends into the mix, so that transactions which combine taproot and pre-taproot spends get tested too.
for compressed in [False, True]:
- eckey1 = ECKey()
- eckey1.set(generate_privkey(), compressed)
- pubkey1 = eckey1.get_pubkey().get_bytes()
- eckey2 = ECKey()
- eckey2.set(generate_privkey(), compressed)
+ eckey1, pubkey1 = generate_keypair(compressed=compressed)
+ eckey2, _ = generate_keypair(compressed=compressed)
for p2sh in [False, True]:
for witv0 in [False, True]:
for hashtype in VALID_SIGHASHES_ECDSA + [random.randrange(0x04, 0x80), random.randrange(0x84, 0x100)]:
diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py
index 7f088a3ca8..f138fa44cc 100755
--- a/test/functional/interface_usdt_mempool.py
+++ b/test/functional/interface_usdt_mempool.py
@@ -139,6 +139,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_ADDED_EVENTS = 1
handled_added_events = 0
+ event = None
self.log.info("Hooking into mempool:added tracepoint...")
node = self.nodes[0]
@@ -147,11 +148,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_added_event(_, data, __):
- nonlocal handled_added_events
+ nonlocal event, handled_added_events
event = bpf["added_events"].event(data)
- assert_equal(txid, bytes(event.hash)[::-1].hex())
- assert_equal(vsize, event.vsize)
- assert_equal(fee, event.fee)
handled_added_events += 1
bpf["added_events"].open_perf_buffer(handle_added_event)
@@ -159,9 +157,6 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Sending transaction...")
fee = Decimal(31200)
tx = self.wallet.send_self_transfer(from_node=node, fee=fee / COIN)
- # expected data
- txid = tx["txid"]
- vsize = tx["tx"].get_vsize()
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
@@ -169,10 +164,13 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Cleaning up mempool...")
self.generate(node, 1)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:added event was handled successfully...")
assert_equal(EXPECTED_ADDED_EVENTS, handled_added_events)
+ assert_equal(bytes(event.hash)[::-1].hex(), tx["txid"])
+ assert_equal(event.vsize, tx["tx"].get_vsize())
+ assert_equal(event.fee, fee)
+
+ bpf.cleanup()
self.generate(self.wallet, 1)
def removed_test(self):
@@ -181,6 +179,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_REMOVED_EVENTS = 1
handled_removed_events = 0
+ event = None
self.log.info("Hooking into mempool:removed tracepoint...")
node = self.nodes[0]
@@ -189,13 +188,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_removed_event(_, data, __):
- nonlocal handled_removed_events
+ nonlocal event, handled_removed_events
event = bpf["removed_events"].event(data)
- assert_equal(txid, bytes(event.hash)[::-1].hex())
- assert_equal(reason, event.reason.decode("UTF-8"))
- assert_equal(vsize, event.vsize)
- assert_equal(fee, event.fee)
- assert_equal(entry_time, event.entry_time)
handled_removed_events += 1
bpf["removed_events"].open_perf_buffer(handle_removed_event)
@@ -203,10 +197,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Sending transaction...")
fee = Decimal(31200)
tx = self.wallet.send_self_transfer(from_node=node, fee=fee / COIN)
- # expected data
txid = tx["txid"]
- reason = "expiry"
- vsize = tx["tx"].get_vsize()
self.log.info("Fast-forwarding time to mempool expiry...")
entry_time = node.getmempoolentry(txid)["time"]
@@ -220,10 +211,15 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:removed event was handled successfully...")
assert_equal(EXPECTED_REMOVED_EVENTS, handled_removed_events)
+ assert_equal(bytes(event.hash)[::-1].hex(), txid)
+ assert_equal(event.reason.decode("UTF-8"), "expiry")
+ assert_equal(event.vsize, tx["tx"].get_vsize())
+ assert_equal(event.fee, fee)
+ assert_equal(event.entry_time, entry_time)
+
+ bpf.cleanup()
self.generate(self.wallet, 1)
def replaced_test(self):
@@ -232,6 +228,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_REPLACED_EVENTS = 1
handled_replaced_events = 0
+ event = None
self.log.info("Hooking into mempool:replaced tracepoint...")
node = self.nodes[0]
@@ -240,15 +237,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_replaced_event(_, data, __):
- nonlocal handled_replaced_events
+ nonlocal event, handled_replaced_events
event = bpf["replaced_events"].event(data)
- assert_equal(replaced_txid, bytes(event.replaced_hash)[::-1].hex())
- assert_equal(replaced_vsize, event.replaced_vsize)
- assert_equal(replaced_fee, event.replaced_fee)
- assert_equal(replaced_entry_time, event.replaced_entry_time)
- assert_equal(replacement_txid, bytes(event.replacement_hash)[::-1].hex())
- assert_equal(replacement_vsize, event.replacement_vsize)
- assert_equal(replacement_fee, event.replacement_fee)
handled_replaced_events += 1
bpf["replaced_events"].open_perf_buffer(handle_replaced_event)
@@ -267,21 +257,20 @@ class MempoolTracepointTest(BitcoinTestFramework):
from_node=node, utxo_to_spend=utxo, fee=replacement_fee / COIN
)
- # expected data
- replaced_txid = original_tx["txid"]
- replaced_vsize = original_tx["tx"].get_vsize()
- replaced_fee = original_fee
- replaced_entry_time = entry_time
- replacement_txid = replacement_tx["txid"]
- replacement_vsize = replacement_tx["tx"].get_vsize()
-
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:replaced event was handled successfully...")
assert_equal(EXPECTED_REPLACED_EVENTS, handled_replaced_events)
+ assert_equal(bytes(event.replaced_hash)[::-1].hex(), original_tx["txid"])
+ assert_equal(event.replaced_vsize, original_tx["tx"].get_vsize())
+ assert_equal(event.replaced_fee, original_fee)
+ assert_equal(event.replaced_entry_time, entry_time)
+ assert_equal(bytes(event.replacement_hash)[::-1].hex(), replacement_tx["txid"])
+ assert_equal(event.replacement_vsize, replacement_tx["tx"].get_vsize())
+ assert_equal(event.replacement_fee, replacement_fee)
+
+ bpf.cleanup()
self.generate(self.wallet, 1)
def rejected_test(self):
@@ -290,6 +279,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_REJECTED_EVENTS = 1
handled_rejected_events = 0
+ event = None
self.log.info("Adding P2P connection...")
node = self.nodes[0]
@@ -301,10 +291,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_rejected_event(_, data, __):
- nonlocal handled_rejected_events
+ nonlocal event, handled_rejected_events
event = bpf["rejected_events"].event(data)
- assert_equal(txid, bytes(event.hash)[::-1].hex())
- assert_equal(reason, event.reason.decode("UTF-8"))
handled_rejected_events += 1
bpf["rejected_events"].open_perf_buffer(handle_rejected_event)
@@ -313,17 +301,15 @@ class MempoolTracepointTest(BitcoinTestFramework):
tx = self.wallet.create_self_transfer(fee_rate=Decimal(0))
node.p2ps[0].send_txs_and_test([tx["tx"]], node, success=False)
- # expected data
- txid = tx["tx"].hash
- reason = "min relay fee not met"
-
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:rejected event was handled successfully...")
assert_equal(EXPECTED_REJECTED_EVENTS, handled_rejected_events)
+ assert_equal(bytes(event.hash)[::-1].hex(), tx["tx"].hash)
+ assert_equal(event.reason.decode("UTF-8"), "min relay fee not met")
+
+ bpf.cleanup()
self.generate(self.wallet, 1)
def run_test(self):
diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py
index 2235da702b..d1f94637c9 100755
--- a/test/functional/interface_usdt_net.py
+++ b/test/functional/interface_usdt_net.py
@@ -116,13 +116,10 @@ class NetTracepointTest(BitcoinTestFramework):
fn_name="trace_outbound_message")
bpf = BPF(text=net_tracepoints_program, usdt_contexts=[ctx], debug=0)
- # The handle_* function is a ctypes callback function called from C. When
- # we assert in the handle_* function, the AssertError doesn't propagate
- # back to Python. The exception is ignored. We manually count and assert
- # that the handle_* functions succeeded.
EXPECTED_INOUTBOUND_VERSION_MSG = 1
checked_inbound_version_msg = 0
checked_outbound_version_msg = 0
+ events = []
def check_p2p_message(event, inbound):
nonlocal checked_inbound_version_msg, checked_outbound_version_msg
@@ -142,12 +139,13 @@ class NetTracepointTest(BitcoinTestFramework):
checked_outbound_version_msg += 1
def handle_inbound(_, data, __):
+ nonlocal events
event = ctypes.cast(data, ctypes.POINTER(P2PMessage)).contents
- check_p2p_message(event, True)
+ events.append((event, True))
def handle_outbound(_, data, __):
event = ctypes.cast(data, ctypes.POINTER(P2PMessage)).contents
- check_p2p_message(event, False)
+ events.append((event, False))
bpf["inbound_messages"].open_perf_buffer(handle_inbound)
bpf["outbound_messages"].open_perf_buffer(handle_outbound)
@@ -158,12 +156,15 @@ class NetTracepointTest(BitcoinTestFramework):
bpf.perf_buffer_poll(timeout=200)
self.log.info(
- "check that we got both an inbound and outbound version message")
+ "check receipt and content of in- and outbound version messages")
+ for event, inbound in events:
+ check_p2p_message(event, inbound)
assert_equal(EXPECTED_INOUTBOUND_VERSION_MSG,
checked_inbound_version_msg)
assert_equal(EXPECTED_INOUTBOUND_VERSION_MSG,
checked_outbound_version_msg)
+
bpf.cleanup()
diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py
index 6774db7c5f..5f2ba49026 100755
--- a/test/functional/interface_usdt_utxocache.py
+++ b/test/functional/interface_usdt_utxocache.py
@@ -188,13 +188,16 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
nonlocal handle_uncache_succeeds
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
self.log.info(f"handle_utxocache_uncache(): {event}")
- assert_equal(block_1_coinbase_txid, bytes(event.txid[::-1]).hex())
- assert_equal(0, event.index) # prevout index
- assert_equal(EARLY_BLOCK_HEIGHT, event.height)
- assert_equal(50 * COIN, event.value)
- assert_equal(True, event.is_coinbase)
-
- handle_uncache_succeeds += 1
+ try:
+ assert_equal(block_1_coinbase_txid, bytes(event.txid[::-1]).hex())
+ assert_equal(0, event.index) # prevout index
+ assert_equal(EARLY_BLOCK_HEIGHT, event.height)
+ assert_equal(50 * COIN, event.value)
+ assert_equal(True, event.is_coinbase)
+ except AssertionError:
+ self.log.exception("Assertion failed")
+ else:
+ handle_uncache_succeeds += 1
bpf["utxocache_uncache"].open_perf_buffer(handle_utxocache_uncache)
@@ -260,24 +263,32 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
self.log.info(f"handle_utxocache_add(): {event}")
add = expected_utxocache_adds.pop(0)
- assert_equal(add["txid"], bytes(event.txid[::-1]).hex())
- assert_equal(add["index"], event.index)
- assert_equal(add["height"], event.height)
- assert_equal(add["value"], event.value)
- assert_equal(add["is_coinbase"], event.is_coinbase)
- handle_add_succeeds += 1
+ try:
+ assert_equal(add["txid"], bytes(event.txid[::-1]).hex())
+ assert_equal(add["index"], event.index)
+ assert_equal(add["height"], event.height)
+ assert_equal(add["value"], event.value)
+ assert_equal(add["is_coinbase"], event.is_coinbase)
+ except AssertionError:
+ self.log.exception("Assertion failed")
+ else:
+ handle_add_succeeds += 1
def handle_utxocache_spent(_, data, __):
nonlocal handle_spent_succeeds
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
self.log.info(f"handle_utxocache_spent(): {event}")
spent = expected_utxocache_spents.pop(0)
- assert_equal(spent["txid"], bytes(event.txid[::-1]).hex())
- assert_equal(spent["index"], event.index)
- assert_equal(spent["height"], event.height)
- assert_equal(spent["value"], event.value)
- assert_equal(spent["is_coinbase"], event.is_coinbase)
- handle_spent_succeeds += 1
+ try:
+ assert_equal(spent["txid"], bytes(event.txid[::-1]).hex())
+ assert_equal(spent["index"], event.index)
+ assert_equal(spent["height"], event.height)
+ assert_equal(spent["value"], event.value)
+ assert_equal(spent["is_coinbase"], event.is_coinbase)
+ except AssertionError:
+ self.log.exception("Assertion failed")
+ else:
+ handle_spent_succeeds += 1
bpf["utxocache_add"].open_perf_buffer(handle_utxocache_add)
bpf["utxocache_spent"].open_perf_buffer(handle_utxocache_spent)
diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py
index 4323aef771..f9d9b525cd 100755
--- a/test/functional/interface_usdt_validation.py
+++ b/test/functional/interface_usdt_validation.py
@@ -85,13 +85,10 @@ class ValidationTracepointTest(BitcoinTestFramework):
self.sigops,
self.duration)
- # The handle_* function is a ctypes callback function called from C. When
- # we assert in the handle_* function, the AssertError doesn't propagate
- # back to Python. The exception is ignored. We manually count and assert
- # that the handle_* functions succeeded.
BLOCKS_EXPECTED = 2
blocks_checked = 0
expected_blocks = dict()
+ events = []
self.log.info("hook into the validation:block_connected tracepoint")
ctx = USDT(pid=self.nodes[0].process.pid)
@@ -101,19 +98,10 @@ class ValidationTracepointTest(BitcoinTestFramework):
usdt_contexts=[ctx], debug=0)
def handle_blockconnected(_, data, __):
- nonlocal expected_blocks, blocks_checked
+ nonlocal events, blocks_checked
event = ctypes.cast(data, ctypes.POINTER(Block)).contents
self.log.info(f"handle_blockconnected(): {event}")
- block_hash = bytes(event.hash[::-1]).hex()
- block = expected_blocks[block_hash]
- assert_equal(block["hash"], block_hash)
- assert_equal(block["height"], event.height)
- assert_equal(len(block["tx"]), event.transactions)
- assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs)
- assert_equal(0, event.sigops) # no sigops in coinbase tx
- # only plausibility checks
- assert event.duration > 0
- del expected_blocks[block_hash]
+ events.append(event)
blocks_checked += 1
bpf["block_connected"].open_perf_buffer(
@@ -126,12 +114,24 @@ class ValidationTracepointTest(BitcoinTestFramework):
expected_blocks[block_hash] = self.nodes[0].getblock(block_hash, 2)
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
- self.log.info(f"check that we traced {BLOCKS_EXPECTED} blocks")
+ self.log.info(f"check that we correctly traced {BLOCKS_EXPECTED} blocks")
+ for event in events:
+ block_hash = bytes(event.hash[::-1]).hex()
+ block = expected_blocks[block_hash]
+ assert_equal(block["hash"], block_hash)
+ assert_equal(block["height"], event.height)
+ assert_equal(len(block["tx"]), event.transactions)
+ assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs)
+ assert_equal(0, event.sigops) # no sigops in coinbase tx
+ # only plausibility checks
+ assert event.duration > 0
+ del expected_blocks[block_hash]
assert_equal(BLOCKS_EXPECTED, blocks_checked)
assert_equal(0, len(expected_blocks))
+ bpf.cleanup()
+
if __name__ == '__main__':
ValidationTracepointTest().main()
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 737a8d0a2e..8f3aec96a7 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -9,7 +9,6 @@ from decimal import Decimal
import math
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.key import ECKey
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
COIN,
@@ -44,6 +43,7 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import generate_keypair
class MempoolAcceptanceTest(BitcoinTestFramework):
@@ -283,9 +283,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[tx.serialize().hex()],
)
tx = tx_from_hex(raw_tx_reference)
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
+ _, pubkey = generate_keypair()
tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=2) # Some bare multisig script (2-of-3)
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
diff --git a/test/functional/mempool_dust.py b/test/functional/mempool_dust.py
index 41a26e82da..f4e385a112 100755
--- a/test/functional/mempool_dust.py
+++ b/test/functional/mempool_dust.py
@@ -5,7 +5,6 @@
"""Test dust limit mempool policy (`-dustrelayfee` parameter)"""
from decimal import Decimal
-from test_framework.key import ECKey
from test_framework.messages import (
COIN,
CTxOut,
@@ -32,6 +31,7 @@ from test_framework.util import (
get_fee,
)
from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import generate_keypair
DUST_RELAY_TX_FEE = 3000 # default setting [sat/kvB]
@@ -74,11 +74,8 @@ class DustRelayFeeTest(BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
# prepare output scripts of each standard type
- key = ECKey()
- key.generate(compressed=False)
- uncompressed_pubkey = key.get_pubkey().get_bytes()
- key.generate(compressed=True)
- pubkey = key.get_pubkey().get_bytes()
+ _, uncompressed_pubkey = generate_keypair(compressed=False)
+ _, pubkey = generate_keypair(compressed=True)
output_scripts = (
(key_to_p2pk_script(uncompressed_pubkey), "P2PK (uncompressed)"),
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index b0900e49b8..bfae190c66 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -14,7 +14,6 @@ from test_framework.blocktools import (
create_block,
create_coinbase,
)
-from test_framework.key import ECKey
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
CBlockHeader,
@@ -89,6 +88,7 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import generate_keypair
MAX_SIGOP_COST = 80000
@@ -1448,9 +1448,7 @@ class SegWitTest(BitcoinTestFramework):
# Segwit transactions using uncompressed pubkeys are not accepted
# under default policy, but should still pass consensus.
- key = ECKey()
- key.generate(False)
- pubkey = key.get_pubkey().get_bytes()
+ key, pubkey = generate_keypair(compressed=False)
assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
utxo = self.utxo.pop(0)
@@ -1544,11 +1542,7 @@ class SegWitTest(BitcoinTestFramework):
@subtest
def test_signature_version_1(self):
-
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
-
+ key, pubkey = generate_keypair()
witness_script = key_to_p2pk_script(pubkey)
script_pubkey = script_to_p2wsh_script(witness_script)
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 279fb01a57..34e60d70f0 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -12,13 +12,13 @@ from test_framework.address import address_to_scriptpubkey
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create, drop_origins
-from test_framework.key import ECPubKey, ECKey
+from test_framework.key import ECPubKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_raises_rpc_error,
assert_equal,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
from test_framework.wallet import (
MiniWallet,
getnewdestination,
@@ -38,10 +38,9 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
self.priv = []
node0, node1, node2 = self.nodes
for _ in range(self.nkeys):
- k = ECKey()
- k.generate()
- self.pub.append(k.get_pubkey().get_bytes().hex())
- self.priv.append(bytes_to_wif(k.get_bytes(), k.is_compressed))
+ privkey, pubkey = generate_keypair(wif=True)
+ self.pub.append(pubkey.hex())
+ self.priv.append(privkey)
if self.is_bdb_compiled():
self.final = node2.getnewaddress()
else:
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index e2fb4673ea..c4ed4da0f2 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -8,7 +8,7 @@ from decimal import Decimal
from itertools import product
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey, H_POINT
+from test_framework.key import H_POINT
from test_framework.messages import (
COutPoint,
CTransaction,
@@ -43,8 +43,8 @@ from test_framework.util import (
random_bytes,
)
from test_framework.wallet_util import (
- bytes_to_wif,
- get_generate_key
+ generate_keypair,
+ get_generate_key,
)
import json
@@ -710,9 +710,7 @@ class PSBTTest(BitcoinTestFramework):
self.log.info("Test that we can fund psbts with external inputs specified")
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, _ = generate_keypair(wif=True)
self.nodes[1].createwallet("extfund")
wallet = self.nodes[1].get_wallet_rpc("extfund")
@@ -825,11 +823,9 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[1].createwallet(wallet_name="scriptwatchonly", disable_private_keys=True)
watchonly = self.nodes[1].get_wallet_rpc("scriptwatchonly")
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
- desc = descsum_create("wsh(pkh({}))".format(eckey.get_pubkey().get_bytes().hex()))
+ desc = descsum_create("wsh(pkh({}))".format(pubkey.hex()))
if self.options.descriptors:
res = watchonly.importdescriptors([{"desc": desc, "timestamp": "now"}])
else:
@@ -846,11 +842,9 @@ class PSBTTest(BitcoinTestFramework):
# Same test but for taproot
if self.options.descriptors:
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
- desc = descsum_create("tr({},pk({}))".format(H_POINT, eckey.get_pubkey().get_bytes().hex()))
+ desc = descsum_create("tr({},pk({}))".format(H_POINT, pubkey.hex()))
res = watchonly.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert res[0]["success"]
addr = self.nodes[0].deriveaddresses(desc)[0]
diff --git a/test/functional/rpc_signrawtransactionwithkey.py b/test/functional/rpc_signrawtransactionwithkey.py
index 580f63063d..ac7a86704f 100755
--- a/test/functional/rpc_signrawtransactionwithkey.py
+++ b/test/functional/rpc_signrawtransactionwithkey.py
@@ -11,7 +11,6 @@ from test_framework.address import (
address_to_scriptpubkey,
script_to_p2sh,
)
-from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -23,16 +22,16 @@ from test_framework.script_util import (
script_to_p2sh_p2wsh_script,
script_to_p2wsh_script,
)
+from test_framework.wallet import (
+ getnewdestination,
+)
from test_framework.wallet_util import (
- bytes_to_wif,
+ generate_keypair,
)
from decimal import (
Decimal,
)
-from test_framework.wallet import (
- getnewdestination,
-)
class SignRawTransactionWithKeyTest(BitcoinTestFramework):
@@ -80,11 +79,8 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework):
def witness_script_test(self):
self.log.info("Test signing transaction to P2SH-P2WSH addresses without wallet")
# Create a new P2SH-P2WSH 1-of-1 multisig address:
- eckey = ECKey()
- eckey.generate()
- embedded_privkey = bytes_to_wif(eckey.get_bytes())
- embedded_pubkey = eckey.get_pubkey().get_bytes().hex()
- p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey], "p2sh-segwit")
+ embedded_privkey, embedded_pubkey = generate_keypair(wif=True)
+ p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey.hex()], "p2sh-segwit")
# send transaction to P2SH-P2WSH 1-of-1 multisig address
self.block_hash = self.generate(self.nodes[0], COINBASE_MATURITY + 1)
self.blk_idx = 0
@@ -109,10 +105,7 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework):
def verify_txn_with_witness_script(self, tx_type):
self.log.info("Test with a {} script as the witnessScript".format(tx_type))
- eckey = ECKey()
- eckey.generate()
- embedded_privkey = bytes_to_wif(eckey.get_bytes())
- embedded_pubkey = eckey.get_pubkey().get_bytes().hex()
+ embedded_privkey, embedded_pubkey = generate_keypair(wif=True)
witness_script = {
'P2PKH': key_to_p2pkh_script(embedded_pubkey).hex(),
'P2PK': key_to_p2pk_script(embedded_pubkey).hex()
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 1d546e12bd..271095ea21 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -20,6 +20,7 @@ from test_framework.address import (
key_to_p2wpkh,
output_key_to_p2tr,
)
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.descriptors import descsum_create
from test_framework.key import (
ECKey,
@@ -53,7 +54,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than_or_equal,
)
-from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.wallet_util import generate_keypair
DEFAULT_FEE = Decimal("0.0001")
@@ -395,9 +396,7 @@ def getnewdestination(address_type='bech32m'):
'legacy', 'p2sh-segwit', 'bech32' and 'bech32m'. Can be used when a random
destination is needed, but no compiled wallet is available (e.g. as
replacement to the getnewaddress/getaddressinfo RPCs)."""
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
+ key, pubkey = generate_keypair()
if address_type == 'legacy':
scriptpubkey = key_to_p2pkh_script(pubkey)
address = key_to_p2pkh(pubkey)
diff --git a/test/functional/test_framework/wallet_util.py b/test/functional/test_framework/wallet_util.py
index 410d85cd8c..319f120297 100755
--- a/test/functional/test_framework/wallet_util.py
+++ b/test/functional/test_framework/wallet_util.py
@@ -63,12 +63,9 @@ def get_generate_key():
"""Generate a fresh key
Returns a named tuple of privkey, pubkey and all address and scripts."""
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
- pubkey = eckey.get_pubkey().get_bytes().hex()
+ privkey, pubkey = generate_keypair(wif=True)
return Key(privkey=privkey,
- pubkey=pubkey,
+ pubkey=pubkey.hex(),
p2pkh_script=key_to_p2pkh_script(pubkey).hex(),
p2pkh_addr=key_to_p2pkh(pubkey),
p2wpkh_script=key_to_p2wpkh_script(pubkey).hex(),
@@ -114,8 +111,14 @@ def bytes_to_wif(b, compressed=True):
b += b'\x01'
return byte_to_base58(b, 239)
-def generate_wif_key():
- # Makes a WIF privkey for imports
- k = ECKey()
- k.generate()
- return bytes_to_wif(k.get_bytes(), k.is_compressed)
+def generate_keypair(compressed=True, wif=False):
+ """Generate a new random keypair and return the corresponding ECKey /
+ bytes objects. The private key can also be provided as WIF (wallet
+ import format) string instead, which is often useful for wallet RPC
+ interaction."""
+ privkey = ECKey()
+ privkey.generate(compressed)
+ pubkey = privkey.get_pubkey().get_bytes()
+ if wif:
+ privkey = bytes_to_wif(privkey.get_bytes(), compressed)
+ return privkey, pubkey
diff --git a/test/functional/wallet_blank.py b/test/functional/wallet_blank.py
index eda3fda35b..4836eba3b2 100755
--- a/test/functional/wallet_blank.py
+++ b/test/functional/wallet_blank.py
@@ -10,11 +10,10 @@ from test_framework.address import (
ADDRESS_BCRT1_UNSPENDABLE,
ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR,
)
-from test_framework.key import ECKey
from test_framework.util import (
assert_equal,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
class WalletBlankTest(BitcoinTestFramework):
@@ -50,10 +49,8 @@ class WalletBlankTest(BitcoinTestFramework):
assert_equal(info["descriptors"], False)
assert_equal(info["blank"], True)
- eckey = ECKey()
- eckey.generate(compressed=comp)
-
- wallet.importpubkey(eckey.get_pubkey().get_bytes().hex())
+ _, pubkey = generate_keypair(compressed=comp)
+ wallet.importpubkey(pubkey.hex())
assert_equal(wallet.getwalletinfo()["blank"], False)
def test_importprivkey(self):
@@ -67,10 +64,7 @@ class WalletBlankTest(BitcoinTestFramework):
assert_equal(info["descriptors"], False)
assert_equal(info["blank"], True)
- eckey = ECKey()
- eckey.generate(compressed=comp)
- wif = bytes_to_wif(eckey.get_bytes(), eckey.is_compressed)
-
+ wif, _ = generate_keypair(compressed=comp, wif=True)
wallet.importprivkey(wif)
assert_equal(wallet.getwalletinfo()["blank"], False)
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index a4e6f96cce..75b507c387 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -7,13 +7,13 @@
from test_framework.address import key_to_p2wpkh
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import bytes_to_wif, generate_wif_key
+from test_framework.wallet_util import generate_keypair
+
EMPTY_PASSPHRASE_MSG = "Empty string given as passphrase, wallet will not be encrypted."
LEGACY_WALLET_MSG = "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."
@@ -50,14 +50,12 @@ class CreateWalletTest(BitcoinTestFramework):
w1.importpubkey(w0.getaddressinfo(address1)['pubkey'])
self.log.info('Test that private keys cannot be imported')
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey)
if self.options.descriptors:
result = w1.importdescriptors([{'desc': descsum_create('wpkh(' + privkey + ')'), 'timestamp': 'now'}])
else:
- result = w1.importmulti([{'scriptPubKey': {'address': key_to_p2wpkh(eckey.get_pubkey().get_bytes())}, 'timestamp': 'now', 'keys': [privkey]}])
+ result = w1.importmulti([{'scriptPubKey': {'address': key_to_p2wpkh(pubkey)}, 'timestamp': 'now', 'keys': [privkey]}])
assert not result[0]['success']
assert 'warnings' not in result[0]
assert_equal(result[0]['error']['code'], -4)
@@ -77,7 +75,7 @@ class CreateWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getrawchangeaddress)
# Import private key
- w3.importprivkey(generate_wif_key())
+ w3.importprivkey(generate_keypair(wif=True)[0])
# Imported private keys are currently ignored by the keypool
assert_equal(w3.getwalletinfo()['keypoolsize'], 0)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)
diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py
index c88e0b3f6e..46706d6ad2 100755
--- a/test/functional/wallet_fundrawtransaction.py
+++ b/test/functional/wallet_fundrawtransaction.py
@@ -10,7 +10,6 @@ from itertools import product
from math import ceil
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.messages import (
COIN,
)
@@ -25,7 +24,7 @@ from test_framework.util import (
count_bytes,
find_vout_for_address,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \
"Please allow other inputs to be automatically selected or include more coins manually"
@@ -999,11 +998,7 @@ class RawTransactionsTest(BitcoinTestFramework):
def test_external_inputs(self):
self.log.info("Test funding with external inputs")
-
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
-
+ privkey, _ = generate_keypair(wif=True)
self.nodes[2].createwallet("extfund")
wallet = self.nodes[2].get_wallet_rpc("extfund")
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 77b407579f..5fe7c4b591 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -7,7 +7,6 @@ from decimal import Decimal
from test_framework.address import key_to_p2wpkh
from test_framework.blocktools import COINBASE_MATURITY
-from test_framework.key import ECKey
from test_framework.messages import (
CMerkleBlock,
from_hex,
@@ -17,7 +16,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
class ImportPrunedFundsTest(BitcoinTestFramework):
@@ -40,10 +39,8 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
# pubkey
address2 = self.nodes[0].getnewaddress()
# privkey
- eckey = ECKey()
- eckey.generate()
- address3_privkey = bytes_to_wif(eckey.get_bytes())
- address3 = key_to_p2wpkh(eckey.get_pubkey().get_bytes())
+ address3_privkey, address3_pubkey = generate_keypair(wif=True)
+ address3 = key_to_p2wpkh(address3_pubkey)
self.nodes[0].importprivkey(address3_privkey)
# Check only one address
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index bfca344fd1..a19a3ac2cb 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -7,7 +7,6 @@
from test_framework.address import key_to_p2wpkh
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import MAX_BIP125_RBF_SEQUENCE
from test_framework.util import (
@@ -15,7 +14,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
from decimal import Decimal
@@ -202,10 +201,8 @@ class ListSinceBlockTest(BitcoinTestFramework):
self.sync_all()
# share utxo between nodes[1] and nodes[2]
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
- address = key_to_p2wpkh(eckey.get_pubkey().get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
+ address = key_to_p2wpkh(pubkey)
self.nodes[2].sendtoaddress(address, 10)
self.generate(self.nodes[2], 6)
self.nodes[2].importprivkey(privkey)
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index c6c2af10b1..320f5dd9df 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -6,6 +6,7 @@
import os
import random
+import shutil
from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -470,6 +471,40 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(bals, wallet.getbalances())
+ def test_default_wallet(self):
+ self.log.info("Test migration of the wallet named as the empty string")
+ wallet = self.create_legacy_wallet("")
+
+ wallet.migratewallet()
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+
+ def test_direct_file(self):
+ self.log.info("Test migration of a wallet that is not in a wallet directory")
+ wallet = self.create_legacy_wallet("plainfile")
+ wallet.unloadwallet()
+
+ wallets_dir = os.path.join(self.nodes[0].datadir, "regtest", "wallets")
+ wallet_path = os.path.join(wallets_dir, "plainfile")
+ wallet_dat_path = os.path.join(wallet_path, "wallet.dat")
+ shutil.copyfile(wallet_dat_path, os.path.join(wallets_dir, "plainfile.bak"))
+ shutil.rmtree(wallet_path)
+ shutil.move(os.path.join(wallets_dir, "plainfile.bak"), wallet_path)
+
+ self.nodes[0].loadwallet("plainfile")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["format"], "bdb")
+
+ wallet.migratewallet()
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+
+ assert os.path.isdir(wallet_path)
+ assert os.path.isfile(wallet_dat_path)
+
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -482,6 +517,8 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_encrypted()
self.test_unloaded()
self.test_unloaded_by_path()
+ self.test_default_wallet()
+ self.test_direct_file()
if __name__ == '__main__':
WalletMigrationTest().main()
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index ac3ec06eec..d7bb6ab1e7 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -9,7 +9,6 @@ from itertools import product
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.messages import (
ser_compact_size,
WITNESS_SCALE_FACTOR,
@@ -22,7 +21,8 @@ from test_framework.util import (
assert_raises_rpc_error,
count_bytes,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
+
class WalletSendTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -500,9 +500,7 @@ class WalletSendTest(BitcoinTestFramework):
assert res["complete"]
self.log.info("External outputs")
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, _ = generate_keypair(wif=True)
self.nodes[1].createwallet("extsend")
ext_wallet = self.nodes[1].get_wallet_rpc("extsend")
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index af21e7b956..d953f48584 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -6,6 +6,7 @@
"""
from concurrent.futures import ThreadPoolExecutor, as_completed
+from pathlib import Path
import argparse
import configparser
import logging
@@ -42,6 +43,11 @@ def main():
help='If true, run fuzzing binaries under the valgrind memory error detector',
)
parser.add_argument(
+ "--empty_min_time",
+ type=int,
+ help="If set, run at least this long, if the existing fuzz inputs directory is empty.",
+ )
+ parser.add_argument(
'-x',
'--exclude',
help="A comma-separated list of targets to exclude",
@@ -76,6 +82,7 @@ def main():
)
args = parser.parse_args()
+ args.corpus_dir = Path(args.corpus_dir)
# Set up logging
logging.basicConfig(
@@ -180,6 +187,7 @@ def main():
src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
use_valgrind=args.valgrind,
+ empty_min_time=args.empty_min_time,
)
@@ -251,16 +259,22 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir)
future.result()
-def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind):
+def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind, empty_min_time):
jobs = []
for t in test_list:
- corpus_path = os.path.join(corpus, t)
+ corpus_path = corpus / t
os.makedirs(corpus_path, exist_ok=True)
args = [
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
- '-runs=1',
- corpus_path,
]
+ empty_dir = not any(corpus_path.iterdir())
+ if empty_min_time and empty_dir:
+ args += [f"-max_total_time={empty_min_time}"]
+ else:
+ args += [
+ "-runs=1",
+ corpus_path,
+ ]
if use_valgrind:
args = ['valgrind', '--quiet', '--error-exitcode=1'] + args
diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py
index e7eecebce5..6da59b0d48 100755
--- a/test/lint/lint-assertions.py
+++ b/test/lint/lint-assertions.py
@@ -45,6 +45,16 @@ def main():
":(exclude)src/rpc/server.cpp",
], "CHECK_NONFATAL(condition) or NONFATAL_UNREACHABLE should be used instead of assert for RPC code.")
+ # The `BOOST_ASSERT` macro requires to `#include boost/assert.hpp`,
+ # which is an unnecessary Boost dependency.
+ exit_code |= git_grep([
+ "-E",
+ r"BOOST_ASSERT *\(.*\);",
+ "--",
+ "*.cpp",
+ "*.h",
+ ], "BOOST_ASSERT must be replaced with Assert, BOOST_REQUIRE, or BOOST_CHECK.")
+
sys.exit(exit_code)
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index ae70fb49d4..8808a83e32 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -46,7 +46,6 @@ unsigned-integer-overflow:hash.cpp
unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
unsigned-integer-overflow:script/interpreter.cpp
-unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:xoroshiro128plusplus.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h